views:

3064

answers:

13

The following code receives seg fault on line 2:

  char *str = "string";
  str[0] = 'z';
  printf("%s", str);

While this works perfectly well:

  char str[] = "string";
  str[0] = 'z';
  printf("%s", str);

Tested with MSVC and GCC.

A: 

If you create the C-string as a pointer, it needs to be dynamically allocated before assigning a value.

If you create it as an array, it will be sized by the compiler.

You should notice the code would fail even if you comment-off the second line.

warren
This is just wrong. If second line will be commented out the code will work and absolutely correct.
Ilya
+6  A: 

Because the type of "whatever" in the context of the 1st example is const char * (even if you assign it to a non-const char*), which means you shouldn't try and write to it.

The compiler has enforced this by putting the string in a read-only part of memory, hence writing to it generates a segfault.

+43  A: 

Normally, string literals are stored in read-only memory when the program is run. This is to prevent you from accidentally changing a string constant. In your first example, "string" is stored in read-only memory and *str points to the first character. The segfault happens when you try to change the first character to 'z'.

In the second example, the string "string" is copied by the compiler from its read-only home to the str[] array. Then changing the first character is permitted. You can check this by printing the address of each:

printf("%p", str);

Also, printing the size of str in the second example will show you that the compiler has allocated 7 bytes for it:

printf("%d", sizeof(str));
Greg Hewgill
Whenever using "%p" on printf, you should cast the pointer to void * as in printf("%p", (void *)str);When printing a size_t with printf, you should use "%zu" if using the latest C standard (C99).
Chris Young
Also, the parenthesis with sizeof are only needed when taking the size of a type (the argument then looks like a cast). Remember that sizeof is an operator, not a function.
unwind
+4  A: 

char *str = "string";

The above sets str to point to the literal value "string" which is hard-coded in the program's binary image, which is probably flagged as read-only in memory.

So str[0]= is attempting to write to the read-only code of the application. I would guess this is probably compiler dependent though.

DougN
+7  A: 

In the first code, "string" is a string constant, and string constants should never be modified because they are often placed into read only memory. "str" is a pointer being used to modify the constant.

In the second code, "string" is an array initializer, sort of short hand for

char str[7] =  { 's', 't', 'r', 'i', 'n', 'g', '\0' };

"str" is an array allocated on the stack and can be modified freely.

Glomek
+3  A: 
char *str = "string";

allocates a pointer to a string literal, which the compiler is putting in a non-modifiable part of your executable;

char str[] = "string";

allocates and initializes a local array which is modifiable

Rob Walker
+1  A: 

String literals like "string" are probably allocated in your executable's address space as read-only data (give or take your compiler). When you go to touch it, it freaks out that you're in its bathing suit area and lets you know with a seg fault.

In your first example, you're getting a pointer to that const data. In your second example, you're initializing an array of 7 characters with a copy of the const data.

Jurney
A: 

The

 char *str = "string";

line defines a pointer and points it to a literal string. The literal string is not writable so when you do:

  str[0] = 'z';

you get a seg fault. On some platforms, the literal might be in writable memory so you won't see a segfault, but it's invalid code (resulting in undefined behavior) regardless.

The line:

char str[] = "string";

allocates an array of characters and copies the literal string into that array, which is fully writable, so the subsequent update is no problem.

Michael Burr
+19  A: 

See the C FAQ, Question 1.32

Q: What is the difference between these initializations?
char a[] = "string literal";
char *p = "string literal";
My program crashes if I try to assign a new value to p[i].

A: A string literal (the formal term for a double-quoted string in C source) can be used in two slightly different ways:

  1. As the initializer for an array of char, as in the declaration of char a[] , it specifies the initial values of the characters in that array (and, if necessary, its size).
  2. Anywhere else, it turns into an unnamed, static array of characters, and this unnamed array may be stored in read-only memory, and which therefore cannot necessarily be modified. In an expression context, the array is converted at once to a pointer, as usual (see section 6), so the second declaration initializes p to point to the unnamed array's first element.

Some compilers have a switch controlling whether string literals are writable or not (for compiling old code), and some may have options to cause string literals to be formally treated as arrays of const char (for better error catching).

matli
Markus
it would be nice if you could quote it here...
Nathan Fellman
quoted it for him
Simucal
A: 

In the first place, str is a pointer that points at "string". The compiler is allowed to put string literals in places in memory that you cannot write to, but can only read. (This really should have triggered a warning, since you're assigning a const char * to a char *. Did you have warnings disabled, or did you just ignore them?)

In the second place, you're creating an array, which is memory that you've got full access to, and initializing it with "string". You're creating a char[7] (six for the letters, one for the terminating '\0'), and you do whatever you like with it.

David Thornley
Does C also support const?
Ferruccio
+4  A: 

The C FAQ that @matli linked to mentions it, but no one else here has yet, so for clarification: if a string literal (double-quoted string in your source) is used anywhere other than to initialize a character array (ie: @Mark's second example, which works correctly), that string is stored by the compiler in a special static string table, which is akin to creating a global static variable (read-only, of course) that is essentially anonymous (has no variable "name"). The read-only part is the important part, and is why the @Mark's first code example segfaults.

rpj
+2  A: 

Most of these answers are correct, but just to add a little more clarity...

The "read only memory" that people are referring to is the text segment in ASM terms. It's the same place in memory where the instructions are loaded. This is read-only for obvious reasons like security. When you create a char* initialized to a string, the string data is compiled into the text segment and the program initializes the pointer to point into the text segment. So if you try to change it, kaboom. Segfault.

When written as an array, the compiler places the initialized string data in the data segment instead, which is the same place that your global variables and such live. This memory is mutable, since there are no instructions in the data segment. This time when the compiler initializes the character array (which is still just a char*) it's pointing into the data segment rather than the text segment, which you can safely alter at run-time.

Bob Somers
A: 
int *p;
printf("%d",p);

In the above two lines 'p' is a pointer with garbage value. But in second line you are trying to read the value of p pointing to the address. Here you get segmentation fault. If your program is trying to read the value from another process then the OS will terminate your process forcefully.

Another case is that if the p is trying to read value from an out-of-memory location then it causes a segmentation fault.