When you write:
char strA = "Hexlo World!"; strA = 'l';
Everything works as expected. But what about:
char *strP = "Hexlo World!"; strP = 'l';
Do you think it will work correctly? If you are not sure, then I guess, you might be interested in the rest of article.
In Visual Studio 2013 I got this message:
Definitely not nice! And probably some stupid mistake :)
What's the problem?
The first example shows simple array initialization. We can read/write from/to the array
strA. We can even print its size:
cout << "sizeof(strA) = " << sizeof(strA) << endl;
And guess what? The output is of course
Our second case looks almost the same. Though, there is a subtle, but important, difference.
cout << "sizeof(strP) = " << sizeof(strP) << std; strP = 'l'; // << crash
This will print
size of the pointer (4 or 8 bytes). The problem is that this pointer points to read-only memory! That way, when we want to modify the string (
strP = 'l';), we get runtime error.
Let's see C++FAQ for some details:
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.
Our first case follows the first rule - it is array initialization. The second code is unnamed static array of character.
It seems that it is up to compiler to decide whether such string goes to read-only or read-write section. Usually compilers (GCC and Visual Studio) places it in the read only block. Any attempt to change such memory location will be a bug.
Advice: do not use
char *p = "..."! Use string literals only for
const char * or array initialization. Also, remember about
std::string which is usually more useful.
GCC Note: It seems that GCC does a better job when compiling such code, you will get the following warning:
deprecated conversion from string constant to 'char*'[-Wwrite-strings]
The above binary formats (and others) have, to simplify, two basic sections:
DATA- this section stores global and initialized variables. Here lies our
TEXTsection - stores compiled binary code. This section is also read-only.
In general when we write:
const int globalA = 10; // will be in .r(o)data
int globalArray; // will be stored in .data, no initialization. // To clarify, it will go .bss section.
String literals (assigned to pointers) also follow 'global variables' rule. So it it important to treat them as read-only and do not try to change them!
char *s = "aaa"creates a pointer, to read only chunk of memory. If you try to modify this data you will get runtime error!
- Do not use such construction in your code!
char s = "aaa"creates a normal array and initializes it.
- Executable format (PE or ELF) consists of several sections. Two, most notable, are DATA and TEXT. In DATA all global and initialized variables are stored. In TEXT there is a compiled code.
- SO: When is a variable placed in
.rdatasection and not in
- SO: Where in memory are my variables stored in c?
- C++ FAQ
- An In-Depth Look into the Win32 Portable Executable File Format
Did you have similar problems?
Any strange errors/bugs with read only sections?
Thanks for comments: