forbiddens in string literals in C

前端 未结 5 671
逝去的感伤
逝去的感伤 2020-12-11 10:00

In the K&R book page 104, I came across this statement:

char amessage[] = \"now is the time\"; //an array
char *pmessage = \"now is the time         


        
相关标签:
5条回答
  • 2020-12-11 10:26

    If you do this:

    char amessage[] = "now is the time"; //an array
    char *pmessage = "now is the time";  //a pointer
    

    You probably really want to be doing this:

    const char *pmessage = "now is the time";  //a pointer
    

    When your program is compiled, somewhere in memory there will be the bytes "now is the time" (note there is a NULL terminator). This will be in constant memory. You shouldn't try to change it, if you do weird things can result (exactly what will happen will depend on your environment and if it is stored in read-only or read-write memory). So while K&R was trying to enlighten you on how you could do things, the pragmatic way is to make pointers to constant strings const, then the compiler will complain if you try to change the contents.

    0 讨论(0)
  • 2020-12-11 10:29

    There is nothing inherently wrong with using pointers as arrays, unless those pointers point to constant data (and string literals are constant data). Although semantically incorrect, in the old days of no memory protection, pmessage[0] = 'n'; would have actually worked with unpredictable results (e.g. affecting all occurrences of the same literal within the program). On modern operating system this could not happen because of the memory protection in place. String literals and other constants are put in so-called read-only sections of the executable and when the executable is loaded in memory in order to create a process, the memory pages that contain the read-only sections are made to be read-only, i.e. any attempt to change their content leads to segementation fault.

    char amessage[] = "now is the time";
    

    is really a syntactic sugar for the following:

    char amessage[] = { 'n','o','w',' ','i','s',' ','t',
                        'h','e',' ','t','i','m','e','\0' };
    

    i.e. it creates an array of 16 characters and initialises its content with the string "now is the time" (together with the NULL terminator).

    On the other hand

    char *pmessage = "now is the time";
    

    puts the same string data somewhere in the read-only data and assigns its address to the pointer pmessage. It works similar to this:

    // This one is in the global scope so the array is not on the stack
    const char _some_unique_name[] = "now is the time";
    
    char *pmessage = _some_unique_name;
    

    _some_unique_name is chosen so as to not clash with any other identifier in your program. Usually symbols that are not permitted by the C language, but are ok for the assembler and the linker, are used (e.g. dots like in string.1634).

    You can change the value of a pointer - this will make it point something else, e.g. to another string. But you cannot change the address behind the name of an array, i.e. amessage will always refer to the same array storage that was allocated for it in first place.

    You can refer to individual elements of each string using amessage[i] or pmessage[i] but you can only assign to the elements of amessage as they are located in the read-write memory.

    0 讨论(0)
  • 2020-12-11 10:30
    char amessage[] = "now is the time"; //an array
    

    An array name is a constant.that is address of array can not be changed.But content of array can be changed.

    SO

    amessage[0]='n';//valid and it change the first element
    

    BUT

    amessage="hello";//if you try then it wrong as array address can not be changed
    

    Now see the pointer part:-

    char *pmessage = "now is the time";  //a pointer
    

    As it is a pointer it can point to any address.But that address location in memory may be modifiable or may not be modifiable.that is may be read Only or may be both read write allowed.

    so when you try to change the some data in memory using pointer pmessage then depend upon pointing memory result depends.Here it point to code section so read only.so modification not allowed.

    so

    pmessage[0]='n';//definitely give you error
    
    0 讨论(0)
  • 2020-12-11 10:38
    /* OK, modifying an array initialized by the 
     * elements of a string literal */
    amessage[0] = 'n';
    
    /* not OK, modifying a string literal.
     * String literals are non-modifiable */
    pmessage[0] = 'n';
    

    Note that in C you cannot assign arrays, so if you want to copy an array use memcpy function or use strcpy function to copy a string.

    0 讨论(0)
  • 2020-12-11 10:45
    char amessage[] = "now is the time";
    /*   ^            ^
         (an array)   (a string literal) */
    

    When you use a string literal to initialize an array in this way, you're setting the initial values of the elements of the array to those of the literal itself. And of course the array is allocated its own separate memory. And you can modify its contents.

    char *pmessage  = "now is the time";
    /*   ^            ^
         (a pointer)  (a string literal) */
    

    When you use a string literal to initialize a pointer, you're making the pointer point to a string literal. This string literal may be stored in read-only memory. And therefore cannot be modified. The pointer itself can be modified.

    What's valid, and what's not?

    amessage[0] = 'n'; /* Valid. Modifying array contents.  */
    amessage = pmessage; /* Invalid. You cannot assign to an array.  */
    pmessage[0] = 'n'; /* Invalid. You're trying to modify a string literal.  */
    

    But:

    pmessage = amessage; /* Valid. You're modifying a pointer. */
    

    Subsequently:

    pmessage[0] = 'n'; /* Valid. You just modified pmessage above,
                       and it now points to modifiable memory.  */
    

    Finally: There's a C-FAQ entry exactly about this. It's worth a read.

    Inspired by ouah's answer. I didn't want to make a big edit to it.

    0 讨论(0)
提交回复
热议问题