2
votes

I am new to C and I am trying to experiment with multi-dimensional arrays. I have the following example where I am trying to initialize a multi-dimensional array:

char matrix[5][10];  

matrix[0] = {'0','1','2','3','4','5','6','7','8','9'};
matrix[1] = {'a','b','c','d','e','f','g','h','i','j'};
matrix[2] = {'A','B','C','D','E','F','G','H','I','J'};
matrix[3] = {'9','8','7','6','5','4','3','2','1','0'};
matrix[4] = {'J','I','H','G','F','E','D','C','B','A'};

At first glance it would appear that this type of declaration would be valid since a multi-dimensional array is an array of arrays; however, this example fails to properly compile and I am not entirely certain as to why.

I am aware that I am able to initialize a multi-dimensional array using the following notation:

char matrix2[5][10] =
{
    {'0','1','2','3','4','5','6','7','8','9'},
    {'a','b','c','d','e','f','g','h','i','j'},
    {'A','B','C','D','E','F','G','H','I','J'},
    {'9','8','7','6','5','4','3','2','1','0'},
    {'J','I','H','G','F','E','D','C','B','A'},
};

However, what if I do not know the contents of the array at declaration time and would like to populate this array with data at a later point. I could initialize each individual element as follows:

matrix[0][0] = '0';
matrix[0][1] = '1';
matrix[0][2] =  '2';
etc....

I am wondering if it somehow possible to declare each array using my original approach:

matrix[0] = {'0','1','2','3','4','5','6','7','8','9'};
matrix[1] = {'a','b','c','d','e','f','g','h','i','j'};
etc...

I tried to use strcpy as follows:

strcpy(matrix[0], "012345678");
strcpy(matrix[1], "abcdefghi");

It appears that this might work if the multi-dimensional array was an array of null-terminated strings, but what would be an equivalent to a multi-dimensional array of integers or other data structures. Any help is appreciated. Thank you.

1
use memcpy instead of strcpy.BLUEPIXY

1 Answers

7
votes

There is a difference between an initialiser and an assignment. They both are introduced by =, but they are syntactically and semantically different.

For an initializer, C can deduce the type of the right side of the = by the left side type. For an assignment, the type must be know with the right side and be compatible with the left side (lvalue) type. Most imporatnt here: the compiler has no type information from the lvalue when evaluating the right side (it does not even started the assignment expression at that moment).

An initialiser must only be used with a definition (you seem to confuse this with declaration - pay heed, they are well-defined terms with different meaning). SO once you have complete the definition, you cannout use an _initialiser anymore.

Since C99, you can use a compound literal. This is much like a string literal ("Hello world"), but you have to tell the compiler its exact type (the string literal's type is given by the "). Additionally, C does not allow arrays to be simply assigned like scalars or structs. Thus you have to memcpy instead of the assignment:

memcpy(matrix[0], (char [10]){ 1,2,3,4, ... }, 10));

Note the (char ...} part which is the compound literal. This is not a cast, but tells the compiler which type the object in the curly braces has (here: array of 10 chars). A cast OTOH is a prefix expression and changess the type of the following expression. Note that you can use a _string literal here instead, but that does obviously not work for other array element types. Also note that for string literals you cannot define their length other than providing as many characters. So if you forget two characters, you will invoke undefined behaviour for reading outside array boundaries. (Two because of the implicit trailing '\0' character).

For the dimensions, you better use symbolic constants, (i.e. macros in C) like #define ROWS 10 to avoid magic numbers in your code - you have to use these values multiple times.

For an array of pointers, you can use the easier way:

matrix[0] = (char [10]){ 1,2,3,4,...};

Warning: This does not allow to change entries like the first version does, because literals must not be written to!

Extra: This version also works for structs (not just pointers to them), because C does allow assignments for those. To me, this looks like one of the irregularities of C one has to live with.