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.