3

I have seen (1, 2) that:

char s[] = "abc";
char t[3] = "abc";

are effectively identical to:

char s[] = { 'a', 'b', 'c', '\0' };
char t[] = { 'a', 'b', 'c' };

And the following:

char *word = "abc";
word[0] = 'd';

places word in read-only memory, causing the illegal memory operation word[0] = 'd' to error.

Is this only the case with chars? I can't get an error when I do something like this:

int array[] = {1, 2, 3};
int *p = array;
p[0] = 0; // No error here
array[1] = 1; // or here
Community
  • 1
  • 1
Alex Walczak
  • 1,276
  • 1
  • 12
  • 27
  • 2
    Yes these behaviours are specific to character arrays and string literals. Read the C standard for full details. – kaylum Dec 29 '16 at 00:32
  • 2
    Sincerely I don't know why they're down-voting your question. – UrbiJr Dec 29 '16 at 00:36
  • 1
    In your first chunk of code, `t[3] = "abc" should be `char t[3] = "abc"; similarly in your second chunk. – Keith Thompson Dec 29 '16 at 00:37
  • 2
    The first two lines are **not** identical to each other. And there is no requirement in the standard for ROM. A PC with the OS running does not even have ROM. There also is no requirement to generate run-time errors. It is not clear what you intend or what you actualy problem is. The snippets are not even comparable and there is information missing. – too honest for this site Dec 29 '16 at 00:38
  • 1
    Note that `word` is itself a modifiable variable; it could be assigned a new pointer value. When you use `char *word = "abc";`, you are making it point to a character literal, which is treated as an array of characters. Attempts to modify a string literal lead to undefined behaviour. The string need not be in readonly memory (though these days it usually is). An attempt to modify `"abc"` to `"dbc"` might succeed, and might also modify a string literal `"xyzabc"` to `"xyzdbc"` at the same time — or it might fail and cause the program to crash. You should use `const char *word = "abc";`. – Jonathan Leffler Dec 29 '16 at 02:42
  • Hey Jonathan, you said that `char *word = "abc";` makes `word` "point to a character literal, which is treated as an array of characters." However, arrays of characters are easily modified. Using the above code, I could have said `s[0] = 'b'` with no problem. Could you please clarify? – Alex Walczak Dec 29 '16 at 03:57

2 Answers2

7

It applies only to string literals.

A string literal implicitly creates an array object of type char[N] containing the character in the literal followed by a terminating \0' character. This object has static storage duration and is read-only. (It's not const, for historical reasons, but attempting to modify it has undefined behavior.)

When you write:

char *ptr = "abc";

you're creating ptr as a pointer object, and initializing it to point to the read-only static array containing "abc". (You can prevent attempts to modify it by defining it as const.)

When you write:

char arr[] = "abc";

you're creating arr as an array object, of type char[4], and copying the contents of the static read-only array into that object. arr is not read-only.

int array[] = {1, 2, 3};

creates an array object and initializes it as shown. There are no "integer array literals" that act like string literals. (There almost are -- see "compound literals" -- but those don't have the same read-only semantics as string literals.)

Note that this:

char t[3] = "abc";

is a special case: if an array is initialized with a string literal, and there isn't room for the terminating '\0', then only the non-null characters are copied to the array. As a result, t does not contain a string, just an unterminated sequence of characters. This isn't particularly relevant to your question.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Thanks! This is a little off topic, but you wrote: "You can prevent attempts to modify [`char* ptr = "abc"`] by defining it as `const`." Any attempt to modify `char* ptr = "abc"` (without `const`) already fails, so could you please clarify what you meant by that? Edit: I'm probably overlooking the possibility of the program without the `const` prefix (?) on a computer different from mine. – Alex Walczak Dec 29 '16 at 03:33
  • 1
    If you write `char *s = "abc"; s[0] = 'A';` you'll *probably* get a run-time crash. (In fact the behavior is undefined; some implementations might not catch it.) If you instead write `const char *s = "abc"; s[0] = 'A';` then the error will be caught by the compiler. Catching errors early is (almost) always better. – Keith Thompson Dec 29 '16 at 03:45
1

There's no exact analog for string literals for other array types. But you can come somewhat close by using a const-qualified compound literal

const int *p = (const int []) { 1, 2, 3 };

There is a chance it will be placed into read-only memory, and might crash the program if an attempt is made to modify it (after casting away constness that is). Another similarity with string literals is that const-qualified compound literals might share storage.

One obvious difference between compound literals and string literals is that string literals always have static storage duration, while block-level compound literals have automatic storage duration.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765