-1

I am trying to compile the following code:

    int rows = 4;
    int columns = 4;
    int numblock[columns][rows] = {
                                   {0,0,0,0},
                                   {0,0,0,0},
                                   {0,0,0,0},
                                   {0,0,0,0}
    };

And it tells me that the variable may not be initialized. When I write int numblock[4][4] instead, the compiler doesn't complain.

I guess it is related to this: C compile error: "Variable-sized object may not be initialized"

Can someone please explain this to me?

Edit - from a comment by op:

.. I set columns and rows = 4. It should know the size, shouldn't it?

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
neolith
  • 699
  • 1
  • 11
  • 20
  • 3
    *Explain* exactly what? It's just the way it is: VLA's may not be initialised, as this is a compile-time thing, where as the size is known at run-time only. The answers under link you already found seem to explains this. – alk Mar 30 '19 at 09:04
  • Explain why it works with numbers but not with variables that hold the numbers. I also think that I have done this before and it worked, although that might have been in Java – neolith Mar 30 '19 at 09:06
  • 1
    I think that you read it the wrong way, i.e. as "maybe it is not initialized". But what it really says is: it is **not allowed** to initialize VLAs. – Support Ukraine Mar 30 '19 at 09:06
  • Okay, so I don't have to work with malloc here or anything? I mean this is for programming a microcontroller and I have to be specific about this – neolith Mar 30 '19 at 09:12
  • You need to explain in more details what it is the linked answer does not cover. If not we just have to close your question as a duplicate of exactly that answer... – Support Ukraine Mar 30 '19 at 09:12
  • No - you don't need malloc. `int numblock[columns][rows];` is fine (if supported by you compiler). Then you just have to set the values afterwards, e.g. using for-loops or memset or .... – Support Ukraine Mar 30 '19 at 09:14
  • Okay, but why can I specifiy the size with int numblock[4][4] and then initialize it? What is the difference? – neolith Mar 30 '19 at 09:15
  • BTW: Only use VLAs if they are small! Huge VLAs with e.g. 10.000 x 5.000 elements will/may cause stack overflow – Support Ukraine Mar 30 '19 at 09:16
  • The difference is whether the **compiler** knows the size of the whole array. If you write `[4][4]` the compiler knows the size and can do initialization for you. When you do `[columns][rows]` the compiler doesn't know the size and therefore it can't initialize – Support Ukraine Mar 30 '19 at 09:18
  • Only use Very Large Arrays if they are small? What?? – neolith Mar 30 '19 at 09:19
  • 2
    VLA is not "Very Large Arrays" It is "Variable Length Array" :-) – Support Ukraine Mar 30 '19 at 09:20
  • But I set columns and rows = 4. It should know the size, shouldn't it? – neolith Mar 30 '19 at 09:20
  • 1
    No - the compiler doesn't track the values of variables `rows/columns` - maybe your code changed them before the array definition, e.g. you could do `rows = rows + 42;` just before the `int numblock[columns][rows]` – Support Ukraine Mar 30 '19 at 09:22
  • Can't I make them static? – neolith Mar 30 '19 at 09:30
  • No - won't help. Not in C. In C++ you could make them `const` but that is another story. I think I'll write an answer - hold on. – Support Ukraine Mar 30 '19 at 09:34
  • @neolith - making `rows` and `columns` `static` only affects how they are stored, not whether their values are known at compile time. VLAs have their uses, but they are quite limited. Can’t be declared `static` or at file scope, can’t be members of `struct` or `union` types, and can’t be declared with an initializer. – John Bode Mar 30 '19 at 12:41

2 Answers2

2

The answer is already in the link you provide but I'll try to clarify as the linked answer wasn't clear to you.

First - what you have is called VLA, i.e. a Variable Length Array. The idea is simply that you can use another variable to set the size of the array. So this allows the size to be set at run time.

The problem you have is because: It is not allowed to initialize a VLA

It is as simple as that - it is just not supported in C.

It works fine with the initializer when the array is defined with numbers (e.g. [4][4]). That is because the size of the array is known at compile time

The fact you you initialize rows and columns to 4 makes no difference. The compiler do not track whether these variables are changed before the array is created. For instance like this:

void foo()
{
    int rows = 4;
    int columns = 4;
    rows = rows + 42;   // or scanf("%d", &rows) to get the number of rows from a user
    int numblock[columns][rows];  // no - initializer here - not allowed
}

Even if you make rows and columns constants - like const int rows = 4; - it still won't work in C (but in C++ it will).

One way to "initialize" a VLA is to use memset - like:

void foo()
{
    int rows = 4;
    int columns = 4;
    int numblock[columns][rows];           // no - initializer here - not allowed
    memset(numblock, 0, sizeof numblock);  // but using memset is easy
}

If you want a fixed number of rows/columns the C way is to use defines. Like:

#define ROWS 4
#define COLUMNS 4

void foo()
{
    int numblock[ROWS][COLUMNS] = {
                                   {0,0,0,0},
                                   {0,0,0,0},
                                   {0,0,0,0},
                                   {0,0,0,0}
                                  };
}

This will work because defines are resolved at compile time

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • 2
    You can use enums as integer-constant-expressions as well, which lets them be scoped tightly to the point of use: `enum {ROWS=4,COLUMNS=4};` within the function body. – Alex Celeste Mar 30 '19 at 10:29
  • Thank you for the detailed explanation. I will have to recap the basics thoroughly! – neolith Mar 30 '19 at 11:35
0

I found that if I initialize n at 0 in the variable declarations, but do not initialize the array until inside of the body of the program (int main ()), that the compiler does not complain and the program functions as expected. This may not be the preferred way, and I think perhaps the use of #define may be a more elegant way.

Forbin117
  • 40
  • 1
  • 1
  • 5