Search code examples
carraysstringpointersstrcpy

Understanding char *, char[] and strcpy()


My understanding is as follows:

  • char * points to a string constant, modifying the data it points to is undefined. You can, however, change where it points to.

  • char[] refers to a block of memory that you can change. You can change its contents but not what it refers to.

  • strcpy(dest, src) copies src into dest.

My question is, is it incorrect to use strcpy() with the dest being a char * that is already pointing to something (as I believe the old contents will be overwritten by strcpy() - which is undefined behaviour)?

For example:

char *dest = malloc(5);
dest = "FIVE";

char *src = malloc(5);
src = "NEW!";

strcpy(dest, src); /* Invalid because chars at dest are getting overwritten? */

Solution

  • Your understanding is not totally correct, unfortunately.

    char * points at character data, and since there's no const in there, you can write to the data being pointed to.

    However, it's perfectly possible to do this:

    char *a = "hello";
    

    which gives you a read/write pointer to read-only data, since string literals are stored in read-only memory, but not "considered" constant by the language's syntax.

    It's better to write the above as:

    const char *a = "hello";
    

    To make it more clear that you cannot modify the data pointed at by a.

    Also, your examples mixing malloc() and assignment are wrong.

    This:

    char *dest = malloc(5);
    dest = "FIVE"; /* BAD CODE */
    

    Is bad code, and you should never do that. It simply overwrites the pointer returned by dest with a pointer to the string "FIVE" which exists somewhere in (again, read-only) memory as a string literal.

    The proper way to initalize newly allocated memory with string data is to use strcpy():

    char *dest = malloc(5);
    if(dest != NULL)
      strcpy(dest, "five");
    

    Note that checking the return value of malloc() is a good idea.

    There's no problem doing multiple writes to the same memory, that's a very basic idea in C; variables represent memory, and can be given different values at different times by being "written over".

    Something as simple as:

    int a = 2;
    
    printf("a=%d\n", a);
    a = 4;
    printf("a=%d\n", a);
    

    demonstrates this, and it works just fine for strings too of course since they are just blocks of memory.

    You can extend the above malloc()-based example:

    char *dest = malloc(5);
    if(dest != NULL)
    {
      strcpy(dest, "five");
      printf("dest='%s'\n", dest);
      strcpy(dest, "four");
      printf("dest='%s'\n", dest);
      strcpy(dest, "one");
      printf("dest='%s'\n", dest);
    }
    

    and it will print:

    dest='five'
    dest='four'
    dest='one'