Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strings in C: Why does this work?

Tags:

c

I'm sorry for asking something that probably seems a little inane as it is apparently not broken but my (newbie) understanding of how C handles string literals tells me that this should not work...

char some_array_of_strings[3][200];
strcpy(some_array_of_strings[2], "Some garbage");
strcpy(some_array_of_strings[2], "Some other garbage");

I thought that C prevented the direct modification of string literals and that was why pointers were used when dealing with strings. The fact that this works tells me I am misunderstanding something.

Also, if this works, why does...

some_array_of_strings[1]="Some garbage"
some_array_of_strings[1]="Some garbage that causes a compiler error due to reassignment"

not work?

like image 934
cwm Avatar asked Jul 18 '26 17:07

cwm


2 Answers

Be careful with the phrase "array of strings". A "string" is not a data type in C; it's a data layout. Specifically, a string is defined as

a contiguous sequence of characters terminated by and including the first null character

An array of char may contain a string, and a char* pointer may point to (the first character of) a string. (The standard defines a pointer to the first character of a string as a pointer to a string.)

char some_array_of_strings[3][200];

This defines a 3-element array, where each of the elements is a 200-element array of char. (It's a 2-dimensional array, which in C is simply an array of arrays.)

strcpy(some_array_of_strings[2], "Some garbage");

The string literal "Some garbage" refers to an anonymous statically allocated array of char; it exists for the entire execution of your program, and you're not allowed to modify it. The strcpy() call, as the name implies, copies the contents of that array, up to and including the terminating '\0' null character, into some_array_of_strings[].

strcpy(some_array_of_strings[2], "Some other garbage");

Same thing: this copies the contents "Some other garbage" into some_array_of_strings[2], overwriting what you copied on the previous line. In both cases, there's more than enough room.

You're not modifying a string literal, you're modifying your own array by copying bytes from a string literal (more precisely, from that anonymous array I mentioned above).

some_array_of_strings[1]="Some garbage";

This doesn't just "not work", it's illegal. There is no assignment of arrays in C.

Let's take a simpler example:

char arr[10];
arr = "hello"; /* also illegal */

arr is an object of array type. In most contexts, an expression of array type is implicitly converted to a pointer to the array object's first element. That applies to both sides of the assignment: the object name arr and the string literal "hello".

But the pointer on the left side is just a pointer value. There is no pointer object. In technical terms, it's not an lvalue, so it can't appear on the left side of an assignment any more than you could write 42 = x;).

(If the array-to-pointer conversion didn't happen, it would still be illegal, because C doesn't permit array assignments.)

Some more detail on the issue of arrays on the left side of assignment:

The contexts where an array expression doesn't decay into a pointer are when the array expression is:

  • an operand of the unary sizeof operator;
  • an operand of unary & (address-of) operator; or
  • a string literal in an initializer used to initialize an array object.

The left side of an assignment isn't any of those contexts, so in:

char array[10];
array = "hello";

LHS is, in principle, converted to a pointer. But the resulting pointer expression is no longer an lvalue, which makes the assignment a constraint violation.

One way to look at it is that the expression array is converted to a pointer, which then makes the assignment illegal. Another is that since the assignment is illegal, the whole program is not valid C, so it has no defined behavior and it's meaningless to ask whether any conversion does or does not happen.

(I'm playing a little fast and loose with my use of the word "illegal", but this answer is long enough already so I won't get into it.)

Recommended reading: Section 6 of the comp.lang.c FAQ; it does an excellent job of explaining the often bewildering relationship between arrays and pointers in C.

like image 67
Keith Thompson Avatar answered Jul 20 '26 09:07

Keith Thompson


you aren't modifying the string literal, you are using it as a source to copy it into your array of characters. Once the copy is finished, your string literal has nothing to do with the copy in your array. You are free to then manipulate the array.

like image 23
Keith Nicholas Avatar answered Jul 20 '26 11:07

Keith Nicholas