104

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?

10 Answers 10

96

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.

Sign up to request clarification or add additional context in comments.

8 Comments

Good answer, except you should never use plain strcpy any longer. Use strncpy or strlcpy.
Also, s should be const char*, not char*.
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.
@dwc there is no problem with strcpy(), just make sure your buffer is long enough for the input string
@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.)
|
78

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);

3 Comments

Not the recommended approach. Beware of the oddities of strncpy: stackoverflow.com/a/1258577/2974922
I think this approach could easily be recommended
"Not recommened" might be a bit harsh, but "beware of the oddities" is definitely justified
13

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

Comments

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.

2 Comments

Why do you need 100 bytes for hello? Isn't char s[6] enough?
@mLstudent33, it was the example given by the OP.
3

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++

Comments

2

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" };

Comments

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';

3 Comments

It's much nicer and easier to use strncpy(), even though I'm pretty sure strncpy() does exactly this internally.
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.
I mean, memberwise copy by assignment in structs but not in arrays doesn't make sense.
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!

Comments

-1

You can use this:

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

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

2 Comments

strdup from <string.h> does the job :)
strdup makes a duplicate and returns the pointer to the duplicate. In this case for char arrays, you are back to where you started with no work done
-3

What I would use is

char *s = "abcd";

1 Comment

Most of us wouldn't, because it risks undefined behaviour. The above is only safe for const char*.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.