Unable to change string C

Consider the following code.

 int main (void) {
     char * test = "abcdefghijklmnopqrstuvwxyz";
     test [5] = 'x';
     printf ("% s \ n", test);
     return EXIT_SUCCESS;
 }

In my opinion, this should print abcdexghij. However, it simply ends without printing. A.

 int main (void) {
     char * test = "abcdefghijklmnopqrstuvwxyz";
     printf ("% s \ n", test);
     return EXIT_SUCCESS;
 }

This, however, works just fine, also did I misunderstand the concept of manipulating C strings, or something else? In case this is important, I am running Mac OS X 10.6, and this is the 32-bit binary that I am compiling.

+7
c cstring
source share
5 answers

the accepted answer is good, but not quite complete.

char * test = "abcdefghijklmnopqrstuvwxyz"; 

A string literal refers to an object of an anonymous array of type char[N] with a static storage duration (which means that it exists for the entire execution of the program), where N is the length of the string plus one for the terminating '\0' . This object is not const , but any attempt to modify it has undefined behavior. (An implementation can make string literals writable if it chooses, but most modern compilers do not.)

The declaration above creates such an anonymous object of type char[27] and uses the address of this first element of the element to initialize test . Thus, an assignment of type test[5] = 'x' tries to change the array and has undefined behavior; usually this will crash your program. (Initialization uses an address because a literal is an array type expression that is implicitly converted in most contexts to a pointer to the first element of the array.)

Note that in C ++, string literals are actually const , and the above declaration would be illegal. In C or C ++, it is better to declare test as a pointer to const char :

 const char *test = "abcdefghijklmnopqrstuvwxyz"; 

therefore, the compiler will warn you if you try to modify the array using test .

(String literals are not const for historical reasons. Before the ANSI C standard of 1989, the keyword const did not exist. The requirement to use it in declarations like yours for safe code, but that would require that the existing code be modified, is that a committee ANSI was trying to avoid. You have to pretend that string literals are const , even if it isn't. If you use gcc, the -Wwrite-strings option -Wwrite-strings compiler to treat string literals as const - which makes gcc a mismatch.)

If you want to change the line referenced by test , you can define it as follows:

 char test[] = "abcdefghijklmnopqrstuvwxyz"; 

The compiler looks at the initializer to determine how big the test should be. In this case, test will be of type char[27] . The string literal still refers to an anonymous read-only array object, but its value is copied to test . (The string literal in the initializer used to initialize the array object is one of the contexts in which the array does not "decay" into a pointer and the rest are the operand of a unary & or sizeof .) Since there are no more references to an anonymous array, the compiler can optimize it.

In this case, test itself is an array containing 26 characters that you specified, plus the terminator '\0' . The lifetime of this array depends on where test declared, which may or may not matter. For example, if you do this:

 char *func(void) { char test[] = "abcdefghijklmnopqrstuvwxyz"; return test; /* BAD IDEA */ } 

the caller will receive a pointer to something that no longer exists. If you need to access the array outside the scope in which test is defined, you can define it as static , or you can select it with malloc :

 char *test = malloc(27); if (test == NULL) { /* error handling */ } strcpy(test, "abcdefghijklmnopqrstuvwxyz"; 

so that the array continues to exist until you call free() . The non-standard strdup() function does this (it is defined by POSIX, but not ISO C).

Note that test can be a pointer or an array, depending on how you declare it. If you pass test to a string function or to any function that takes char* , it doesn't matter, but something like sizeof test will behave differently depending on whether test pointer or an array.

comp.lang.c FAQ is excellent. Section 8 covers characters and lines, and question 8.5 points to question 1.32, which addresses your specific question. Section 6 covers the often confusing relationship between arrays and pointers.

+4
source share

Char pointers defined by an initialization value go into a read-only segment. To make them modifiable, you need to either create them on the heap (for example, using new / malloc), or define them as an array.

Unable to change:

 char * foo = "abc"; 

Modifiable:

 char foo[] = "abc"; 
+27
source share

You should get used to matching the type of the variable with the type of the initializer. In this case:

 const char* test = "abcdefghijklmnopqrstuvwxyz"; 

This way you get a compiler error, not a runtime error. Minimizing your compiler's warning level to max can also help avoid such errors. Why this is not a mistake in C is probably historical; early compilers resolved this and refused, perhaps breaking too much existing code when the language was standardized. Now, however, operating systems do not allow this so academically.

+4
source share

String literals cannot be changed; it is better to assume that this is not so. See here for more details.

+3
source share

do:

  char * bar = strdup(foo); bar[5] = 'x'; 

strdup makes a modifiable copy.

And yes, you should really check that strdup did not return NULL.

+1
source share

All Articles