Where does the compound/string literals get stored in the memory?
Asked Answered
C

4

9

I read that ;

A compound literal is a C99 feature that can be used to create an array with no name. Consider the example:

int *p = (int []){3, 0, 3, 4, 1};

p points to the first element of a five- element array containing 3, 0, 3, 4, and 1.

Actually I want to know, Is this array will stored in memory or not as it doesn't have a name?
In other words in case of

char* str = "hello"

Where the string "hello" will stored in memory?

Congdon answered 26/7, 2013 at 20:17 Comment(25)
@user2553780; Though array has no name?Congdon
@Congdon What? You just declared an int *p...Frowsty
Once you have a pointer, it doesn't matter how it was assigned. You can use it the same way. An array returned by malloc() has no name, either.Jefferyjeffie
@H2CO3; I think this question is misinterpreted. I know pointer arithmetic. Actually I want to know, Is this array will stored in memory or not as it doesn't have a name?Congdon
@Congdon It has block scope - it's an unnamed, temporary object which is alive as far as its enclosing block lasts.Frowsty
@H2CO3; Yeah. It written in book that it is created "on the fly", but still in block scope a variable name is needed.Congdon
@Congdon No, it's not needed.Frowsty
@Congdon Sorry, I don't understand that, please rephrase your sentence.Frowsty
@H2CO3; I mean to say, Is the reason behind no name is needed in block scope in this case is I assigned the CL to pointer p?Congdon
The string literal in char * p = "some words"; doesn't have a "name", either, but would you think this wasn't "stored in memory" either?Lusty
@PaulGriffiths; That's what I have not understand yet.Congdon
@H2CO3, sorry, but compound literals don't have scope, no objects have. Scope is a property of identifiers and not of objects. You probably mean "lifetime". This is a bit more complicated, basically the lifetime of such an object (like any automatic object) ends when the enclosing block isn't reachable anymore by the execution. "Reachable" could mean normal control flow, but also jumps like goto or longjmp.Bandy
@JensGustedt Right, I meant "lifetime".Frowsty
@haccks: "names" are just symbols that are used to refer to objects, which are basically just regions of data storage. Your program needs a name to refer to something (even with pointers, at least the pointer has to have a name) but your compiler doesn't need a name to create them. On the contrary, if anything - you have to have an object first, before you can have a name which refers to it. Your compiler could write literals right into your object code, if it wanted to, and they'd "exist" in some sense even when your program wasn't running.Lusty
Actually, come to think of it, it would have to do this, otherwise it wouldn't know how to create them at run-time.Lusty
@PaulGriffiths; OK. You mean to say (int []){...} is an object with no name?Congdon
@haccks: Yes, although no object really has a name, so in that sense, it's not different to any other object. A name can refer to an object, but that name doesn't somehow belong to the object. Down in the internals, a name is always going to just resolve to an address in one way or another.Lusty
@PaulGriffiths; I never knew that (int []){...} declares an object. I am surprised!.Congdon
@haccks: Why? How would you be able to access the values if it wasn't an object? There'd be no place for the values to go, it would defeat the whole purpose of having such a construction.Lusty
@PaulGriffiths; If you look at my question again then you will realize that this is what I wanted to know (unfortunately the question is not formatted well). I am feeling sad for your +25 reputation(my bad) :).Congdon
@haccks: Well, other people answered your question better than I did. Both Jason and Grijesh told you it was stored in the data segment of your executable, which answers "Where the string hello will stored in memory?"Lusty
@PaulGriffiths: Inside a function, compound literals and string literals have different storage durations. Compound literals inside functions have automatic storage duration, so they cannot be in the data segment unless optimization permits it because there is no “observable” difference. String literals have static storage duration.Woodbury
@EricPostpischil: I stand corrected. Where in the executable do they go, then, if not the data segment?Lusty
@PaulGriffiths: The compiler could store an image of the initial value of the object in the constant data section and copy it to the stack each time an instance is created. Or it could construct it with immediate values in instructions. There are other possibilities too.Woodbury
@EricPostpischil: Interesting - thanks!Lusty
W
5

C 2011 (N1570) 6.5.2.5 5 says:

If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

So the compound literal you show has automatic storage duration. The C standard does not specify where such objects are in memory. It is up to the C implementation to organize memory. Typically, an object with automatic storage duration is created on the stack, but there are other methods by which an implementation might manage such objects.

In particular, suppose you record the value of p elsewhere and recursively call the routine containing this compound literal. When the routine initializes p again, there is a second instance of the compound literal. They are actually different objects, and the C standard requires that their addresses be different. So, if you print the two pointers, they will have different values. However, if the optimizer is able to determine that you do not do this, and that two pointers to different instances of the compound literal are never compared, and there is no other observable behavior (as defined by the C standard) that can distinguish them, then the C implementation is free to use one actual instance of the compound literal instead of creating a new one each time. In this case, the compiler could keep the compound literal in a data section instead of on the stack.

Here is code that demonstrates two instances of the same compound literal have different addresses:

#include <math.h>
#include <stdio.h>


void foo(int *q)
{
    int *p = (int []) { 2, 3 };
    if (!q)
        foo(p);
    else
        printf("p = %p, q = %p.\n", (void *) p, (void *) q);
}


int main(void)
{
    foo(0);
    return 0;
}

String literals are different. C 2011 (N1570) 6.4.5 6 says:

In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals.78) The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence.

So a string literal denotes an object with static storage duration. There is only one instance of it even if a routine containing it is called recursively.

Woodbury answered 26/7, 2013 at 22:43 Comment(7)
Additionally, in the case of string literals it is explicitly called out that they may not be distinct objects, whereas compound literals must at least appear to be.Juno
Hi Eric!.. I have a question. Suppose I declare: int *p = (int []){3, 0, 3, 4, 1}; and then I try to modify array p[2] = 34; Is it possible? I believe it will causes an segmentation fault because I am trying to change constant array.Heritable
@GrijeshChauhan: I do not see a prohibition in the C standard against modify a compound literal, as long as it does not have the const attribute.Woodbury
@Er icPostpischil So char* s = "hello"; and char* s = (char []){'h', 'e', 'l', 'l', 'o', '\0'}; are quit different ?Heritable
@GrijeshChauhan: Yes. For simplicity, you can write the latter as char *s = (char []){"hello"};.Woodbury
@EricPostpischil Is char str[7] = "grijesh"; is valid or Undefined behavior It doesn't give a warning/or error with gcc -Wall -pedantic Whereas if I defined like char name[7] = {'1', '2', '3', '4', '5', '6', '7', '\0'}; it causes warning `excess elements in array initializer.Heritable
@GrijeshChauhan: In C, char str[3] = "abc"; is equivalent to char str[3] = {'a', 'b', 'c'};. In C such usage is forbidden. Personally, I think there should have been a defined prefix for a string literal to indicate that no terminating null byte is expected since there are cases where the length of the string will be known some other way and the null byte would at best be wasted space [if the string is part of a struct, there may be no room for the null byte].Mileage
M
9

Using pointer arithmetic. So

p[0], p[1], ...

or

*p, *(p + 1), ...

Here's the thing. In C, you have nice literals for primitive types like int and char, and even string literals. So, we can easily say things like

int length(char *s);
int len = length("Hello, World!");

In C99, the concept of compound literals was added to handle "array literal" and "struct literal". Therefore, we can now say things like:

int sum(int a[], int n);
int total = sum((int []){ 17, 42 }, 2);

This is using a compound literal to represent an "array literal".

Actually I want to know, Is this array will stored in memory or not as it doesn't have a name?

Yes, in memory.

I think your confusion stems from this. p has a name. (int []){3, 0, 3, 4, 1} does not. It just so happens that p's value is the address of (int []){3, 0, 3, 4, 1}. Of course (int []){3, 0, 3, 4, 1} is in memory; it will be in the data segment for your executable. You just don't have any name with which to refer to it.

Marrin answered 26/7, 2013 at 20:19 Comment(2)
What do you mean? It will be in the data segment for the executable. What else do you expect?Marrin
This answer states that the compound literal will be in the data segment. That is generally incorrect. It has automatic storage duration, so it is typically on the stack. (The implementation might store the initial values in the data segment so that each instance can be initialized easily, but the object itself will typically be on the stack, unless optimization enables it to be managed otherwise.)Woodbury
W
5

C 2011 (N1570) 6.5.2.5 5 says:

If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

So the compound literal you show has automatic storage duration. The C standard does not specify where such objects are in memory. It is up to the C implementation to organize memory. Typically, an object with automatic storage duration is created on the stack, but there are other methods by which an implementation might manage such objects.

In particular, suppose you record the value of p elsewhere and recursively call the routine containing this compound literal. When the routine initializes p again, there is a second instance of the compound literal. They are actually different objects, and the C standard requires that their addresses be different. So, if you print the two pointers, they will have different values. However, if the optimizer is able to determine that you do not do this, and that two pointers to different instances of the compound literal are never compared, and there is no other observable behavior (as defined by the C standard) that can distinguish them, then the C implementation is free to use one actual instance of the compound literal instead of creating a new one each time. In this case, the compiler could keep the compound literal in a data section instead of on the stack.

Here is code that demonstrates two instances of the same compound literal have different addresses:

#include <math.h>
#include <stdio.h>


void foo(int *q)
{
    int *p = (int []) { 2, 3 };
    if (!q)
        foo(p);
    else
        printf("p = %p, q = %p.\n", (void *) p, (void *) q);
}


int main(void)
{
    foo(0);
    return 0;
}

String literals are different. C 2011 (N1570) 6.4.5 6 says:

In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals.78) The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence.

So a string literal denotes an object with static storage duration. There is only one instance of it even if a routine containing it is called recursively.

Woodbury answered 26/7, 2013 at 22:43 Comment(7)
Additionally, in the case of string literals it is explicitly called out that they may not be distinct objects, whereas compound literals must at least appear to be.Juno
Hi Eric!.. I have a question. Suppose I declare: int *p = (int []){3, 0, 3, 4, 1}; and then I try to modify array p[2] = 34; Is it possible? I believe it will causes an segmentation fault because I am trying to change constant array.Heritable
@GrijeshChauhan: I do not see a prohibition in the C standard against modify a compound literal, as long as it does not have the const attribute.Woodbury
@Er icPostpischil So char* s = "hello"; and char* s = (char []){'h', 'e', 'l', 'l', 'o', '\0'}; are quit different ?Heritable
@GrijeshChauhan: Yes. For simplicity, you can write the latter as char *s = (char []){"hello"};.Woodbury
@EricPostpischil Is char str[7] = "grijesh"; is valid or Undefined behavior It doesn't give a warning/or error with gcc -Wall -pedantic Whereas if I defined like char name[7] = {'1', '2', '3', '4', '5', '6', '7', '\0'}; it causes warning `excess elements in array initializer.Heritable
@GrijeshChauhan: In C, char str[3] = "abc"; is equivalent to char str[3] = {'a', 'b', 'c'};. In C such usage is forbidden. Personally, I think there should have been a defined prefix for a string literal to indicate that no terminating null byte is expected since there are cases where the length of the string will be known some other way and the null byte would at best be wasted space [if the string is part of a struct, there may be no room for the null byte].Mileage
H
4

Conceptually as like you assigns string to a char pointer in C, similarly you are assigning an array of integers to p of type int*:
When you declares: int *p = (int []){3, 0, 3, 4, 1}; it can be assume to be store in memory like:

  p          23    27   31   35   36  37
+----+      +----+----+----+----+----+----+
| 23 |      | 3  | 0  |  3 | 4  | 1  | ?  |    
+----+      +----+----+----+----+----+----+  
              ▲    ▲    ▲    ▲    ▲     ▲
              |    |    |    |    |     // garbage value 
              p    p+1  p+2  p+3  p+4

So basically array allocates continues memory. And you can access elements of array as follows:

p[0] == 3
p[1] == 0
p[2] == 3
p[3] == 4
p[4] == 1

Note:

We do char* str = "hello"; While type of string literals in C is char[N] not char*. But thing is in most expressions char[N] can decays into char*.

Point:

When you declares an array, for example:

int p[] = {3, 0, 3, 4, 1};

then here p type is int[5] and &p pointer to an array = types is: int(*)[5]

Whereas in declaration:

int *p = (int []){3, 0, 3, 4, 1};

p pointer to first element and type of p is int* and &p type is int**. (this is similar to string assignment to char pointer).

In first case p[i] = 10; is legal for 0 <= i <= 4, But in second case you are writing on read only memory-illegal memory operation-segmentation fault.

point:

Not following is also valid declaration:

int *p = (int *){3, 0, 3, 4, 1};

Q Actually I want to know, Is this array will stored in memory or not as it doesn't have a name?

Of-course array's stored in memory but its just pointed by p (p is not name of array), no other name is for it. Suppose if you do:

int *p = (int []){3, 0, 3, 4, 1};
int i = 10;
p = &i;

Now you have lost the address of array, its exactly similar to:

char* s = "hello";
char c = 'A';
s = &c;

and now you loses the address of "hello".

Memory for constant comes from static segment, when you declares. Any int-array of char string literal get store there. When your declaration runs address assigned to pointer variables. But constant don't have any name-but value. In both cases array and string "hello" becomes the part of executable in data section. (you can disassemble to find there values).

Heritable answered 26/7, 2013 at 20:28 Comment(22)
I understand what you want to explain, but my question is: Is this array will stored in memory or not as it doesn't have a name?Congdon
@Congdon as I said its just as a string literal stores, its pointed by p but doesn't have any other name.Heritable
That's what I do not understand yet.Congdon
@Congdon what actually, I couldn't get you? comment meHeritable
As you said in your previous comment its just as a string literal stores, its pointed by p but doesn't have any other name, and my question is where this string is stored if it has no variable to store?Congdon
@Congdon memory for constant comes from static segment, when you declares. Any int-array of char string literal get store there. When you declaration runs address assigned to pointer variables. But constant don't have any name-but value.Heritable
@Congdon one more thing, when you declare this constant its become part of your executable.Heritable
@Congdon do you have disassemble ??Heritable
p is not a name for it.Marrin
@Jason didn't get you.. where is mistake.Heritable
What is executable? you mean to say executable file?Congdon
@Congdon yes! executable file get it disassembled using objdump. in data section you will find this value.Heritable
You said "No, of-course its stored in memory but its just pointed by p, no other name for it." This suggests p is a name for it; it's not though.Marrin
@Jason Thanks I correct my English in few minutes. I saw your profile NP- answer awesome, are you from TOC background?Heritable
@Jason I say it Theory of computation. I also answer automata question. I just saw your profile. Are you teacher?Heritable
Oh, I should have guessed that's what it meant. I forget what we called it in university, but it was my favorite class (automata was a separate class though, that I also loved). No, I am not a teacher.Marrin
@Jason I glad to talk to you :) I have bookmarked your page. Automata is my favorite subject too. (I also teach in part time). I catch you as I find difficulty :) :)Heritable
@haacks: I agree. But it is so beautiful. :(Marrin
@Congdon I passed with A+ :)Heritable
@Grijesh Chauhan: The pleasure was mine.Marrin
@Congdon yes you will pass with good grads I am full confident :) let me know if you have any problem In subject I will give you an answer. And if I find it difficult I will get an answer from @ Jason for you :)Heritable
@GrijeshChauhan +1 I seriously salute you for your tremendous contributions and efforts for explaining , If you are a teacher , then I am sure you are gonna help me too as you know I am still a student :)Autotomy
S
0

Two ways:

&((int[]){3,0,3,4,1})[3]

and

((int[]){3,0,3,4,1})+3

Be aware that if the literal is inside a function, pointers to it are invalidated when the enclosing block is exited.

Softener answered 26/7, 2013 at 20:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.