简体   繁体   中英

ANSI C - initializing an array

What I was always doing is:

int arr[] = {2, 3, 4};

and it always worked.

I've heard of a better way to initialize new array, using the pointer:

int *arr = {2, 3, 4};

However, it doesn't work in any IDE, it throws some errors like int differs in levels of indirection from int , or too many initializers . How should I do this?

int arr[] = {2, 3, 4};

is just fine, and completely correct. No need to change.

That initialization seems to work for me, on gcc, but not correctly.

int *arr = {2, 3, 4}; //weird behaviour, stores first value `2` as read-only

int arr[] = {2, 3, 4}; //array decl

The former isn't a correct way to initialize an array.

For a char* , it makes more sense

char* arr = "abcde"; //Pointer to a read-only char array in memory

char[] arr = "abcde"; //Normal char array

The difference:

The former is written to the Rodata (constant, read-only data) section of the assembly, while the latter, resides in the read/write Data-Segment . Any attempt to change the former, might result in a segmentation-fault .


The places where the values are stored are different.

char* arr = "abcde";
arr[1] = 'f'; //(undefined behavior)

char[] arr2 = "abcde";
arr2[1] = 'f'; //no issue

If you want to "initialize an array", you have to initialize an array , not a pointer.

Anyway, in C99 compound literals can be used and a pointer can be initialized as

int *arr = (int []) {2, 3, 4};

which is close to what you were trying to do. Although the term "ANSI C" is often used to refer to C89/90, where this feature is not available.

There's nothing "better" about this approach. It just gives you a pointer instead of an array, so it is really a question of what you need.

Why would the second version be better than the first?

The first version at least is explicit: you define an int array, with the given elements. Let the compiler determine how to do this optimally.

Going from your comment to Evan Li ("string is also kind of an array, and it is initialized with a pointer. Thus, arrays should be also initialized this way."). If the instructor actually told you this, I'd seriously think about finding a new instructor, because he's confused about things.

A string literal is an array expression; the literal "Hello" is a 6-element array of char ( const char in C++). String literals are stored in such a way that their memory is allocated over the lifetime of the program; this memory may or may not be read-only, depending on the platform. The behavior on attempting to modify the contents of a string literal is undefined , meaning you may get a segfault, or the string may get modified, or something else happens.

When an array expression appears in a context other than as an operand to the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, then the type of the expression is converted ("decays") from "N-element array of T " to "pointer to T ", and the value of the expression is the address of the first element of the array.

That's why you can write something like

char *foo = "This is a test";

The string literal "This is a test" is an array expression of type "15-element array of char "; since it isn't the operand of the sizeof or & operators, and isn't being used to initialize another array of char , the type of the expression becomes "pointer to char ", and the address of the first character is assigned to foo . By comparison,

char foo[] = "This is a test";

declares foo as an array of char ; the size is computed from the size of the initializer string (15 characters), and the contents of the string literal are copied to foo .

A string is an array expression; a brace-enclosed list of values is not .

int *foo = {1, 2, 3};

won't create a 3-element array of int and assign the address of the first element to foo ; instead, this should be a constraint violation if I'm reading this right:





2 No initializer shall attempt to provide a value for an object not contained within the entity being initialized.

As of C99, you can use what are known as compound literals , like so:

int *foo = (int []) {1, 2, 3};

The cast-expression (int []) is required. This does create a new 3-element array of int and assigns the address of the first element to foo . Unlike string literals, compound literals like this only exist for the duration of the enclosing block 1 ; IOW, if you did something like

int *foo = NULL;
if (condition())
{
  foo = (int []){1, 2, 3};
  // do stuff
}
// do more stuff

the anonymous array object pointed to by foo only exists within the if block; once the if block exits, the array no longer exists, and the value of foo is no longer valid.


1. If the compound literal is defined at file scope (outside of any function), then it has static duration and exists for the lifetime of the program.

int arr[] = {2, 3, 4}; is ok.

If you want to use pointer, you will have to allocate memory with for example malloc. Something like that :

  int *arr = malloc(sizeof(int)*4);

  arr[0]=1;
  arr[1]=2;
  arr[2]=3;
  arr[3]=4;

  //display
  printf("%d %d %d %d\n",arr[0],arr[1],arr[2],arr[3]);

  free(arr);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM