1

I'm learning programming in C and I have a question of what is better when I declare an array. My teacher told me that it is better to use a variable that contains the value of the size like this:

#include <stdio.h>
#include <stdlib.h>

int main (){
  int size = 10;
  int array [size];

  return 0;
}

But my logic is: If i have a variable that never changes in the code. Can i declare like this? Is it wrong?

#include <stdio.h>
#include <stdlib.h>

#define size 10

int main (){
  int array [size];

  return 0;
}
5
  • Are you going to do C exclusively, or a lot of C++ as well? Does your C compiler target support const? Some coding styles recommend #define SIZE 10 where SIZE is all-caps to make it clear it's a defined macro. Commented Jun 9, 2020 at 1:22
  • define is for macro substitution, in which case size will be a runtime constant, because before compiling the code, a pre-processor will transform your source code to replace the values. In the first case depending on optimizations, size might not be a runtime constant, and the created array will be a variable length array, because in some more complex cases, the compiler will not be sure of the value of size when you create the array. Commented Jun 9, 2020 at 1:22
  • In both cases the preferred notation is int array[size] with no space between the name and square brackets. Commented Jun 9, 2020 at 1:23
  • Yes you can, and it actually better to understand. However, defines use all UPPERCASE letters, so when people are reading your code, they will know that SIZE is a constant. Commented Jun 9, 2020 at 1:23
  • Does this answer your question? #Define VS Variable Commented Jun 9, 2020 at 2:22

2 Answers 2

1

The reason your teacher thinks it is better to use a variable, is that with variable specific type constrained can be enforced.

#define size 10
int main (){
  int array [size];

  return 0;
}

vs

const int size=10;
int main (){
  int array [size];

  return 0;
}

while meaning the same thing, the second approach should prevent you (or another person) from putting bad values into size, at a very small cost, you are explicitly telling the next human modifying the code that the size constant should be an int.

for example you can alter your declaration:

const unsigned int size = 10; 

to tell the developer to not try to put negative value into size.

One valid approach to use define macro, would be to use compile-time define (via -D)

Remember that source code is mainly for human first, to be interpreted, compiled and executed by computer later. Your main goal when writing code is readability.

This is why some people would advise for readable variable names, put your constant name in UPPERCASE, use some common sense to name your functions/procedure, so that people reading the code would make sense of your own intents when writing the code (some comments can be nice too but can have adverse effect that are better discussed elsewhere).

Sign up to request clarification or add additional context in comments.

1 Comment

Another point is related to debugging. defines usually not treated well by debuggers as they can be redefined at certain points in the source files while const int size = ...; cannot be changed and the debugger can show the value of size anytime (as long as it is in the proper scope)
1

First, #define defines a preprocessor macro. As others have mentioned, most style guides recommend the use of ALL_CAPS for constants. The contents of the macro are replaced directly, so this:

#define SIZE  10
void test(void)
{
    int ar[SIZE];
}

will become this, which defines a normal fixed-size array:

void test(void)
{
    int ar[10];
}

This is a C99 variable-length array (VLA):

void test(void)
{
    int size = 10;
    int ar[size];
}

On a modern compiler with optimizations enabled, there is probably no difference. The compiler will see that size never changes, and will probably generate the same code.

There might be subtle differences with regard to static analysis, but for the most part, their behavior is identical.


However, VLAs are more powerful than that. See this example:

void test(int size)
{
    int ar[size];
}

Now the size of ar will change each time test() is called, according to the size parameter. That means the stack layout and consumption will vary at runtime. This is similar to this pre-C99 code using alloca:

void test(int size)
{
    int * const ar = alloca(size * sizeof(int));
}

A key difference is that using sizeof() on a VLA will return its runtime size, whereas sizeof(ar) in that example would return the size of the pointer.


So if you were do do this:

int size = 10;

void test(void)
{
    int ar[size];
}

Then the compiler would be forced to generate code which reads the global size variable, and dynamically allocate the array on the stack.

3 Comments

Remember that VLAs cannot have static storage duration (they cannot be used as globals), nor may they be members of struct or union types.
The alloca() example is not exactly equivalent, as you have an extra pointer variable (trhat can be changed to point elsewhere) and you don't have the pointer in the other view. But it's functionally equivalent, if you declare it as: int * const ar = alloca(...);
Thanks @Louis. I made some minor edits to reflect that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.