Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C compound literals, pointer to arrays

I'm trying to assign a compound literal to a variable, but it seems not to work, see:

  int *p[] = (int *[]) {{1,2,3},{4,5,6}}; 

I got a error in gcc.

but if I write only this:

  int p[] = (int []) {1,2,3,4,5,6}; 

Then it's okay.

But is not what I want.

I don't understand why the error occurrs, because if I initialize it like a array, or use it with a pointer of arrays of chars, its okay, see:

  int *p[] = (int *[]) {{1,2,3},{4,5,6}}; //I got a error   int p[][3] = {{1,2,3},{4,5,6}}; //it's okay   char *p[] = (char *[]) {"one", "two"...}; // it's okay! 

Note I don't understand why I got an error in the first one, and please I can't, or I don't want to write like the second form because it's needs to be a compound literals, and I don't want to say how big is the array to the compiler. I want something like the second one, but for int values.

Thanks in advance.

like image 307
drigoSkalWalker Avatar asked Mar 31 '11 06:03

drigoSkalWalker


2 Answers

First, the casts are redundant in all of your examples and can be removed. Secondly, you are using the syntax for initializing a multidimensional array, and that requires the second dimension the be defined in order to allocate a sequential block of memory. Instead, try one of the two approaches below:

  • Multidimensional array:

    int p[][3] = {{1,2,3},{4,5,6}}; 
  • Array of pointers to one dimensional arrays:

    int p1[] = {1,2,3}; int p2[] = {4,5,6}; int *p[] = {p1,p2}; 

The latter method has the advantage of allowing for sub-arrays of varying length. Whereas, the former method ensures that the memory is laid out contiguously.

Another approach that I highly recommend that you do NOT use is to encode the integers in string literals. This is a non-portable hack. Also, the data in string literals is supposed to be constant. Do your arrays need to be mutable?

int *p[] = (int *[]) {     "\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00",     "\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00" }; 

That example might work on a 32-bit little-endian machine, but I'm typing this from an iPad and cannot verify it at the moment. Again, please don't use that; I feel dirty for even bringing it up.

The casting method you discovered also appears to work with a pointer to a pointer. That can be indexed like a multidimensional array as well.

int **p = (int *[]) { (int[]) {1,2,3}, (int[]) {4,5,6} }; 
like image 163
Judge Maygarden Avatar answered Sep 22 '22 03:09

Judge Maygarden


First understand that "Arrays are not pointers".

int p[] = (int []) {1,2,3,4,5,6}; 

In the above case p is an array of integers. Copying the elements {1,2,3,4,5,6} to p. Typecasting is not necessary here and both the rvalue and lvalue types match which is an integer array and so no error.

int *p[] = (int *[]) {{1,2,3},{4,5,6}}; 

"Note I don't understand why I got a error in the first one,.."

In the above case, p an array of integer pointers. But the {{1,2,3},{4,5,6}} is a two dimensional array ( i.e., [][] ) and cannot be type casted to array of pointers. You need to initialize as -

int p[][3] = { {1,2,3},{4,5,6} };   // ^^ First index of array is optional because with each column having 3 elements   // it is obvious that array has two rows which compiler can figure out. 

But why did this statement compile ?

char *p[] = {"one", "two"...}; 

String literals are different from integer literals. In this case also, p is an array of character pointers. When actually said "one", it can either be copied to an array or point to its location considering it as read only.

char cpy[] = "one" ; cpy[0] = 't' ;  // Not a problem  char *readOnly = "one" ; readOnly[0] = 't' ;  // Error because of copy of it is not made but pointing                      // to a read only location. 

With string literals, either of the above case is possible. So, that is the reason the statement compiled. But -

char *p[] = {"one", "two"...}; // All the string literals are stored in                                 // read only locations and at each of the array index                                 // stores the starting index of each string literal. 

I don't want to say how big is the array to the compiler.

Dynamically allocating the memory using malloc is the solution.

Hope it helps !

like image 30
Mahesh Avatar answered Sep 25 '22 03:09

Mahesh