2

On this answer by michael-burr on this question:

what-is-the-type-of-string-literals-in-c-and-c

I found that

In C the type of a string literal is a char[] - it's not const according to the type, but it is undefined behavior to modify the contents

from this I can think that sentence "How are you" can't be modified (just as char c*="how are you?") but once it is used to initialize some char[] then it can be unless declared as const.

Apart from this from that answer:

The multibyte character sequence is then used to initialize an array of static storage duration

and from C Primer Plus 6th Edition I found:

Character string constants are placed in the static storage class, which means that if you use a string constant in a function, the string is stored just once and lasts for the duration of the program, even if the function is called several times

But when I tried this code:

  #include <stdio.h>

  void fun() {
      char c[] = "hello";
      printf("%s\n", c);
      c[2] = 'x';
  }

  int main(void) {
      fun();
      fun();

      return 0;
   }

The array inside function fun doesn't behave as if it has retained the changed value.

Where am I going wrong on this?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Gaurav
  • 1,570
  • 5
  • 17
  • The string literal found on the right side of the `char c[] = ` assignment isn't the same string literal being discussed in the answer you linked. In your example, the string literal is by the compiler interpreted as a sequence of bytes to be stored in the memory location at `c` (the char array), which is allocated on the stack, is non-static, and is modifiable. See [this answer](https://stackoverflow.com/a/2589963/5447136) – bool3max Sep 08 '18 at 13:40
  • It retains if you declare it static: static char c[]="hello"; – purec Sep 08 '18 at 13:44
  • This question is the evidence that some advanced topics should not be read before OP understand well the basic idea of the pointers and arrays – 0___________ Sep 08 '18 at 13:51
  • UB seems to be relevant to multibyte literals: of course result will be unpredicted if you try to modify one byte of the mb secquence. – purec Sep 08 '18 at 13:57
  • No, they have too broad definition of string literals: it is multibyte. And UB in every hole. Which is also too broad. – purec Sep 08 '18 at 14:18
  • Static duration means that the address is same. But where did you get this main(void) ? I am just curious. – purec Sep 08 '18 at 14:28
  • @purec Its from ideone and also since no argument is being passed so its better to mention void. – Gaurav Sep 08 '18 at 14:47
  • I see. But you can't actually pass anything to main() if you don't use recursion, which is stupid way to use main function. – purec Sep 08 '18 at 15:18
  • @purec Through command line arguments one can pass arguments to main. – Gaurav Sep 08 '18 at 15:24
  • Yes, but nothing will happen if you have just main(). – purec Sep 08 '18 at 15:40

3 Answers3

3

char c[]="hello"; is not at all the same thing as char *c="hello";. The latter initializes a pointer to the aforementioned static string storage, modifying c[2] would be undefined behavior. The former is equivalent to:

char c[] = {'h', 'e', 'l', 'l', 'o', '\0'};

It's initializing an array on the stack, it's not creating a reference or pointer to the static string in some other memory location. Like any other non-const stack array, you can modify it however you please (as long as you don't go out of bounds).

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
2

Because it is an automatic variable and it's instance is initialized every time you call the function.

Change it to have static storage

  static char c[]="hello";

And it will behave as you expect keeping the changed value between the function calls

This is something completely different from how the string literals and compound literals are stored and used in the variable initialization. It is left to the implementation - for example this initialization of the automatic storage variable may be done by copying data from .rodata segment or it can be just couple immediate store instructions and the literal will be stored in the .text segment

0___________
  • 60,014
  • 4
  • 34
  • 74
  • I can understand that when marked explicitly as `static` it will hold the value in subsequent invocation but it is just said that "Character string constants are placed in the static storage class" - nowhere it is said that it should be marked static. – Gaurav Sep 08 '18 at 14:00
  • @user10334659 The string literal is static; your variable is only static if you declare it so. `c` is not a string literal. – melpomene Sep 08 '18 at 14:01
  • @user10334659 something to be copied during the initialization has to be stored somewhere. But where and how it is implementation defined. char x[]="c" ; will compile on many compilers just to one store instruction with the 'c' hided in the machine code instruction. So just remember: if you assign the pointer with address of the literal or compound literal you should not modify the referenced object – 0___________ Sep 08 '18 at 14:06
  • @melpomene so the literal stays static but the variable doesn't until and unless marked explicitly. – Gaurav Sep 08 '18 at 14:08
  • This is not static in the same sense as in the variable declaration. They should use the word `permanent` as they will exist every time they are needed. But it does not mean that they will have any storage as they may be inlined in the code as well. – 0___________ Sep 08 '18 at 14:10
  • @P__J__ Just one more thing - where can I read more about these things? Pointers and Arrays from K&R? – Gaurav Sep 08 '18 at 14:15
  • @user10334659 No. The topic is related to compiler internals and there is no books as I know. Write a lots programs - see what compiler has generated and knowledge will come with time and tens of kilo lines written, understanding of the linking process, linker scripts (then you will learn about the memories, segments, startup codes and many other related topics). For the "normal" C programming this knowledge is not very useful and it is not needed. The only thing you must remember as rule of thumb: `do not modify the literals` – 0___________ Sep 08 '18 at 14:32
2

You’re not modifying the string literal. You’re modifying a local array that contains a copy of the string literal. Each time you call fun, a new instance of c is created and initialized. When fun exits, that instance of c ceases to exist.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • So when `c` ceases to exist then the string literal still doesn't gets destroyed (due to static storage duration)? If yes then where is it originally stored? – Gaurav Sep 08 '18 at 13:52
  • Forget about the literals and how they are stored loaded and destroyed. It is too early for you. As I wrote you they may not even exist as a separate being – 0___________ Sep 08 '18 at 13:55
  • @user10334659 Because the string literal is only used to initialize another variable (and thus it cannot be used elsewhere, its address cannot be taken, etc), gcc has apparently decided that the best place to store it is inline as immediate operands of two `mov` instructions: https://godbolt.org/z/_-3q50 (`movl $111, %eax`, `movl $1819043176, 10(%rsp)`) – melpomene Sep 08 '18 at 14:05