3

My understanding is that it is meant to contain the memory address of a char variable, but now I'm seeing it can be used to create strings? For example,

char* ptr = "string";

How can ptr be assigned a string when it is meant to hold a memory address? I thought the dereference operator would be needed to change the value being pointed to?

papercut
  • 31
  • 1
  • Possibly a good dupe out there somewhere but I answered since this code is actually not standard C++, and the duplicates out there may well not make that point. – Bathsheba Apr 02 '20 at 16:30
  • 1
    Attempt to change that value is undefined behavior. For "string" is a `const char[]` lvalue. In fact, ISO C++ forbid code like `char* ptr = "string";`. – con ko Apr 02 '20 at 16:31
  • @JohnDing Only since C++11 though. (The last sentence.) – walnut Apr 02 '20 at 16:35
  • @walnut It's deprecated since ISO C++ came out, but of course my statement was not precise. – con ko Apr 02 '20 at 16:38
  • Does this answer your question? [Use of pointers on strings](https://stackoverflow.com/questions/46057088/use-of-pointers-on-strings) – Daemon Apr 02 '20 at 18:35
  • @Daemon: That one is on the C tag, although the bulk of it is indeed applicable to C++ so in that respect it's helpful and a good spot. There is a subtle difference, in C strings decay to a non-`const` pointer type, but the behaviour on attempting to modify the string via the pointer is undefined. In C++ strings decay to a `const` pointer type. – Bathsheba Apr 03 '20 at 06:54

2 Answers2

11

"string" is a const char[7] type literal. C++ allows you to use the rabbits ears to simplify the language. The 0 terminator is added for you, which is why there are 7 elements, not 6.

In various instances, array types decay to pointer types, with the pointer set to the first element of the array. Assignment is one of those instances. And that's what is happening here.

Formally, from C++11 onwards, your C++ compiler should not compile that statement. It should be

const char* ptr = "string";
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • If you really want to see what's going on, this is a nice read on memory segments. https://en.wikipedia.org/wiki/Data_segment – jiveturkey Apr 02 '20 at 16:33
7

Your understanding is correct; a char* does point to a single char.

The trick is that arrays are laid out contiguously in memory, so given a pointer to the first element of an array, you can access the other elements by simply adding an offset to the pointer. In your example, things look (logically) like this:

+-----+
| ptr |
+--+--+
   |
   v
 +-+-+---+---+---+---+---+----+
 | s | t | r | i | n | g | \0 |
 +---+---+---+---+---+---+----+

ptr points at the 's' at the beginning of "string". By adding 1 to ptr, you can find the 't', and so on. That's what the (builtin) [] operator does. ptr[2] is defined to be equvilent to *(ptr + 2): offset the pointer by 2 positions, and then fetch the value pointed to by the result.

A '\0' character is used to mark the end of the string, so that the consuming code knows to stop looking for more characters.

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52
  • This array/pointer duality is true for all other pointer declarations in C++ (e.g., int* pInt; float* pFloat) because of the backwards compatibility with C.Often (but not always) pointers are interchangeable with arrays because if you have a pointer to the first element of an array, C/C++ allows you to easily access the subsequent elements of the array. One must not access elements beyond the end of the array and (in the case of character arrays) allocate an extra character for the last null character. These issues are mitigated in C++ with such classes as std::string, std::array.... – Siegfried Apr 02 '20 at 17:27
  • So "string" is an array of characters and ptr points to the first element of that array, which is an s... that makes a lot of sense now. If I were to output ptr, what would be the difference between cout << ptr; and cout << *ptr; ? One gives the whole array and the other just gives the s, and I'm not sure why. I would have though ptr contains the memory address of the first element while *ptr contains the value there (the 's') – papercut Apr 02 '20 at 20:10
  • @papercut The standard library has an overloaded `operator<<(std::ostream&, const char*)` which `cout << ptr` calls that prints the full string. `cout << *ptr` calls `operator<<(std::ostream&, char)`, which prints a single character. If you want to print the address contained in `ptr`, use `cout << static_cast(str)`. – Miles Budnek Apr 02 '20 at 23:33