Search code examples
cpointerscharchar-pointer

Is String Literal in C really not modifiable?


As far as I know, a string literal can't be modified for example:

char* a = "abc";
a[0] = 'c';

That would not work since string literal is read-only. I can only modify it if:

char a[] = "abc";
a[0] = 'c';

However, in this post, Parse $PATH variable and save the directory names into an array of strings, the first answer modified a string literal at these two places:

path_var[j]='\0';
array[current_colon] = path_var+j+1;

I'm not very familiar with C so any explanation would be appreciated.


Solution

  • Code blocks from the post you linked:

    const char *orig_path_var = getenv("PATH"); 
    char *path_var = strdup(orig_path_var ? orig_path_var : "");
    
    const char **array;
    array = malloc((nb_colons+1) * sizeof(*array));
    array[0] = path_var;
    array[current_colon] = path_var+j+1;
    

    First block:

    • In the 1st line getenv() returns a pointer to a string which is pointed to by orig_path_var. The string that get_env() returns should be treated as a read-only string as the behaviour is undefined if the program attempts to modify it.
    • In the 2nd line strdup() is called to make a duplicate of this string. The way strdup() does this is by calling malloc() and allocating memory for the size of the string + 1 and then copying the string into the memory.
    • Since malloc() is used, the string is stored on the heap, this allows us to edit the string and modify it.

    Second block:

    • In the 1st line we can see that array points to a an array of char * pointers. There is nb_colons+1 pointers in the array.
    • Then in the 2nd line the 0th element of array is initilized to path_var (remember it is not a string literal, but a copy of one).
    • In the 3rd line, the current_colonth element of array is set to path_var+j+1. If you don't understand pointer arithmetic, this just means it assigns the address of the j+1th char of path_var to array[current_colon].

    As you can see, the code is not operating on const string literals like orig_path_var. Instead it uses a copy made with strdup(). This seems to be where your confusion stems from so take a look at this:

    char *strdup(const char *s);

    The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory for the new string is obtained with malloc(3), and can be freed with free(3).

    The above text shows what strdup() does according to its man page.

    It may also help to read the malloc() man page.