6

Why does the first version make the program crash, while the second one doesn't? Aren't they the same thing?

Pointer Notation

char *shift = "mondo";
shift[3] = shift[2];

Array Notation

char shift[] = {'m', 'o', 'n', 'd', 'o', '\0'};
shift[3] = shift[2];

MWE

int main( void )
{
    char *shift = "mondo";
    shift[3] = shift[2];

    char shift[] = {'m', 'o', 'n', 'd', 'o', '\0'};
    shift[3] = shift[2];

    return 0;
}
Nerva
  • 329
  • 4
  • 13
  • @user3121023 Why? Even if I haven't used `const`? – Nerva Jan 24 '16 at 15:24
  • @user3379939 - It is due to historical reasons that const is not required. Back in the '70s they did not know better - summat to do with flower power and the grateful dead – Ed Heal Jan 24 '16 at 15:30
  • @user3121023: String literals such as `"mondo"` are allocated in such a way that they may or may not be writable; it depends on the platform. In your case, it is not writable, hence the error. In general, the behavior is *undefined*; it may work, it may crash, it may do something else. – John Bode Jan 24 '16 at 15:50
  • @CoolGuy: minimum working example. – John Bode Jan 24 '16 at 15:50

5 Answers5

6

No! This is one of the important issues in C. In the first, you create a pointer to a read-only part of memory, i.e. you can not change it, only read it. The second, makes an array of characters, i.e. a part of memory of continuous characters where you can have both read and write access, meaning you can both read and change the values of the array.

zuko32
  • 239
  • 1
  • 9
3

First one points to a string literal (usually in a read only section of code, should really be const char * but able to get away with it due to historical reasons)|.

The second one creates an array and then populates that array.

Therefore they are not the same

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
2

The first is allocating memory in the .TEXT segment while the second is putting it into the .BSS. Memory in the .TEXT segment is, effectively, read only or const:

 char *string = "AAAA";

This creates what is effectively a const char * since the memory will be allocated in the .TEXT segment as a string literal. Since this will typically be marked read-only, an attempt to write to it will generate an access violation or segmentation fault.

You want to do this:

 char string[] = "AAAA";

This will work as expected and allocate memory for a string of four capital As and use the variable string as a pointer to the location.

David Hoelzer
  • 15,862
  • 4
  • 48
  • 67
  • 1
    Sorry, but I did not fully understand what you mean. :P The char *string = "String" is valid if you just want to access these characters for reading. Yes, obviously if you want to change any value of any character of this part of memory you either have to use an array, as you show, or dynamically allocate memory. – zuko32 Jan 24 '16 at 15:29
  • I'll update to clarify.. – David Hoelzer Jan 24 '16 at 15:30
  • OK, now I understand what do you mean. But this is not right. What you do in the first is you allocate a part of memory of 4 continuous bytes, you store in each of these bytes the value of 'A', in hex 0x41 and then you return the address of the first byte and 'string' is a pointer to this address. It's just that you can't alter this memory, it is read-only. You can see what I mean if you use a debugger, like gdb. – zuko32 Jan 24 '16 at 15:36
  • Your explanation of `char *string = "AAAA";` is completely inaccurate. Try compiling some code containing `char *string = "AAAA";` and look at the generated assembly code. What it actually does is creates a string literal `"AAAA"` in memory (usually in the `.text` segment), and then assigns the *address of* that literal to the pointer. The program crashes when attempting to modify a value stored in read-only memory. Like zuko32 says, it's fine to read from that address—but it's not OK to write to it. – DaoWen Jan 24 '16 at 15:37
  • I'll check.. It wasn't my understanding of what's happening. – David Hoelzer Jan 24 '16 at 19:02
1

This creates a pointer to an existing string:

char *shift = "mondo";

This creates a new array of characters:

char shift[] = {'m', 'o', 'n', 'd', 'o', '\0'};

In the second case, you are allowed to modify the characters because they are the ones that you just created.

In the first case, you are just pointing to an existing string, which should never be modified. The details of where the string is stored is up to the particular compiler. For example, it can store the string in unmodifyable memory. The compiler is also allowed to do tricks to save space. For example:

 char *s1 = "hello there";
 char *s2 = "there";

s2 might actually point to the same letter 't' that is at the seventh position of the string that s1 points to.

To avoid confusion, prefer to use const pointers with string literals:

const char *shift = "mondo";

This way, the compiler will let you know if you accidentally try to modify it.

Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
1

Whenever you define a string using char * str = "hello"; This is implicitly expressed by compiler const char * str= "hello"; Which makes this symbol goes to read only location of program memory.

But in case of array the same is interpreted as char const *array[]; That's why compiler screams when user try to change base address of array. This is implicit done by compiler

anshkun
  • 105
  • 1
  • 12