difference between char* and char[] with strcpy()

2019-04-08 21:53发布

问题:

I've been having trouble the past couple hours on a problem I though I understood. Here's my trouble:

void cut_str(char* entry, int offset) {
    strcpy(entry, entry + offset);
}

char  works[128] = "example1\0";
char* doesnt = "example2\0";

printf("output:\n");

cut_str(works, 2);
printf("%s\n", works);

cut_str(doesnt, 2);
printf("%s\n", doesnt);

// output:
// ample1
// Segmentation: fault

I feel like there's something important about char*/char[] that I'm not getting here.

回答1:

The difference is in that doesnt points to memory that belongs to a string constant, and is therefore not writable.

When you do this

char  works[128] = "example1\0";

the compiler copies the content of a non-writable string into a writable array. \0 is not required, by the way.

When you do this, however,

char* doesnt = "example2\0";

the compiler leaves the pointer pointing to a non-writable memory region. Again, \0 will be inserted by compiler.

If you are using gcc, you can have it warn you about initializing writable char * with string literals. The option is -Wwrite-strings. You will get a warning that looks like this:

 warning: initialization discards qualifiers from pointer target type

The proper way to declare your doesnt pointer is as follows:

const char* doesnt = "example2\0";


回答2:

The types char[] and char * are quite similar, so you are right about that. The difference lies in what happens when objects of the types are initialized. Your object works, of type char[], has 128 bytes of variable storage allocated for it on the stack. Your object doesnt, of type char *, has no storage on the stack.

Where exactly the string of doesnt is stored is not specified by the C standard, but most likely it is stored in a nonmodifiable data segment loaded when your program is loaded for execution. This isn't variable storage. Thus the segfault when you try to vary it.



回答3:

This allocates 128 bytes on the stack, and uses the name works to refer to its address:

char works[128];

So works is a pointer to writable memory.

This creates a string literal, which is in read-only memory, and uses the name doesnt to refer to its address:

char * doesnt = "example2\0";

You can write data to works, because it points to writable memory. You can't write data to doesnt, because it points to read-only memory.

Also, note that you don't have to end your string literals with "\0", since all string literals implicitly add a zero byte to the end of the string.



标签: c string char