1

What's the difference between this two literal string definitions?:

const char *message1 = "message1";
const char message2[] = "message2";

If both of them are null-terminated it's so strange - when i pass the first one to some text printing function I get an "memory could not be written" error but when pass the second everything is OK!?

enter image description here

The function of question is some 3-rd party function from Fallout 2 game mod source called sfall. The function as far as i know calls the native Fallout 2 engine defined function which the sfall code calls by it's own wrapper.

Daros911
  • 435
  • 5
  • 14
  • 2
    `message1` is a pointer while `message2` is an array – NathanOliver Jun 08 '21 at 17:27
  • 4
    Note that the string literals in the question are `"message1"` and `"message2"`. The variables named `message1` and `message2` are not string literals. – Pete Becker Jun 08 '21 at 17:36
  • 3
    *"memory could not be written"* I smell a poor "printing function" that tries to modify the string, ignoring the fact that it's `const`. – HolyBlackCat Jun 08 '21 at 17:44
  • 1
    @HolyBlackCat I was just about to say the same thing. Why is a *printing* function trying to *write* to a string's memory? It should only be *reading* from the string – Remy Lebeau Jun 08 '21 at 17:45
  • What "some text printing function" are you referring to? Your question seems to be about the behavior of this function – Drew Dormann Jun 08 '21 at 17:45
  • If both `message1` and `message2` are compatible with your function, then your function probably takes a `const char *` as its argument, which means the function is not allowed to write anything to the pointed object, using that pointer. The error message indicates that there is a serious problem with that function. – François Andrieux Jun 08 '21 at 17:49
  • @DrewDormann I've updated my question... – Daros911 Jun 08 '21 at 17:57
  • It just means that the function is poorly written, and to be safe you should give it a non-const array: `char message[] = "...";`. The fact that the second version doesn't crash for you is mostly a coincidence; it can start doing so in the future, since modifying `const` objects causes undefined behavior. If the function was written properly, both options you have would work. – HolyBlackCat Jun 08 '21 at 18:00
  • If you call the second version does your string gets modified? – Dundo Jun 08 '21 at 18:10

3 Answers3

2

In the first case the string literal decays to pointer.

In the second case the string literal gets stored to an array of char that the compiler will automatically size to fit the literal complete with the null terminator.

With the second you are retaining more information in your variable. So for example you can call std::size on the second but not on the first.

Calling a printing function that takes const char* should be the same with both cases. Since in the second case the const char[] would decay to pointer at the moment of the function call.

user4581301
  • 33,082
  • 7
  • 33
  • 54
Dundo
  • 714
  • 8
  • 12
2
const char message2[] = "message2";

"message2" will be placed in read-only memory. Then its characters are copied to the allocated memory of the message2[] array.

const char *message1 = "message1";

"message1" will be placed in read-only memory. message1 will simply be a pointer to that memory.

In both examples, values are constant.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • As I've investigated in the debugger at some breakpoint both variables are allocated at totally different addresses. Could it be the reason of the error? – Daros911 Jun 08 '21 at 18:17
  • 1
    You can not write in read-only memory, because it lives for the entire life of the program. The first variable points that read-only memory, that's why you got ERROR. But the second one allocates automatic storage which writable. String literal is copied to that variable. – Mushfiqur Rahman Jun 08 '21 at 18:33
1

What's the difference between this two literal string definitions?

message1 is a pointer to a string literal.

message2 is an array copy of a string literal.

Consider a hypothetical hostile printing function

void hostile_print( const char* msg )
{
    const_cast<char*>(msg)[0] = 0;
}

In the code below, the address of this string literal could be located in memory that the OS has marked as read-only. That's not uncommon for string literals.

Regardless, hostile_print commits Undefined Behavior and the OS gives you that angry dialog box. Because Undefined Behavior can look like that.

const char *message1 = "message1";
hostile_print(message1);

In the code below, the address of the array could be located in memory that the OS has marked as writable. Perhaps the stack. That's not uncommon for local arrays.

Regardless, hostile_print commits Undefined Behavior and the program proceeds as expected. Because Undefined Behavior can look like that.

const char message2[] = "message2";
hostile_print(message2);

In either case, the function is writing to memory that it shouldn't.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180