0

Im trying to declare a pointer to a 2d float matrix in order to have a dynamical behaviour of my image data but Im having a compilation error C2057: expected constant expression. I thought a pointer had to be casted in that way but apparently not.. Please anyone could help me ? Thanks!!

    //Image size input

int imheight;
int imwidth;

cout << "Please, enter image height: \n>";
scanf ("%d",&imheight);
cout << "Please, enter image width: \n>";
scanf ("%d",&imheight);

const int imheight2 = imheight;
const int imwidth2 = imwidth;

float *zArray[imheight2][imwidth2];

Here is one of my other functions where I´m trying to hace access to zArray. Im not getting the data properly read:

void LoadRIS( char* inputFileName , float** zArray, int imageHeight , int  imageWidth){

    // Load input RIS file
FILE* lRis = fopen ( inputFileName, "rb" );

// Jump to data position
for (int i = 0; i < 88; i++){       
    uchar a = getc (lRis);   
}   

// Read z array
size_t counter = fread ( *zArray , 1 , imageHeight * imageWidth * sizeof(zArray) , lRis );

//Get max value of RIS
float RISmax = zArray [0][0];
float RISmin = zArray [0][0];
for (int i=0; i<imageHeight; i++) 
{
    for (int j=0; j<imageWidth; j++)
        {
            if (zArray[i][j] > RISmax)
            RISmax = zArray [i][j];
            if (zArray[i][j] < RISmin)
            RISmin = zArray [i][j];
        }
}
std::cout<<"The max value of the RIS file is: "<<RISmax<<"\n";
std::cout<<"The min value of the RIS file is: "<<RISmin<<"\n";
Beep(0,5000);


// Close input file
fclose (lRis);

}

Nicolai
  • 333
  • 8
  • 15
  • In addition to what the answers say, that type is a 2D array of pointers, not a pointer to a 2D array. You would want `float (*zArray)[imheight2][imwidth2];`. – Joseph Mansfield May 06 '13 at 10:11
  • This question is tagged C and C++, but the answers are different. C has supported variable-length arrays for some time, so small variable-length arrays can and should be defined with `float foo[r][c];`. One of the tags should be deleted. – Eric Postpischil May 06 '13 at 11:43

7 Answers7

2
const int imheight2 = imheight;
const int imwidth2 = imwidth;

It doesn't make constant expressions. You cannot create array with such bounds. You should use dynamic-allocation, or vector.

ForEveR
  • 55,233
  • 2
  • 119
  • 133
2

The problem is that you're declaring 2 const int variables but you're not assigning them const values. imheight and imwidth are not constant.

If you're fine with STL:

std::vector<std::valarray<float> > floatMatrix;

edit: Just for your information, the space I placed between the > in the above line of code has nothing to do with my coding style. Your compiler might assume that >> is the right shift operator instead of 2 template argument list terminators. Angew's comment below sums it up.

user123
  • 8,970
  • 2
  • 31
  • 52
  • 1
    The "old" interpretation of `>>` is not a bug, C++03 was simply defined that way (although many compilers supported treating `>>` as `> >` as an extension). First C++11 made this parse legal, so now it's mandatory for compilers to understand `>>` as template terminator when applicable. – Angew is no longer proud of SO May 06 '13 at 10:18
  • 1
    And seeing as it's supposed to be a matrix, I'd consider `std::valarray` instead of `std::vector`. – Angew is no longer proud of SO May 06 '13 at 10:19
  • I guess I can reword that last statement to be more general so I can avoiding misinforming anyone – user123 May 06 '13 at 10:20
  • @EricPostpischil: Indeed, but in C++ they can't (yet) be used to specify the size of an array, which is a problem. – Mike Seymour May 06 '13 at 11:47
  • @EricPostpischil: No it isn't. The problem is that the variables are `const` but their values are not constant expressions, hence can't be used to declare arrays. That's exactly what the first sentence says. – Mike Seymour May 06 '13 at 11:50
  • @EricPostpischil: OK, pedantically you have to read between the lines to infer that the first sentence means that "the problem" (by which I assumes was meant the "expected constant expression" error reported in the question) is caused by initialising the array with values that are not constant expressions; but I don't see how that slight lack of clarity makes it false. That certainly is the problem, and they certainly could be used in array declarations if they were initialised with constant expressions (in C++ at least; the question is clearly about that language, whatever the original tags). – Mike Seymour May 06 '13 at 13:03
  • @EricPostpischil: Clarify it if you like then; it's not my answer. I was just trying to understand why you think it's false when (to me) it clearly isn't. As far as I can see, it is pure pedantry to insist it's "completely false" just because it says "the problem" rather than "the reason you get the error you get when you use these variables in the way you do". I'm leaving my upvote, because this is the only answer that both states what the problem is (albeit not clearly enough for you) and presents a sensible C++ alternative. – Mike Seymour May 06 '13 at 13:52
2

instead of float *zArray[imheight2][imwidth2]; it should be:

float **zArray = new float*[imheight2];

for(int i=0; i<imheight2; i++)
{
    zArray[i] = new float[imwidth2];
}
fatihk
  • 7,789
  • 1
  • 26
  • 48
1

Try this (dynamical allocation)

//Image size input

int imheight;
int imwidth;

cout << "Please, enter image height: \n>";
scanf ("%d",&imheight);
cout << "Please, enter image width: \n>";
scanf ("%d",&imwidth);

float** zArray = new float*[imheight];
for(int i=0;i<imheight;i++){
    zArray[i] = new float[imwidth];
}

Of course you need to free the allocation by:

for(int i=0;i<imheight;i++){
    delete[] zArray[i];
}
delete[] zArray;

Hope this helps :)

P.S. As @FrankH says, this calls too many news and deletes, wasting a lot of time. Better idea should be to alloc imwidth*imheight space together.

hongtao
  • 406
  • 4
  • 7
  • Working great, thanks! by the way, how can I access the values of the double pointer float** from another function? It´s crashing – Nicolai May 07 '13 at 08:54
  • @Nicolai you mean access the values in the 2d array? just using zArray[i][j] is ok. i would like to know about the whole code, could you edit the question and paste your 'another function' code? – hongtao May 07 '13 at 09:54
  • Hi hongtao, just pasted one function in the question. Im not getting a crash now, but I´m not able to read the file properly and load it into my zArray – Nicolai May 07 '13 at 11:08
  • ouch. `imheight+1` calls to `new`, for no better reason than to use a `array[x][y]` syntax. The error-prone `delete` loop (you're not storing the size of the '2D array' alongside it so need a global variable ...). Not everything that "technically works" is an answer. At the very very least, use only _two_ `new` / `delete[]` calls, `float *tmp = new float[imwidth*imheight]; for(i=0;i – FrankH. May 07 '13 at 23:20
1

If you have to do this, then code it at least as:

float **zArray = new float*[imheight];
float *tmp = new float[imheight*imwidth];

for(int i=0; i<imheight; i++, tmp += imwidth)
    zArray[i] = tmp;

...
delete[] *zArray;
delete[] zArray;

This at least avoids doing more than two new / delete[] calls. And it preserves the functionality of your fread(*zArray, ...) which breaks if the memory isn't contiguous (and it won't generally be if you initialize this via many new calls).

A proper wrapper class would do just a single new / malloc, like:

template <class T> class Array2D {
private:
    size_t m_x;
    T* val;
public:
    Array2D(size_t x, size_t y) :
        m_x(x)),
        val(new T[x*y]) {}
    ~Array2D() { delete[] val; }
    T* operator[](size_t y) { return val + y*m_x; }
}

You still cannot assign an instance of this to a float**. And it still allocates on the heap, where ordinary constant-dimension arrays can be on the stack. The only advantage of the additional allocation for the float** is that you're not bound to use a multiplication operation - but a separate memory access instead; that type of behaviour could be templated / traited into the wrapper class.

Generically, I'm more on the side of multidimensional arrays are evil (see also https://stackoverflow.com/a/14276070/512360, or C++ FAQ, 16.16) but tastes vary ...

Community
  • 1
  • 1
FrankH.
  • 17,675
  • 3
  • 44
  • 63
0

You cannot use Arrays with dynamic sizes (your width and height variables are not compile time constant).

You can either use malloc() or new Operator to allocate Memory in a dynamic fashion.

Pixelchemist
  • 24,090
  • 7
  • 47
  • 71
  • You're right but I think it is very likely that Nicolai is using C++, since variable-length arrays will not result in this compiler error C2057 in C. Therefore, this answer is correct with regard to the question. – Pixelchemist May 06 '13 at 12:17
  • That cplusplus.com reference is no good ... even the code samples are buggy (the `FreeDynamicArray` leaks `(nRows - 1)*nCols` units of `T`). It's just not right to use 'dynamic multidimensional arrays' in C/C++. Stick to `std::vector` and/or use/implement a proper `matrix` class - with `operator(int, int)` instead of `[][]`. – FrankH. May 08 '13 at 00:03
  • You are indeed right about that Website. I'll remove the link since this function may confuse People. But: Nobody should learn about how to use dynamic memory anymore, since we got the STL?! :X Everyone using C++ (especially when using C) SHOULD of course know about handling of one- or multi-dimensional arrays! Sooner or later you will be required to know such stuff even if you (try to) avoid using it in your own code. – Pixelchemist May 08 '13 at 09:26
  • You need to know about arrays, ack; and you need to understand that C/C++ "N-D arrays" are neither arrays nor matrices, in spite of the suggestingly deceptive syntax. Also, in C/C++, "dynamic N-D arrays" and "statically-defined N-D arrays" can't be made into compatible types even if they've got the same dimensions. Corollary: if you need "N-D arrays", you really need a matrix/tensor class (else the multiple new/delete involved make dealing with errors very hard ... many `try {} catch {}` blocks). Speculating why the STL provides none may be a good topic for another question ;-) – FrankH. May 09 '13 at 10:06
  • @FrankH: Correct. Therefore you'll need to know how such "dynamic N-D-structures" are handled to understand why there is (most likely) no contigous memory block present (in contrast to "static N-D-Arrays", where you got a single chunk of memory). – Pixelchemist May 09 '13 at 14:43
  • You're still missing the _main_ point - if there is no contiguous memory block present, then _you're doing it wrong_. Create a (or better, use an existing) matrix/tensor/image class that _does_ allocate _contiguous_ memory, and provides an overloaded `operator()(int x, int y, ...)` (_not_ `operator[]`) for access to individual elements. The `[][]...` syntax is _not the best way_ of representing/using multidimensional entities in C/C++. – FrankH. May 10 '13 at 09:37
  • Nope! There may be cases where contiguous storage is not required, beneficial or even desired. It is most likely that a contiguously stored 1d memory block is preferable but a dynamic Array of dynamic Arrays may still be valid and even far from "wrong". You need to know WHAT you are doing and WHY you are doing it one way or another. – Pixelchemist May 10 '13 at 09:45
  • I'll upvote you on that if you _give me a real-world example_ (quote from an existing widely-used opensource software project's commit log / blog or bugtracker posting describing the case) where a situation was found that a "1D array" / contiguous storage came out _inferior_ (in benchmarking) to a "dynamic 2D array". There's a reason why OpenGL buffers (even for 2D/3D textures), OpenCV images/matrices, even Windows Bitmaps or Fortran Matrices are ... contiguous in memory. Even _Sparse matrices_ for very large datasets are not usally done by "2D Arrays". – FrankH. May 12 '13 at 08:07
  • 1
    I'm currently working on a project where we store N (where N changes during execution) vectors of size M (which does not change) to keep a system from returning to already visited states in an optimization process. This is in fact a NxM matrix of values where the number of rows constantly changes (vectors are added and removed during the execution). Contiguous storage would either require all values to be move/copied every time the size changes or a preallocation of very large memory chunks. We use vector-of-vectors but this is nothing but a wrapped "dynamic 2D array". – Pixelchemist May 12 '13 at 14:13
  • While I buy that usecase, from my point of view, that's a situation where things like `auto hash = [](int val) { return val }; std::unordered_map< int, std::shared_ptr< std::vector<...> >, decltype(hash)> dyn_container(default_size);` come into play; you're in the area of _sparse matrices_ there, and those are necessarily different; often hashed, sometimes done via kd-trees, and others. The core original question, tough, was about _dense 2D arrays_, and while it is technically possible to "construct" those via multiple allocations, it's never a good idea to do so. – FrankH. May 23 '13 at 10:26
  • @FrankH. [This answer](http://stackoverflow.com/questions/17259877/1d-or-2d-array-whats-faster/17260533#17260533) is probably more "conformant" with your opinion. If the question is "What should I use?", I'll have my answer like "a contiguous block of memory in most cases". If the question, in contrast, is "Why does my 2d-approach refuse to work?", my answer should at least try to cope with the questions specifity. – Pixelchemist Jun 27 '13 at 23:50
-1

float *pMatrix = new float[imheight2*imwidth2];

then access elements like this

float f = pMatrix[x + imwidth2 * y];

t_smith
  • 89
  • 1
  • 1
  • 7