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?

haccks
  • 104,019
  • 25
  • 176
  • 264
  • @user2553780; Though array has no name? – haccks Jul 26 '13 at 20:18
  • 4
    @haccks What? You **just** declared an `int *p`... –  Jul 26 '13 at 20:21
  • 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. – Barmar Jul 26 '13 at 20:21
  • @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? – haccks Jul 26 '13 at 20:29
  • @haccks It has block scope - it's an unnamed, temporary object which is alive as far as its enclosing block lasts. –  Jul 26 '13 at 20:32
  • @H2CO3; Yeah. It written in book that it is created "on the fly", but still in block scope a variable name is needed. – haccks Jul 26 '13 at 20:36
  • @haccks No, it's not *needed.* –  Jul 26 '13 at 20:37
  • @haccks Sorry, I don't understand that, please rephrase your sentence. –  Jul 26 '13 at 20:39
  • @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? – haccks Jul 26 '13 at 20:42
  • 3
    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? – Crowman Jul 26 '13 at 20:43
  • @PaulGriffiths; That's what I have not understand yet. – haccks Jul 26 '13 at 20:46
  • 2
    @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`. – Jens Gustedt Jul 26 '13 at 20:48
  • @JensGustedt Right, I meant "lifetime". –  Jul 26 '13 at 20:54
  • @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. – Crowman Jul 26 '13 at 20:56
  • Actually, come to think of it, it would *have* to do this, otherwise it wouldn't know how to create them at run-time. – Crowman Jul 26 '13 at 21:06
  • @PaulGriffiths; OK. You mean to say `(int []){...}` is an object with no name? – haccks Jul 26 '13 at 21:17
  • @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. – Crowman Jul 26 '13 at 21:21
  • @PaulGriffiths; I never knew that `(int []){...}` declares an object. I am surprised!. – haccks Jul 26 '13 at 21:34
  • @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. – Crowman Jul 26 '13 at 21:37
  • @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) :). – haccks Jul 26 '13 at 21:46
  • @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?" – Crowman Jul 26 '13 at 21:54
  • @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. – Eric Postpischil Jul 26 '13 at 23:14
  • @EricPostpischil: I stand corrected. Where in the executable do they go, then, if not the data segment? – Crowman Jul 27 '13 at 00:06
  • @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. – Eric Postpischil Jul 27 '13 at 00:22
  • @EricPostpischil: Interesting - thanks! – Crowman Jul 27 '13 at 00:32

4 Answers4

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.

jason
  • 236,483
  • 35
  • 423
  • 525
  • 1
    What do you mean? It will be in the data segment for the executable. What else do you expect? – jason Jul 26 '13 at 20:35
  • 5
    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.) – Eric Postpischil Jul 26 '13 at 23:15
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.

haccks
  • 104,019
  • 25
  • 176
  • 264
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • 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. – caf Jul 27 '13 at 02:25
  • 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. – Grijesh Chauhan Aug 05 '13 at 06:37
  • @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. – Eric Postpischil Aug 05 '13 at 12:56
  • @Er icPostpischil So `char* s = "hello";` and `char* s = (char []){'h', 'e', 'l', 'l', 'o', '\0'};` are quit different **?** – Grijesh Chauhan Aug 05 '13 at 13:33
  • 2
    @GrijeshChauhan: Yes. For simplicity, you can write the latter as `char *s = (char []){"hello"};`. – Eric Postpischil Aug 05 '13 at 13:48
  • @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. – Grijesh Chauhan Aug 22 '13 at 05:28
  • @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]. – supercat Jul 22 '15 at 21:57
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).

haccks
  • 104,019
  • 25
  • 176
  • 264
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
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.

Geoff Reedy
  • 34,891
  • 3
  • 56
  • 79