Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 535
sally2000 Avatar asked May 31 '17 21:05

sally2000


People also ask

Does char * need to be deleted?

You delete (or delete[]) it when you longer need it and when it points to a char object that you created with new or new[]. You shouls delete/free only if it created with new/malloc, not if it is created on the stack.

Why are C string literals read only?

The string literal is stored in the read-only part of memory by most of the compilers. The C and C++ standards say that string literals have static storage duration, any attempt at modifying them gives undefined behavior. s is just a pointer and like any other pointer stores address of string literal.

Can you redefine a string in C?

You need to copy the string into another, not read-only memory buffer and modify it there. Use strncpy() for copying the string, strlen() for detecting string length, malloc() and free() for dynamically allocating a buffer for the new string. Show activity on this post. The malloc needs 1 more byte.

What is read only memory in C?

Read-Only Memory (ROM) is the primary memory unit of any computer system along with the Random Access Memory (RAM), but unlike RAM, in ROM, the binary information is stored permanently . Now, this information to be stored is provided by the designer and is then stored inside the ROM .


2 Answers

The presented code snippet does not change the string literals themselves. It only changes the values stored in the pointer fruit.

You can imagine these lines

char* fruit = "banana";
fruit = "apple";

the following way

char unnamed_static_array_banana[] = { 'b', 'a', 'n', 'a', 'n', 'a', '\0' };
char *fruit = &unnamed_static_array_banana[0];
char unnamed_static_array_apple[]  = { 'a', 'p', 'p', 'l', 'e', '\0' };
fruit = &unnamed_static_array_apple[0];

These statements do not change the arrays that correspond to the string literals.

On the other hand if you will try to write

char* fruit = "banana";
printf("fruit is %s\n", fruit);
fruit[0] = 'h';
^^^^^^^^^^^^^^
printf("fruit is %s\n", fruit);

that is if you will try to change a string literal using a pointer that points to it (to the first character of the string literal) then the program will have undefined behavior.

From the C Standard (6.4.5 String literals)

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

like image 127
Vlad from Moscow Avatar answered Oct 15 '22 07:10

Vlad from Moscow


In your program, the expression "banana" denotes a string literal object in the program image, a character array. The value of the expression is of type char *, or "pointer to character". The pointer points to the first byte of that array, the character 'b'.

Your char *fruit variable also has type "pointer to character" and takes its initial value from this expression: it is initialized to a copy of the pointer to the data, not the data itself; it merely points to the b.

When you assign "apple" to fruit, you're just replacing its pointer value with another one, so it now points to a different literal array.

To modify the data itself, you need an expression such as:

char *fruit = "banana";
fruit[0] = 'z';  /* try to turn "banana" into "zanana" */

According to the ISO C standard, the behavior of this is not defined. It could be that the "banana" array is read-only, but that is not required.

C implementations can make string literals writable, or make it an option.

(If you are able to modify a string literal, that doesn't mean that all is well. Firstly, your program is still not well defined according to ISO C: it is not portable. Secondly, the C compiler is allowed to merge literals which have common content into the same storage. This means that two occurrences of "banana" in the program could in fact be exactly the same array. Furthermore, the string literal "nana" occurring somewhere in the program could be the suffix of the array "banana" occurring elsewhere; in other words, share the same storage. Modifying a literal can have surprising effects; the modification can appear in other literals.)

Also "static" and "read-only" aren't synonymous. Most static storage in C is in fact modifiable. We can create a modifiable static character array which holds a string like this:

/* at file scope, i.e. outside of any function */
char fruit[] = "banana";

Or:

{
  /* in a function */
  static fruit[] = "banana";

If we leave out the array size, it is automatically sized from the initializing string literal, and includes space for the null terminating byte. In the function, we need static to put the array into static storage, otherwise we get a local variable.

These arrays can be modified; fruit[0] = 'z' is well-defined behavior.

Also, in these situations, "banana" doesn't denote a character array. The array is the variable fruit; the "banana" expression is just a piece of syntax which indicates the array's initial value:

char *fruit = "banana";  // "banana" is an object in program image
                         // initial value is a pointer to that object

char fruit_array[] = "apple"; // "apple" is syntax giving initial value
like image 40
Kaz Avatar answered Oct 15 '22 09:10

Kaz