Search code examples
cstrcmpstrdup

what is different between initialization of string and using strdup()


What is the difference between

char *key_str="kiwi";

and

char *key_str = strdup("kiwi");

For example:

int strCmp(void *vp1, void *vp2) {
    char * s1 = (char *) vp1;
    char * s2 = (char *) vp2;
    return strcmp(s1, s2);
}

Why do those *key_str behave differently when used in the function strCmp()?

src code : https://github.com/alexparkjw/typing/blob/master/pa2.c


Solution

  • In C all literal strings are really arrays of (effectively read-only) characters.

    With

    char *str = "kiwi";
    

    you make str point to the first element of such an array.

    It is somewhat equivalent to

    char internal_array_for_kiwi[5] = { 'k', 'i', 'w', 'i', '\0' };
    char *str = &internal_array_for_kiwi[0];
    

    The strdup function dynamically allocates memory and copies the passed string into this memory, creating a copy of the string.

    So after

    char *str = strdup("kiwi");
    

    you have two arrays containing the same contents.

    It's equivalent to

    char internal_array_for_kiwi[5] = { 'k', 'i', 'w', 'i', '\0' };
    char *str = malloc(strlen(internal_array_for_kiwi) + 1);
    strcpy(str, internal_array_for_kiwi);
    

    An important difference between the two needs to be emphasized: Literal strings in C can't be modified. Attempting to modify such a string will lead to undefined behavior. The arrays aren't const, but are effectively read-only.

    If you create your own array (as an array or allocated dynamically) then you can modify its contents as much as you want, as long as you don't go out of bounds or change the string null-terminator.

    So if we have

    char *str1 = "kiwi";
    char *str2 = strdup("kiwi");
    

    then

    str1[0] = 'l';  // Undefined behavior, attempting to modify a literal string
    str2[0] = 'l';  // Valid, strdup returns memory you can modify
    

    Because literal strings can't be modified, it's recommended that you use const char * when pointing to them:

    const char *str1 = "kiwi";
    

    Another important thing to remember: Since strdup allocates memory dynamically (using malloc) you need to free that memory once you're done with the string:

    free(str2);
    

    If you don't free the memory then you will have a memory leak.


    Beyond the above, there's no effective difference between the two variants. Both can be used interchangeably when calling functions, for example.