tags:

views:

150

answers:

5
#include<stdio.h>

void main()
{
    char *p="nyks";

    p[2]='n';

    printf("%s",p);
}

This crashes with a SEGMENTATION FAULT. Can someone explain why?

+12  A: 

It is undefined behavior to try to overwrite a string literal. C99 §6.4.5/6:

If the program attempts to modify such an array, the behavior is undefined.

This is restated in Appendix J.2 (undefined behavior).

If you instead do:

char p[] = "nyks";

you can allocate and initialize an automatic (stack) character array. In that case, it is perfectly fine to modify elements.

Matthew Flaschen
+ it is not allowed to have non-constant string literal declarations anymore. GCC will issue a big red warning.
Vlad Lazarenko
+1 for reference to spec
linuxuser27
+5  A: 

The standard dictates that literal strings are defined const. You cannot change it.

The compiler places the literal in a readonly memory section. You can output the assembly and observe this. If you are using GCC it is done via the -s flag. It will place the string in a .rodata section.

linuxuser27
and if i write char arr[10]="nyks";arr[2]='p';will it show seg fault again?
hopefulLLl
@hopeful, no. That is fine, since you're allocating a (modifiable) array on the stack. As I noted above, you can leave out the size so C calculates it.
Matthew Flaschen
A: 

String literals are not modifiable... The ability to write char *p="nyks"; is actually a type system hole in C.

usta
How is this a type system hole?
mathepic
For historical reasons, the compiler was allowed to silently cast away `const` in this case. Of course, at the time `const` was invented and they noticed that a string constant must effectively be `const char *`, it was likely deemed to large a breaking change to forbid assignment to `char *`.
RBerteig
@mathepic It is from C++ point of view, at least. In C++, a character literal is of type const char[N]. A string literal can be implicitly converted to non-const char* (const qualification removed without a cast). This is a type system hole in C++, but this behavior was inherited from C. This is a deprecated feature in C++, and will be removed entirely in C++0x.Here's what the C standard has to say on the matter of this question: "If the program attempts to modify such an array, the behavior is undefined." where 'such an array' is a character array which holds a string literal.
usta
+1  A: 

That translates to (essentially):

 #include<stdio.h>  
 const char privatestring[5] = {"nyks"};

 void main()  
 {  
    char *p = const_cast<char*>(privatestring); 
    p[2]='n';        

    printf("%s",p);        
 }        

The compiler is allowed to put privatestring somewhere where you only have read access. It does the const_cast for backward compatibility with programs written before that was a const keyword.

James Curran
+1  A: 

Other answers say the view from the standards perspective, but here's why it crashes.

Compilers typically put program literals – especially strings – in read-only memory. The memory is marked read-only by the OS, so any attempt to write to it will get trapped and, on your platform, this is what the segmentation fault indicates; an attempt to do an operation on some memory that isn't permitted. The other kind of crash associated with bad memory usage is a bus error, which typically indicates either a non-aligned memory access or a write to a page that isn't mapped at all. For C code, the difference is almost entirely academic (some other language implementations use these faults to help them manage memory).

Note that the trapping of writes to read-only is independent of the official semantics of the language. While you might have a char* pointing to it, you still can't write it. Always treat program literals as if they are pointing to constant memory and you won't go wrong (that they aren't that by default is because of the need to support compatibility with older programs).

Donal Fellows
And the (C89) standard doesn't specify what happens when you write to a literal precisely because they didn't want to specify the exact way in which a crash happens, and because they also wanted to allow compilers to support writable strings if they wanted (e.g., via a switch; gcc has `-fwritable-strings` to do that sort of thing, though needing that's really just an indication of a badly broken program if you ask me).
Donal Fellows