3

I'm completely new to the C++ language (pointers in particular, experience is mainly in PHP) and would love some explanation to the following (I've tried searching for answers).

How are both lines of code able to do exactly the same job in my program? The second line seems to go against everything I've learnt & understood so far about pointers.

char disk[3] = "D:";

char* disk = "D:";

How am I able to initialize a pointer to anything other than a memory address? Not only that, in the second line I'm not declaring the array properly either - but it's still working?

Jamie Cole
  • 51
  • 4

4 Answers4

7

The usual way to initialize an array in C and C++ is:

int a[3] = { 0, 1, 2 };
Aside: And you can optionally leave out the array bound and have it deduced from the initializer list, or have a larger bound than there are initializers:
int aa[] = { 0, 1, 2 };    // another array of three ints
int aaa[5] = { 0, 1, 2 };  // equivalent to { 0, 1, 2, 0, 0}

For arrays of characters there is a special rule that allows an array to be initialized from a string literal, with each element of the array being initialized from the corresponding character in the string literal.

Your first example uses the string literal "D:" so each element of the array will be initialized to a character from that string, equivalent to:

char disk[3] = { 'D', ':', '\0' };

(The third character is the null terminator, which is implicitly present in all string literals).

Aside: Here too you can optionally leave out the array bound and have it deduced from the string literal, or have a larger bound than the string length:
char dd[] = "D:";    // another array of three chars
char ddd[5] = "D:";  // equivalent to { 'D', ':', '\0', '\0', '\0'}
Just like the aaa example above, the extra elements in ddd that don't have a corresponding character in the string will be zero-initialized.

Your second example works because the string literal "D:" will be output by the compiler and stored somewhere in the executable as an array of three chars. When the executable is run the segment that contains the array (and other constants) will be mapped into the process' address space. So your char* pointer is then initialized to point to the location of that array, wherever that happens to be. Conceptually it's similar to:

const char __some_array_created_by_the_compiler[3] = "D:";
const char* disk = __some_array_created_by_the_compiler;

For historical reasons (mostly that const didn't exist in the early days of C) it was legal to use a non-const char* to point to that array, even though the array is actually read-only, so C and the first C++ standard allow you to use a non-const char* pointer to point to a string literal, even though the array that it refers to is really const:

const char __some_array_created_by_the_compiler[3] = "D:";
char* disk = (char*)__some_array_created_by_the_compiler;

This means that despite appearances your two examples are not exactly the same, because this is only allowed for the first one:

disk[0] = 'C';

For the first example that is OK, it alters the first element of the array.

For the second example it might compile, but it results in undefined behaviour, because what it's actually doing is modifying the first element of the __some_array_created_by_the_compiler which is read-only. In practice what will probably happen is that the process will crash, because trying to write to a read-only page of memory will raise a segmentation fault.

It's important to understand that there are lots of things in C++ (and even more in C) which the compiler will happily compile, but which cause Very Bad Things to happen when the code is executed.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
5
char disk[3] = "D:";

Is treated as

char disk[3] = {'D',':','\0'};

Where as in C++11 and above

char* disk = "D:";

Is an error as a string literal is of type const char[] and cannot be assigned to a char *. You can assign it to a const char * though.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • Don't you think this answer would be kind of confusing to someone who is new to C++, and isn't aware of version differences, and on their compiler, the code is clearly compiling? (or maybe you weren't aware that this used to be legal) – Benjamin Lindley Aug 26 '15 at 18:37
  • @BenjaminLindley It didn't occur to me to add that it used to be okay as the question is tagged as C++ which should be answered with the current standard. I have added to my answer to call out that it is an error in and after C++11. – NathanOliver Aug 26 '15 at 18:41
5

String literals are actually read-only, zero-terminated arrays of characters, and using a string literal gives you a pointer to the first character in the array.

So in the second example

char* disk = "D:";

you initialize disk to point to the first character of an array of three characters.


Note in my first paragraph above that I said that string literals are read-only arrays, that means that having a plain char* pointing to this array could make you think that it's okay to modify this array when it's not (attempting to modify a string literal leads to undefined behavior). This is the reason that const char* is usually used:

const char* disk = "D:";

Since C++11 it's actually an error to not use a const char*, through most compilers still only warn about it instead of producing an error.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • `char* disk = "D:";` should be a warning at minimum and should be an error according to the standard. http://coliru.stacked-crooked.com/a/723cd7928608aed0 – NathanOliver Aug 26 '15 at 18:13
  • @NathanOliver, according to the standard it should be a diagnostic message, defined as a "message belonging to an implementation-defined subset of the implementation’s output messages". Warnings are technically compliant with that. – Jonathan Wakely Aug 26 '15 at 18:38
2

You are absolutely right to say that pointers can store only memory address. Then how is the second statement valid? Let me explain.

When you put a sequence of characters in double quotes, what happens behind the screens is that the string gets stored in a read only computer memory and the address of the location where the string is stored is returned. So at run-time, the expression is evaluated, the string evaluates to the memory address, which is a character pointer. It is this pointer that is assigned to your pointer variable.

So what is the difference between the two statements? The string in the second case is a constant, while the string declared by the first statement can be changed.

daltonfury42
  • 3,103
  • 2
  • 30
  • 47
  • 1
    Thanks, but if it's a constant then how come I can change it? `char* disk = "A"; disk = "BBB"; cout << disk;` – Jamie Cole Aug 26 '15 at 19:16
  • 1
    @JamieCole, The string is read only, while the pointer is not. What you are doing is to assign another memory address to the pointer. But you can't do `*disk ++` and change the value from 'A' to 'B'. – daltonfury42 Aug 26 '15 at 19:23