If char*s are read only, why can I overwrite them?

Viewed 6973

My course taught me that char*s are static/read only so I thought that would mean you can't edit them after you have defined them. But when I run:

char* fruit = "banana";
printf("fruit is %s\n", fruit);
fruit = "apple";
printf("fruit is %s\n", fruit);

Then it compiles fine and gives me:

fruit is banana
fruit is apple

Why? Have I misunderstood what it means to be read-only? Sorry if this is obvious but I'm new to coding and I can't find the answer online.

9 Answers

when defining a C string, aka char array, by double quotations "...", in the format below:

char * <varName> = "<someString>"

only the elements of the array are immutable (their content can not be changed). In other words, the <varName> has a const char * type (a mutable pointer towards a read-only memory). And every time you invoke the assignment operator with double quotations <varName> = "<otherString>" it changes the pointer value automatically. The below example should give a complete overview of the different possibilities:

#include <stdio.h>

int main()
{
    char * var_1 = "Lorem";
    printf("1. %s , %p\n", var_1, var_1); // --> 1. Lorem , 0x400640

    var_1 = "ipsu";
    printf("2. %s , %p\n", var_1, var_1); // --> 2. ipsu , 0x400652

    // var_1[0] = 'x'; // --> Segmentation fault

    var_1++;
    printf("3. %s , %p\n", var_1, var_1); // --> 3. psu , 0x400653

    char var_2[] = {'L', 'o', 'r', 'e', 'm', '\0'};
    printf("4. %s , %p\n", var_2, var_2); // --> 4. Lorem , 0x7ffed0fc5381

    var_2[0] = 'x';
    printf("5. %s , %p\n", var_2, var_2); // --> 5. xorem , 0x7ffed0fc5381

    // var_2++; //error: lvalue required as increment operand

    char var_3[] = "Lorem";
    printf("6. %s , %p\n", var_3, var_3); // --> 6. Lorem , 0x7ffe36a42d5c

    // var_3 = "ipsu"; // --> error: assignment to expression with array type

    var_3[0] = 'x';
    printf("7. %s , %p\n", var_3, var_3); // --> 7. xorem , 0x7ffe36a42d5c

    char * const var_4 = "Lorem";

    // var_4 = "ipsu"; // --> error: assignment of read-only variable

    // var_4[0] = 'x'; // --> Segmentation fault

    char const * var_5 = "Lorem";
    printf("8. %s , %p\n", var_5, var_5); // --> Lorem , 0x400720

    var_5 = "ipsu";
    printf("9. %s , %p\n", var_5, var_5); // --> ipsu , 0x400732

    // var_5[0] = 'x'; // --> error: assignment of read-only location

    const char * var_6 = "Lorem";
    printf("10. %s , %p\n", var_6, var_6); // --> 10. Lorem , 0x400760

    var_6 = "ipsu";
    printf("11. %s , %p\n", var_6, var_6); // --> 11. ipsu , 0x400772

    // var_6[0] = 'x'; // --> error: assignment of read-only location

    const char const * var_7 = "Lorem"; // clang only --> warning: duplicate 'const' declaration specifier [-Wduplicate-decl-specifier]
    printf("12. %s , %p\n", var_7, var_7); // --> 12. Lorem , 0x400760

    var_7 = "ipsu";
    printf("13. %s , %p\n", var_7, var_7); // --> 13. ipsu , 0x400772

    // var_7[0] = 'x'; // --> error: assignment of read-only location

    char const const * var_8 = "Lorem"; // clang only --> warning: duplicate 'const' declaration specifier [-Wduplicate-decl-specifier]
    printf("14. %s , %p\n", var_8, var_8); // --> 14. Lorem , 0x400790

    var_8 = "ipsu";
    printf("15. %s , %p\n", var_8, var_8); // --> 15. ipsu , 0x4007a2

    // var_8[0] = 'x'; // --> error: assignment of read-only location

    char const * const var_9 = "Lorem";

    // var_9 = "ipsu"; // --> error: assignment of read-only variable

    // var_9[0] = 'x'; // --> error: assignment of read-only location

    const char var_10[] = {'L', 'o', 'r', 'e', 'm', '\0'};

    // var_10[0] = 'x'; // --> error: assignment of read-only location

    // var_10++; // --> error: lvalue required as increment operand

    char const var_11[] = {'L', 'o', 'r', 'e', 'm', '\0'};

    // var_11[0] = 'x'; // --> error: assignment of read-only location 

    // var_11++; // --> error: lvalue required as increment operand

    const char var_12[] = "Lorem";

    // var_12[0] = 'x'; // --> error: assignment of read-only location

    // var_12++; // --> error: lvalue required as increment operand

    char const var_13[] = "Lorem";

    // var_13[0] = 'x'; // --> error: assignment of read-only location

    // var_13++; // --> error: lvalue required as increment operand


    return 0;
}

this code was tested on GCC, Clang and Visual Studio.

Basically, there are three possibilities:

  • immutable pointer, mutable content

    • char <varName>[] = {'L', 'o', 'r', 'e', 'm', '\0'};
    • char <varName>[] = "Lorem";
  • mutable pointer, immutable content

    • char * <varName> = "Lorem";
    • char const * <varName> = "Lorem";
    • const char * <varName> = "Lorem";
    • const char const * <varName> = "Lorem";
    • char const const * <varName> = "Lorem";
  • immutable pointer, immutable content

    • char * const <varName> = "Lorem";
    • char const * const <varName> = "Lorem";
    • const char * const <varName> = "Lorem";
    • const char <varName>[] = {'L', 'o', 'r', 'e', 'm', '\0'};
    • char const <varName>[] = {'L', 'o', 'r', 'e', 'm', '\0'};
    • const char <varName>[] = "Lorem";
    • char const <varName>[] = "Lorem";

Conclusion:

  • <typing> <varName>[] = <string> always returns an immutable pointer and the mutability of the content is independant from the <array> format ("Lorem" or {'L', 'o', 'r', 'e', 'm', '\0'})
  • <typing> * <varName> = "someString" always returns immutable content
  • <typing> * const <varName> = "someString" always returns both immutable content and pointer
  • char const <other>, char const <other>, const char const <other>, and char const const <other> always create immutable content.

I have tried to summerise C's array behavior here in detail.

When you use char *p="banana"; the string banana is stored in a read only memory location. Following which when you enter p="apple"; the string apple is stored in some other memory location and the pointer is now pointing to the new memory location.

You can confirm this by printing p just after each assignment.

#include<stdio.h>
int main(void)
{
    char *p = "Banana";
    printf("p contains address of string constant 'Banana' at 0x%p\n", p);

    p="Apple";
    printf("p contains address of string constant 'Apple' at 0x%p\n", p);

}
Related