compound literals and pointers - c

It's safe initialize pointers using compound literals in such way and it's possible at all?:
#include <stdio.h>
#include <string.h>
void numbers(int **p)
{
*p = (int []){1, 2, 3};
}
void chars(char **p)
{
*p = (char[]){'a','b','c'};
}
int main()
{
int *n;
char *ch;
numbers(&n);
chars(&ch);
printf("%d %c %c\n", n[0], ch[0], ch[1]);
}
output:
1 a b
I don't understand exactly how it's works, does it's not the same as init pointer with local variable?
also if i try to print:
printf("%s\n", ch);
It's print nothing.

A compound literal declared inside a function has automatic storage duration associated with its enclosing block (C 2018 6.5.2.5 5), which means its lifetime ends when execution of the block ends.
Inside numbers, *p = (int []){1, 2, 3}; assigns the address of the compound literal to *p. When numbers returns, the compound literal ceases to exist, and the pointer is invalid. After this, the behavior of a program that uses the pointer is undefined. The program might be able to print values because the data is still in memory, or the program might print different values because memory has changed, or the program might trap because it tried to access inaccessible memory, or the entire behavior of the program may change in drastic ways because compiler optimization changed the undefined behavior into something else completely.

It depends on where the compound literal is placed.
C17 6.5.2.5 §5
The value of the compound literal is that of an unnamed object initialized by the
initializer list. 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.
That is, if the compound literal is at local scope, it works exactly like a local variable/array and it is not safe to return a pointer to it from a function.
If it is however declared at file scope, it works like any other variable with static storage duration, and you can safely return a pointer to it. However, doing so is probably an indication of questionable design. Plus you'll get the usual thread-safety issues in a multi-threaded application.

Related

Are these two initializations equivalent?

char *str = "String!";
char *str = (char []){"String!"};
Are these two initializations equivalent? If not, what is the difference between them?
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 snippet of code, 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 chars, 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.
Another difference you should note is that the string literal "String!" in the first one has static storage duration, while the compound literal (char []){"String!"} in the second one has static storage duration only if it occurs outside the body of a function; otherwise, it has automatic storage duration associated with the enclosing block.
From n1570 6.5.2.5 (Compound literals) p12:
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.
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!"; and char *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.
*/
}

Does array reinitializing cause memmory leaks?

I found an answer on SO that suggests the following solution to reinitialize array in c.
int *foo = (int[]){1,2,3,4,5};
I am not really sure what exactly such syntax will do and I have few questions:
Will it cause memory leaks if my array was previously created?
double *my_array = (double[]){1.1, 2.2, 3.3, 4.4, 5.5};
...
my_array = (double[]){-1.1, -2.2, -3.3}; // Do i need to call free(my_array) first?
Is it allowed to use such an approach in function calls?
void foo(int *arr)
{
arr = (int[]){-2, -7, 1, 255};
}
int main()
{
int *my_array = (int[]){1, 2, 3};
foo(my_array);
if (my_array[2] != 1)
return -1;
}
Generalizing:
Does such syntax just allocates new memory in heap with predefined values and returns pointer?
Does it clear automatically everything that was in the previous pointer?
First, the declaration int *foo makes foo a pointer, not an array.
(int[]){1,2,3,4,5} is a compound literal. It is rare there is a good reason to set pointers to compound literals in this way.
Compound literals are managed automatically, so you do not need to free them. If a compound literal appears outside any function, it has static storage duration; it exists for the entire execution of the program. Otherwise, it has automatic storage duration associated with the block it is in, and its memory reservation will end when execution of that block ends. You should not set a pointer to point to such a compound literal if the pointer is used after execution of the block ends.
In this code:
void foo(int *arr)
{
arr = (int[]){-2, -7, 1, 255};
}
arr is set to point to the compound literal, but arr is only a function parameter. It effectively ceases to exist when the function returns.
In this code:
int *my_array = (int[]){1, 2, 3};
foo(my_array);
if (my_array[2] != 1)
return -1;
When foo is called, its parameter arr is set to the value of my_array. When arr is changed inside foo, it does not affect my_array. my_array will still be pointing to the start of (int[]){1, 2, 3}. This would be true regardless of whether arr is set to point to a compound literal, allocated memory, or anything else: Changing a parameter inside a function does not change the thing that was passed as an argument.
To get the pointer out of the function, you could either return it or you could pass a pointer to a pointer so that the function had the address of the pointer:
void foo(int **arr)
{
*arr = (int []) { -2, -7, 1, 255 };
}
int main(void)
{
int *my_array = (int []) { 1, 2, 3 };
foo(&my_array);
…
}
However, then foo would be putting the address of its compound literal into a pointer that is used after the function ends. That is a situation where you ought to call malloc to reserve memory and then copy the data into the allocated memory. Later, after the program is done with that data, it would call free to release the memory.
This is known as compound literals and code such as int *foo = (int[]){1,2,3,4,5}; can be regarded as 100% equivalent to this:
int arr[] = {1,2,3,4,5};
int *foo = arr;
That is, a compound literal has the same scope and storage duration as a named array declared at the same scope.
Will it cause memory leaks if my array was previously created?
No. In case a compound literal was declared at local scope, it will be valid inside the { } where it was declared (so-called automatic storage duration). After that, it gets automatically cleaned up just like any other local variable. Since it isn't using allocated storage, there are no leaks.
Is it allowed to use such an approach in function calls?
No. Just like any local variable, you cannot return a pointer to it from inside a function.
Additionally, your example has a bug, it just sets the local copy of the pointer parameter arr. The pointer in the caller was passed by value and is unaffected by the arr = (int[]){-2, -7, 1, 255}; line.
Does such syntax just allocates new memory in heap with predefined values and returns pointer?
The C standard doesn't specify where variables are allocated. But when looking at all well-known compiler implementations out there, then the following will likely hold:
Compilers/linkers do not allocate anything on the heap unless explicitly told to through malloc.
Local compound literals are likely allocated on the stack and/or in registers.
File scope compound literals are likely allocated in the .data segment.
Does it clear automatically everything that was in the previous pointer?
Data isn't stored "inside pointers", but yes the pointed-at memory will get "cleared" (become invalid to use & available for other parts of the program) when it goes out of scope. No matter if there are pointers pointing at it or not.

Initializing a pointer to compound literals in C

Here is one not-so-common way of initializing the pointer:
int *p = (int[10]){[1]=1};
Here, pointer point to compound literals.
#include <stdio.h>
int main(void)
{
int *p = (int[10]){[1]=1};
printf("%d\n", p[1]);
}
Output:
1
This program is compiled and run fine in G++ compiler.
So,
Is it the correct way to initializing a pointer to compound literals? or
Is it undefined behaviour initialize pointer to compound literals?
Yes, it is valid to have a pointer to compound literals. Standard allows this.
n1570-§6.5.2.5 (p8):
EXAMPLE 1 The file scope definition
int *p = (int []){2, 4};
initializes p to point to the first element of an array of two ints, the first having the value two and the second, four. The expressions in this compound literal are required to be constant. The unnamed object
has static storage duration.

Why can't we assign int* x=12 or int* x= "12" when we can assign char* x= "hello"?

What is the correct way to use int* x?
Mention any related link if possible as I was unable to find one.
Because the literal "hello" evaluates to a pointer to constant memory initialised with the string "hello" (and a nul terminator), i.e. the value you get is of char* type.
If you want a pointer to number 12 then you'll need to store the value 12 somewhere, e.g. in another int, and then take a pointer to that:
int x_value = 12;
int* x = &x_value;
However in this case you're putting the 12 on the stack, and so that pointer will become invalid once you leave this function.
You can at a pinch abuse that mechanism to make yourself a pointer to 12; depending on endianness that would probably be
int* x = (int*)("\x0c\x00\x00");
Note that this is making assumptions about your host's endianness and size of int, and that you would not be able to modify that 12 either (but you can change x to point to something else), so this is a bad idea in general.
Because the compiler creates a static (constant) string "hello" and lets x point to that, where it doesn't create a static (constant) int.
A string literal creates an array object. This object has static storage duration (meaning it exists for the entire execution of the program), and is initialized with the characters in the string literal.
The value of a string literal is the value of the array. In most contexts, there is an implicit conversion from char[N] to char*, so you get a pointer to the initial (0th) element of the array. So this:
char *s = "hello";
initializes s to point to the initial 'h' in the implicitly created array object. A pointer can only point to an object; it does not point to a value. (Incidentally, that really should be const char *s, so you don't accidentally attempt to modify the string.)
String literals are a special case. An integer literal does not create an object; it merely yields a value. This:
int *ptr = 42; // INVALID
is invalid, because there is no implicit conversion of 42 from int* to int. This:
int *ptr = &42; // INVALID
is also invalid, because the & (address-of) operator can only be applied to an object (an "lvalue"), and there is no object for it to apply to.
There are several ways around this; which one you should use depends on what you're trying to do. You can allocate an object:
int *ptr = malloc(sizeof *ptr); // allocation an int object
if (ptr == NULL) { /* handle the error */ }
but a heap allocation can always fail, and you need to deallocate it when you're finished with it to avoid a memory leak. You can just declare an object:
int obj = 42;
int *ptr = &obj;
You just have to be careful with the object's lifetime. If obj is a local variable, you can end up with a dangling pointer. Or, in C99 and later, you can use a compound literal:
int *ptr = &(int){42};
(int){42} is a compound literal, which is similar in some ways to a string literal. In particular, it does create an object, and you can take that object's address.
But unlike with string literals, the lifetime of the (anonymous) object created by a compound literal depends on the context in which it appears. If it's inside a function definition, the lifetime is automatic, meaning that it ceases to exist when you leave the block containing it -- just like an ordinary local variable.
That answers the question in your title. The body of your question:
What is the correct way to use int* x?
is much more general, and it's not a question we can answer here. There are a multitude of ways to use pointers correctly -- and even more ways to use them incorrectly. Get a good book or tutorial on C and read the section that discusses pointers. Unfortunately there are also a lot of bad books and tutorials. Question 18.10 of the comp.lang.c FAQ is a good starting point. (Bad tutorials can often be identified by the casual use of void main(), and by the false assertion that arrays are really pointers.)
Q1. Why can't we assign int *x=12? You can provided that 12 is a valid memory address which holds an int. But with a modern OS specifying a hard memory address is completely wrong (perhaps except embedded code). The usage is typically like this
int y = 42; // simple var
int *x = &y; // address-of: x is pointer to y
*x = 12; // write a new value to y
This looks the same as what you asked, but it is not, because your original declaration assigns the value 12 to x the pointer itself, not to *x its target.
Q2. Why can't we assign int *x = "12"? Because you are trying to assign an incompatible type - a char pointer to int pointer. "12" is a string literal which is accessed via a pointer.
Q3. But we can assign char* x= "hello"
Putting Q1 and Q2 together, "hello" generates a pointer which is assigned to the correct type char*.
Here is how it is done properly:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *x;
x = malloc(sizeof(int));
*x = 8;
printf("%d \n", *x);
}

Stack memory fundamentals

Consider this code:
char* foo(int myNum) {
char* StrArray[5] = {"TEST","ABC","XYZ","AA","BB"};
return StrArray[4];
}
When I return StrArray[4] to the caller, is this supposed to work?
Since the array is defined on the stack, when the caller gets the pointer, that part of memory has gone out of scope. Or will this code work?
This code will work. You are returning the value of the pointer in StrArray[4], which points to a constant string "BB". Constant strings have a lifetime equal to that of your entire program.
The important thing is the lifetime of what the pointer points to, not where the pointer is stored. For example, the following similar code would not work:
char* foo(int myNum) {
char bb[3] = "BB";
char* StrArray[5] = {"TEST","ABC","XYZ","AA",bb};
return StrArray[4];
}
This is because the bb array is a temporary value on the stack of the foo() function, and disappears when you return.
Beware: you're lying to the compiler.
Each element of StrArray points to a read-only char *;
You're telling the compiler the return value of your function is a modifiable char *.
Lie to the compiler and it will get its revenge sooner or later.
In C, the way to declare a pointer to read-only data is to qualify it with const.
I'd write your code as:
const char* foo(int myNum) {
const char* StrArray[5] = {"TEST","ABC","XYZ","AA","BB"};
return StrArray[4];
}
The code will work. The point you are returning (StrArray[4]) points to a string literal "BB". String literals in C are anonymous array objects with static storage duration, which means that they live as long as your program lives (i.e forever). It doesn't matter where you create that sting literal. Even if it is introduced inside a function, it still has static storage duration.
Just remember, that string literals are not modifiable, so it is better to use const char* pointers with string literals.
C uses arrays with indicies beginning at 0. So the first element is StrArray[0]
Thus StrArray[5] was not declared in your code.
C will allow you to write code to return StrArray[5] but wht happens is undefined and will differ on OS and compiler but often will crash the program.
Only the array of pointers is on the stack, not the string-literal-constants.

Resources