tags:

views:

94

answers:

4
char sXSongBuffer[20][30];
sXSongBuffer = {"Thriller", "Don't Stop Till You Get Enough", "Billy Jean"};

Why does this return the error expected expression before ‘{’ token? The reason I want to initialize my array like this is so that I can change its contents like this later:

sXSongBuffer = {"New Song", "More Music From Me"};
A: 

C does not have general-purpose array literals. The {} list syntax only works when initializing, i.e. when assigning the value in the same statement that declares the variable.

unwind
A: 

You cannot just write

char sXSongBuffer[20][30];
sXSongBuffer = {"Thriller", "Don't Stop Till You Get Enough", "Billy Jean"};

You must either initialize array at once (but it will containt only 3 items):

char * sXSongBuffer[]= {"Thriller", "Don't Stop Till You Get Enough", "Billy Jean"};

Or either use stnrcpy on every item:

char sXSongBuffer[20][30];
strncpy(sXSongBuffer[0],"Thriller",29);
strncpy(sXSongBuffer[1],"Don't Stop Till You Get Enough",29);
strncpy(sXSongBuffer[2],"Billy Jean",29);
werewindle
He can use a designated initializer to get the effect he wants.
Robert S. Barnes
+5  A: 

You can't assign to arrays in C. C allows initializing arrays with values that are compile-time constants. If you want to change the values later, or set values that are not compile-time constants, you must assign to a particular index of the array manually.

So, your assignment to sXSongBuffer is disallowed in C. Moreover, since sXSongBuffer[0] to sXSongBuffer[19] are arrays too, you can't even say: sXSongBuffer[0] = "New Song";

Depending upon what you want, this may work for you:

/* declare sXSongBuffer as an array of pointers */
char *sXSongBuffer[30] = {
    "Thriller",
    "Don't Stop Till You Get Enough",
    "Billy Jean",
    NULL /* set the rest of the elements to NULL */
};
size_t i;
/* and then later in your code */
sXSongBuffer[0] = "New Song";
sXSongBuffer[1] = "More Music From Me";
for (i=2; i < sizeof sXSongBuffer; ++i)
    sXSongBuffer[i] = NULL;

But the above only works if you know all your strings at compile time. If not, you will have to decide if you want "big-enough" arrays, or if you need dynamic memory for the strings and/or the number of strings. In both cases, you will want to use an equivalent of strcpy() to copy your strings.

Edit: To respond to the comment:

You're declaring an array of 30 char pointers with the first three elements pointing to buffers the size of the strings, ie the buff pointed to by sXSongBuffer[0] won't hold any string larger than "Thriller" and if he does sXSongBuffer[0] = malloc(32); He'll get a minor memory leek. Also, he'll have to malloc memory for each of the rest of the slots in the array. He should either use 2d char arrays like in the OP + a designated init, or malloc each buffer at run time and copy in the values. He'll also need to remember to free any memory he mallocs.

sXSongBuffer in char *sXSongBuffer[30]; is an array of size 30, with each element being a char *, a pointer to char. When I do:

char *sXSongBuffer[30];

each of those 30 pointers is uninitialized. When I do:

char *sXSongBuffer[30] = { "Thriller", ... };

I set the pointers to different read-only locations. There is nothing preventing me to then "re-point" the pointers somewhere else. It is as if I had:

char *data = "Hello";
printf("%s\n", data);
data = "Hello, world";
printf("%s\n", data);

In the above snippet, I assign data to "Hello" first, and then change it to point to a longer string later. The code I had above in my answer did nothing more than reassign sXSongBuffer[i] to something else later, and since sXSongBuffer[i] is a pointer, the assignment is OK. In particular, sXSongBuffer[0] is a char *, and can point to any valid location that has a char in it.

As I said later in my answer, if the strings aren't known at compile-time, this scheme doesn't work, and one has to either use arrays with "big enough" sizes, or dynamically allocate memory that's big enough.

Alok
You're declaring an array of 30 char pointers with the first three elements pointing to buffers the size of the strings, ie the buff pointed to by `sXSongBuffer[0]` won't hold any string larger than "Thriller" and if he does `sXSongBuffer[0] = malloc(32);` He'll get a minor memory leek. Also, he'll have to malloc memory for each of the rest of the slots in the array. He should either use 2d char arrays like in the OP + a designated init, or malloc each buffer at run time and copy in the values. He'll also need to remember to free any memory he mallocs.
Robert S. Barnes
@Robert: please see my edit.
Alok
A: 

Take a look at Designated Initializers.

#include <stdio.h>

int main (void) {

    char a[6][6] = { [2] = "foo", [4] = "bar" };

    for (int i=0; i<6; ++i)
        printf("%d == %s\n", i, a[i]);

    return 0;
}

This is a c99 feature. Compile with:

gcc -W -std=c99 2dInit.c -o 2dInit

This outputs:

0 == 
1 == 
2 == foo
3 == 
4 == bar
5 == 

In your case you want to do:

char sXSongBuffer[20][30] = { 
    [0] = "Thriller", 
    [1] = "Don't Stop Till You Get Enough", 
    [2] = "Billy Jean"
};
Robert S. Barnes