Last Update:
Quick case: Char Pointer vs Char Array in C++
Table of Contents
When you write:
char strA[] = "Hexlo World!";
strA[2] = 'l';
Everything works as expected. But what about:
char *strP = "Hexlo World!";
strP[2] = '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 13
.
Our second case looks almost the same. Though, there is a subtle, but important, difference.
cout << "sizeof(strP) = " << sizeof(strP) << std;
strP[2] = '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[2] = '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:
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).
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]
VC Note: in Visual Studio 2013< /> there is option "/Zc:strictStrings" to prevent such conversion.
< >< />
The .rdata
/.rodata
section
Executable file on Windows has PE (Portable Executable) format. On Linux we have ELF (Executable and Linkable Format).
The above binary formats (and others) have, to simplify, two basic
sections: DATA
and CODE
:
DATA
- this section stores global and initialized variables. Here lies ourread-only-data
subsection:rdata
- PErodata
- ELF
CODE
- orTEXT
section - 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
but:
int globalArray[100]; // 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!
Wrap up
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.
References
- SO: When is a variable placed in
.rdata
section and not in.text
section? - SO: Where in memory are my variables stored in c?
- C++ FAQ
- An In-Depth Look into the Win32 Portable Executable File Format
Actions
Did you have similar problems?
Any strange errors/bugs with read only sections?
Thanks for comments:
I've prepared a valuable bonus for you!
Learn all major features of recent C++ Standards on my Reference Cards!
Check it out here: