13
char *p = "string"; //creates pointer to constant string

char p[] = "string"; //just an array with "string"

I'm just a bit confused about why does it in the first example create a pointer to a constant string? Shouldn't it be just a pointer refering to a place in memory with "string"?

Mihai Neacsu
  • 2,045
  • 5
  • 23
  • 37

4 Answers4

25

In the first case, "string" may be stored in a read-only area of the process, so attempting to modify the memory pointed to by p would cause undefined behaviour.

In the second case, actual memory is allocated and initialised on the stack at runtime (or in an appropriate section of the process at program startup if it's not a local variable), so modifying the memory is OK.

The first case can be illustrated like this:

+---+           +---+---+---+---+---+---+---+
|   |   ---->   | s | t | r | i | n | g | \0|
+---+           +---+---+---+---+---+---+---+
  p

Whereas the second case is:

+---+---+---+---+---+---+---+
| s | t | r | i | n | g | \0|
+---+---+---+---+---+---+---+
              p

The two declarations have a significant difference, although you may have heard that they are the same from low-quality C programming books.

The first is a pointer of type char *, whereas the second is an array of type char []. Array identifiers decay to a pointer in some contexts, but that doesn't make them pointers.

A pointer is merely an address and an array is "the whole thing" - in the first case sizeof(p) yields the size of a pointer (usually 4 or 8 depending on the target machine), and in the second case it yields 7 * sizeof(char), the length of the actual string.

Blagovest Buyukliev
  • 42,498
  • 14
  • 94
  • 130
  • "a read-only area of the executable": maybe "process" is more significant here... "executable" is more focused on the disk file containing the program, but the key thing is that the memory into which that file content is copied will be made read-only by most modern OS loaders. I like that you've put your second-case `p` under 'i'... part of me wants to have it under 's' to emphase "array starting at..." - as understanding array offsets is important - but you've emphasised that p *is* all of the array containing the textual data, which is much more important in this context. +1 – Tony Delroy Jun 29 '11 at 09:36
  • Very good answer. Also the graphic method to explain the differences. – Alberto Solano Jun 29 '11 at 10:57
17

It is unfortunately legal in C (and in C++03, for compatibility). But any attempt to modify the string literal via the pointer will result in Undefined behavior. So, better always assign the string literal to a const char*

const char * cp = "Hello"; //OK
char* p = "Hello"; //OK in C and C++03 (unfortunately), Illegal in C++11
cp[0] = 'Y'; //Compile-time error, good
p[0] = 'Y'; //no compiler error, undefined behavior
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
3

The first one creates a pointer and sets it to the address of a constant string (presumably in a region that does not have write protection on pages). Writing to this pointer is illegal (and will probably crash).

The second one creates an array and copies characters into it. Writing to this array will write to some location on your stack and is perfectly legal.

Damon
  • 67,688
  • 20
  • 135
  • 185
  • 1
    In the first case, writing to the pointer is not illegal in C, it is undefined behaviour. It might cause a memory protection error or it might work fine. It depends entirely on the combination of compiler operating system and machine architecture. – JeremyP Jun 29 '11 at 09:55
1

In the first case, "string" may be stored in a read-only area of the process, so attempting to modify the memory pointed to by p would cause undefined behaviour.

It can be proved by running the above line of codes repeatedly.

char *p="string";

you will notice that the content of p (i.e. the address of "string") remains constant.

char p[] = "string"; 

for these memory is allocated hence each time you run content of p changes.

Pang
  • 9,564
  • 146
  • 81
  • 122