96

I am a little surprised by the following.

Example 1:

char s[100] = "abcd"; // declare and initialize - WORKS

Example 2:

char s[100]; // declare
s = "hello"; // initalize - DOESN'T WORK ('lvalue required' error)

I'm wondering why the second approach doesn't work. It seems natural that it should (it works with other data types)? Could someone explain me the logic behind this?

Ree
  • 6,061
  • 11
  • 48
  • 50

10 Answers10

89

When initializing an array, C allows you to fill it with values. So

char s[100] = "abcd";

is basically the same as

int s[3] = { 1, 2, 3 };

but it doesn't allow you to do the assignment since s is an array and not a free pointer. The meaning of

s = "abcd" 

is to assign the pointer value of abcd to s but you can't change s since then nothing will be pointing to the array.
This can and does work if s is a char* - a pointer that can point to anything.

If you want to copy the string simple use strcpy.

shoosh
  • 76,898
  • 55
  • 205
  • 325
  • 9
    Good answer, except you should never use plain strcpy any longer. Use strncpy or strlcpy. – dwc Feb 23 '09 at 23:01
  • 4
    Also, s should be const char*, not char*. – aib Feb 24 '09 at 14:17
  • 1
    `s[0] = 'x'; s[1] = 'y'; s[2] = 'z'; s[3] = 'm';` works if one wants to replace the string characters one by one even after initialization. – RBT Oct 28 '16 at 02:44
  • @RBT, maybe it does in your platform with your compilation flags but often times these strings are defined in read-only memory. writing to it would cause a segfault or an Access-Violation error – shoosh Dec 04 '16 at 07:52
  • Why? Doing `char s[100]; s = "abcd";` gives error makes perfect sense because s is effectively treated as a const pointer. So if we try assigning "abcd" in second line we are trying to change the value of the pointer which is not allowed. But if a const pointer is pointing to a memory location then the contents of the memory location should of course be modifiable. Let's say `s` points to memory location 1000 then s contains 1000 and memory location # 1000 contains a. I can't change s to store new memory location e.g. 2000 but I can store a new character e.g. z at memory location 1000. – RBT Dec 05 '16 at 03:46
  • 2
    @dwc there is no problem with strcpy(), just make sure your buffer is long enough for the input string – 12431234123412341234123 Jan 18 '17 at 10:16
  • The part *The meaning of `s = "abcd"` is to assign the pointer value of `abcd` to `s` but you can't change `s` since then nothing will be pointing to the array.* is a little unclear to me: what will the array that won't be pointed anymore? The literal `abcd`? – roschach Jan 03 '19 at 17:08
  • 1
    @FrancescoBoi: The declaration `char s[100];` sets aside 100 bytes on the stack. You can access and modify those values just like you would an `int` array. The line `s = "abcd";` attempts to assign a pointer to the string "abcd" to `s`, but that doesn't make sense. The words you quote are saying that, if you were able to make that assignment, the original array of 100 bytes would be lost. (I think it's more clear just to realize the operation doesn't make any sense. Although `s` may act like a pointer, it isn't one; it's an array of 100 bytes on the stack.) – Nick Matteo May 04 '19 at 17:20
70

There is no such thing as a "string" in C. In C, strings are one-dimensional array of char, terminated by a null character \0. Since you can't assign arrays in C, you can't assign strings either. The literal "hello" is syntactic sugar for const char x[] = {'h','e','l','l','o','\0'};

The correct way would be:

char s[100];
strncpy(s, "hello", 100);

or better yet:

#define STRMAX 100
char    s[STRMAX];
size_t  len;
len = strncpy(s, "hello", STRMAX);
H.S.
  • 11,654
  • 2
  • 15
  • 32
dwc
  • 24,196
  • 7
  • 44
  • 55
14

Initialization and assignment are two distinct operations that happen to use the same operator ("=") here.

Sparr
  • 7,489
  • 31
  • 48
4
1    char s[100];
2    s = "hello";

In the example you provided, s is actually initialized at line 1, not line 2. Even though you didn't assign it a value explicitly at this point, the compiler did.

At line 2, you're performing an assignment operation, and you cannot assign one array of characters to another array of characters like this. You'll have to use strcpy() or some kind of loop to assign each element of the array.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Matt Davis
  • 45,297
  • 16
  • 93
  • 124
2

To expand on Sparr's answer

Initialization and assignment are two distinct operations that happen to use the same operator ("=") here.

Think of it like this:

Imagine that there are 2 functions, called InitializeObject, and AssignObject. When the compiler sees thing = value, it looks at the context and calls one InitializeObject if you're making a new thing. If you're not, it instead calls AssignObject.

Normally this is fine as InitializeObject and AssignObject usually behave the same way. Except when dealing with char arrays (and a few other edge cases) in which case they behave differently. Why do this? Well that's a whole other post involving the stack vs the heap and so on and so forth.

PS: As an aside, thinking of it in this way will also help you understand copy constructors and other such things if you ever venture into C++

Community
  • 1
  • 1
Orion Edwards
  • 121,657
  • 64
  • 239
  • 328
1

I know that this has already been answered, but I wanted to share an answer that I gave to someone who asked a very similar question on a C/C++ Facebook group.


Arrays don't have assignment operator functions*. This means that you cannot simply assign a char array to a string literal. Why? Because the array itself doesn't have any assignment operator. (*It's a const pointer which can't be changed.)

arrays are simply an area of contiguous allocated memory and the name of the array is actually a pointer to the first element of the array. (Quote from https://www.quora.com/Can-we-copy-an-array-using-an-assignment-operator)

To copy a string literal (such as "Hello world" or "abcd") to your char array, you must manually copy all char elements of the string literal onto the array.

char s[100]; This will initialize an empty array of length 100.

Now to copy your string literal onto this array, use strcpy

strcpy(s, "abcd"); This will copy the contents from the string literal "abcd" and copy it to the s[100] array.

Here's a great example of what it's doing:

int i = 0; //start at 0
do {
    s[i] = ("Hello World")[i]; //assign s[i] to the string literal index i
} while(s[i++]); //continue the loop until the last char is null

You should obviously use strcpy instead of this custom string literal copier, but it's a good example that explains how strcpy fundamentally works.

Hope this helps!

JMS Creator
  • 116
  • 6
1

Note that you can still do:

s[0] = 'h';
s[1] = 'e';
s[2] = 'l';
s[3] = 'l';
s[4] = 'o';
s[5] = '\0';
aib
  • 45,516
  • 10
  • 73
  • 79
  • It's much nicer and easier to use strncpy(), even though I'm pretty sure strncpy() does exactly this internally. – Chris Lutz Feb 24 '09 at 14:33
  • Of course. But this is as close as it gets to 's = "hello";' In fact, this should have been implemented in C, seeing as how you can assign structs. – aib Feb 24 '09 at 14:47
  • I mean, memberwise copy by assignment in structs but not in arrays doesn't make sense. – aib Feb 24 '09 at 14:49
0

I am annoyed by this... It really would be logical if:

char string[10] = "hello";  

should give the same result as:

char string[10] = {0}; 
string = "hello";        // doesn't work!

But I guess it just doesn't work like that. Anyways, here was my workaround:

char string[10] = {0}; 
sprintf(string,"hello");   

its almost as good, because it is short.

Strangely enough, another thing which has worked for me (though a little off-topic perhaps) is when you declare arrays of structs, you can initialize them with the good-ole double quotes like this:

struct myStruct {
   char name[NAX_NAME_LEN];
};

struct myStruct name[DATA_ARRAY_SIZE];

name[1] = (struct myStruct ) { "Hello" };

Incidentally, this method of initialization is known as a "compound literal" Id love to see if anyone could explain why this works to use double quotes and not the string = "hello"; way...

This method is great if you have a lot of strings by the way, because it allows you to write code like:

#define DATA_ARRAY_SIZE 4
enum names{ BOB, GEORGE, FRANK, SARAH};
struct myStruct {
       char name[NAX_NAME_LEN];
};
struct myStruct name[DATA_ARRAY_SIZE];

name[BOB   ] = (struct myStruct ) { "Bob" };
name[GEORGE] = (struct myStruct ) { "George" };
name[FRANK ] = (struct myStruct ) { "Frank" };
name[SARAH ] = (struct myStruct ) { "Sarah" };

Or if you're going to go all multilingual for some app:

#define NUM_LANGUAGES 4
enum languages{ ENGLISH , FRENCH  , SWEDISH , ITALIAN };
struct myStruct {
       char intro[NAX_NAME_LEN];

};
struct myStruct name[DATA_ARRAY_SIZE];

intro[ENGLISH ] = (struct myStruct ) { "Hello" };
intro[FRENCH  ] = (struct myStruct ) { "Bonjour" };
intro[SWEDISH ] = (struct myStruct ) { "Hej" };
intro[ITALIAN ] = (struct myStruct ) { "Ciao" };
Leigh Boyd
  • 71
  • 1
  • 3
-1

You can use this:

yylval.sval=strdup("VHDL + Volcal trance...");

Where yylval is char*. strdup from does the job.

josliber
  • 43,891
  • 12
  • 98
  • 133
Yekatandilburg
  • 187
  • 1
  • 2
-3

What I would use is

char *s = "abcd";
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Vivek
  • 41
  • 2