char *str = "String!";
char *str = (char []){"String!"};
Are these two initializations equivalent? If not, what is the difference between them?
CodePudding user response:
Are these two initializations equivalent?
No.
If not, what is the difference between them?
One of the major differences between the two is that you cannot modify the object that str
is pointing to in the first one, while in the second one, you can.
Trying to modify a string literal in C is undefined behavior. So in case of
char *str = "String!";
if you try to modify the object pointed to by str
, it'll invoke UB.
In case of
char *str = (char []){"String!"};
however, (char[]){"String!"}
is a compound literal, which has type array of char
s, and str
points to the first element of that array.
Since the compound literal is not read-only (doesn't have a const
qualifier), you can modify the object pointed to by str
.
From n1570 6.5.2.5 (Compound literals) p12 (emphasis mine):
12 EXAMPLE 5 The following three expressions have different meanings:
"/tmp/fileXXXXXX" (char []){"/tmp/fileXXXXXX"} (const char []){"/tmp/fileXXXXXX"}
The first always has static storage duration and has type array of char, but need not be modifiable; the last two have automatic storage duration when they occur within the body of a function, and the first of these two is modifiable.
CodePudding user response:
Are these two initializations equivalent?
No. There are at least three differences:
The C standard does not define the behavior upon attempting to modify the characters of
"String!"
, but it does define the behavior of attempting to modify the characters of(char []){"String!"}
.Each occurrence of
"String"
may be the same object, but each occurrence of(char []){"String!"}
is a distinct object.The array defined by
"String!"
has static lifetime (the memory for it is reserved for all of program execution), but the array defined by(char []){"String!"}
has static lifetime if it is outside of any function and automatic lifetime if it is inside a function.
Let’s examine these differences:
The C standard only requires the contents of string literals to be available for reading, not writing. It does not define the behavior if you attempt to modify them. This does not mean a program may not modify them, just that the standard does not say what happens if a program tries. In consequence, good engineers will not attempt to modify them in ordinary situations. (However, a C implementation may define the behavior, in which case a program for that implementation could make use of that.)
C implementations are allowed to coalesce string literals and parts of them, so defining two pointers initialized with the same string, as with
char *str0 = "String!";
andchar *str1 = "String!";
, may yield two pointers with the same value. This is due to a special rule in the C standard for string literals, so it does not apply for compound literals. When two pointers are initialized with the same compound literal source code, they must have different values. This means that multiple uses of compound literals must use more memory than multiple uses of strings, unless the compiler is able to optimize them away. Even a single use of a compound literal to initialize a pointer inside a function may cause more use of memory because the compiler typically must use space on the stack for the compound literal and separately have a copy of the string used to initialize it.Because a string literal has static lifetime, its address may be returned from a function and used by the caller. However, a compound literal may not be relied on after the function it is defined in returns. For example:
char *GetErrorMessageFromCode(int code)
{
char *ErrorMessages[] =
{
"invalid argument",
"out of range",
"resource unavailable",
…
}
return ErrorMessages[code];
/* The above is working code for returning pointers to (the first
characters of) static string literals. If compound literals were
used instead, the behavior would not be defined by the C standard
because the memory for the compound literals would not be reserved
after the function returns.
*/
}