How does compound literals work in this code? - c

I have the following code in which I wrote two functions. Both are meant to produce the same output. But the function g() which has loop produces a different output from what I had expected as shown below.
#include <stdio.h>
struct S { int i; };
void f(void)
{
struct S *p;
int i = 0;
p = &((struct S) {i});
printf("%p\n", p);
i++;
p = &((struct S) {i});
printf("%p\n", p);
}
void g(void)
{
struct S *p;
for (int i = 0; i < 2; i++)
{
p = &((struct S) {i});
printf("%p\n", p);
}
}
int main()
{
printf("Calling function f()\n");
f();
printf("\nCalling function g()\n");
g();
}
Output:
Calling function f()
0023ff20
0023ff24
Calling function g()
0023ff24
0023ff24
How come the address of p is same in case of g() when it was called?

Well, I don't know exactly what are you trying to accomplish, but what happens here is:
the (struct S){i} notation in C99 will create new data structure on stack
this data structure is automaticaly destroyed at the end of the scope in which it was created
So in f() function you actually make TWO distinct structures in the scope of the whole function (even if you assign their addresses to the same pointer) - hence two different addresses.
void f(void)
{
struct S *p;
int i = 0;
p = &((struct S) {i}); // <- first data structure, let's call it A
printf("%p\n", p); // <- address of the structure A printed
i++;
p = &((struct S) {i}); // <- second data structure, let's call it B
printf("%p\n", p); // <- address of the structure B printed
} // <- both A and B destroyed
But in g() function the p is created and destroyed in the inner block of the for block, and so it happens that p is allocated over and over again in the same position on stack, giving always the same address.
void g(void)
{
struct S *p;
for (int i = 0; i < 2; i++)
{
p = &((struct S) {i}); // <- data structure A created
printf("%p\n", p); // <- data structure A's address printed
} // <- data structure A destroyed
}

You should check assembly code to be sure but I guess that, since p is assigned locally in a loop scope with the address of an automatic allocated variable (which is allocated on the stack), it just reuses the same space on the stack.
In f() it doesn't do it because both structs coexist in the same scope while in g() compiler is sure that at the end of the first iteration you won't be able to use &((struct S) {0}).
Just tried for curiosity with -O2 on gcc4.2 to see if anything changes:
Calling function f()
0x7fff5fbff388
0x7fff5fbff380
Calling function g()
0x7fff5fbff390
0x7fff5fbff390

Related

Why is the pointer's value still 20?

void func(char *p)
{
int q = 13;
p = &q;
printf("%d\n", *p);
}
void main(void)
{
int var = 20;
int *p = &var;
printf("%d\n", *p);
func(p);
printf("%d\n", *p);
}
How come at the function exit the pointer is still 20?
I was hopping when the func() ends, the pointer is modified in it, in the last printf(), the *p value would be pointing some random stuff from the stack.
What you had is this
void func(char *p)
{
int q = 13;
p = &q;
}
This means "make p point to q" and changes value of p, which is just a variable inside the function. No variable value changes are reflected outside the function.
If you were to write this
void func(char *p)
{
int q = 13;
*p = q;
}
This would mean "make the variable to which p points to change its value to 13" and that would be seen outside, meaning the variable var in main would change its value (depends on endianness what it would be since it's int and not char as the pointer claims it to be).
If you want to change the pointer's value in main you need a double pointer:
void func(char **p)
{
int q = 13;
*p = &q;
printf("%d\n", *p);
}
This would mean "make the pointer to which p points to point to a local variable q" and in this case you would have a dangling pointer as you expected in main.
No, p itself is passed be value. Any change made to p inside func() will not be reflected back to main().
For sake of completeness, any changes made to the value pointed to by p (i.e., *p) would have been reflected back in main().

Access struct member from pointer

I've some problems of segmentation fault with this code:
void init(int max, pile * p) {
p = (pile *)malloc(sizeof(pile));
if(p){
p->nbElemPresent = 0;
p->maxElem = max;
p->tete = (data *)malloc(max * sizeof(data));
}
}
short int vide(pile * p) {
if(p->maxElem == 0) {return 1;}
return 0;
}
my function vide return me segfault.. I don't know how to access to struct member from the p pointer.
The main program:
pile * p;
init(5, p);
printf("%d", vide(p));
ty.
as already said, p is a new variable in your init function. other than the other answers suggested, i'd rather suggest not taking p as an argument at all, but instead returning it:
pile* init(int max) {
pile *p = (pile *)malloc(sizeof(pile));
...
return p;
}
and in your main function:
pile * p = init(5);
printf("%d", vide(p));
C takes parameters by value, that means that pointer p is copied when you pass it to init().
p in the function is a completely new variable and if its value is changed that doesn't change the value of p passed to the function.
You should pass its address:
init(5, &p);
void init(int max, pile** p) {
*p = malloc(sizeof(pile));
if(*p){
(*p)->nbElemPresent = 0;
....
}
}
Note the unusual parenthesis (*p)->nbElemPresent, this is done because -> operator has a higher precedence, yet we want to dereference the p first.
As said by barak manos, your problem lies in init. C pass parameters by value so let's imagine :
you set a pointer to pile to NULL (pile *p = NULL;)
you pass it to init (init(p);)
in init you alloc a pile and affect is to the local copy of p
on return from init, p is still NULL and you have a memory leak since you have no longer any pointer to the allocated pile
That's the reason why you should write :
void init(int max, pile ** p) {
pile *lp = *p = (pile *)malloc(sizeof(pile));
if(*p){
lp->nbElemPresent = 0;
lp->maxElem = max;
lp->tete = (data *)malloc(max * sizeof(data));
}
}
Now you use :
pile *p;
init(&p);
and on return p points to the allocated pile.

C free(): invalid pointer allocated in other function

I'm new in StackOverflow. I'm learning C pointer now.
This is my code:
#include <stdio.h>
#include <stdlib.h>
int alloc(int* p){
p = (int*) malloc (sizeof(int));
if(!p){
puts("fail\n");
return 0;
}
*p = 4;
printf("%d\n",*p);
return 1;
}
int main(){
int* pointer;
if(!alloc(pointer)){
return -1;
}else{
printf("%d\n",*pointer);
}
free(pointer);
return 0;
}
I compile with: gcc -o main main.c
error: free(): invalid pointer: 0xb77ac000 ***
what's wrong with my code?
Arguments in C are always passed by value. So, when you call alloc(pointer), you just pass in whatever garbage value pointer contains. Inside the function, the assignment p = (int*)... only modifies the local variable/argument p. Instead, you need to pass the address of pointer into alloc, like so:
int alloc(int **p) {
*p = malloc(sizeof(int)); // side note - notice the lack of a cast
...
**p = 4; // <---- notice the double indirection here
printf("%d\n", **p); // <---- same here
return 1;
}
In main, you would call alloc like this:
if (!(alloc(&pointer))) {
....
Then, your code will work.
Everything in C is pass-by-value. This means that functions always operate on their own local copy of what you pass in to the function. Usually pointers are a good way to mimic a pass-by-reference scheme because a pointer and a copy of that pointer both contain the same memory address. In other words, a pointer and its copy both point to the same space.
In your code the issue is that the function alloc gets its own local copy of the pointer you're passing in. So when you do p = (int*) malloc (sizeof(int)); you're changing the value of p to be a new memory address, but the value of pointer in main remains unchanged.
You can get around this by passing a pointer-to-a-pointer, or by returning the new value of p.
You have two major problems in your code.
First, the alloc function creates a pointer via malloc, but never frees it, nor does it return the pointer to the calling function. This guarantees the memory the pointer addresses can never be freed up via the free command, and you now have memory leaks.
Second, the variable, int* pointer in main, is not being modified as you would think. In C, function arguments are "passed by value". You have two ways to address this problem:
Pass a pointer to the variable you want to modify (in your case, a pointer to a pointer to an int)
Have the function return the pointer to the function that called it.
Here are two implementations of my recommendations:
Approach 1
#include <stdio.h>
#include <stdlib.h>
int alloc(int** p);
int alloc(int** p) {
if (!p) {
printf("Invalid argument\n");
return (-1);
}
if ((*p = (int*)malloc(sizeof(int))) == NULL) {
printf("Memory allocation error\n");
return (-1);
}
**p = 123;
printf("p:%p - *p:%p - **p:%d\n", p, *p, **p);
return 0;
}
int main(){
int* pointer;
if(alloc(&pointer) != 0){
printf("Error calling function\n");
}else{
printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
}
free(pointer);
return 0;
}
Sample Run for Approach 1
p:0xbfbea07c - *p:0x8656008 - **p:123
&pointer:0xbfbea07cointer - pointer:0x8656008ointer - *pointer:123
Approach 2
#include <stdio.h>
#include <stdlib.h>
int* alloc(void) {
int* p;
if ((p = (int*)malloc(sizeof(int))) == NULL) {
printf("Memory allocation error\n");
return (NULL);
}
*p = 123;
printf("p:%p - *p:%d\n", p, *p);
return p;
}
int main(){
int* pointer = alloc();
if(pointer == NULL) {
printf("Error calling function\n");
}else{
printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
}
free(pointer);
pointer = NULL;
return 0;
}
Sample Run for Approach 2
p:0x858e008 - *p:123
&pointer:0xbf9bb1ac- pointer:0x858e008- *pointer:123
You are passing the pointer by value into your alloc function. Although that function takes a pointer to an int, that pointer itself cannot be modified by the function. If you make alloc accept **p, set *p = ..., and pass in &pointer from main, it should work.
#include <stdio.h>
#include <stdlib.h>
int alloc(int** p){
*p = (int*) malloc (sizeof(int));
if(!*p){
puts("fail\n");
return 0;
}
**p = 4;
printf("%d\n",**p);
return 1;
}
int main() {
int* pointer;
if(!alloc(&pointer)){
return -1;
} else {
printf("%d\n",*pointer);
}
free(pointer);
return 0;
}
If you want a function to write to a non-array parameter of type T, you must pass a pointer to that parameter.
void func( T *ptr )
{
*ptr = new_value;
}
void foo ( void )
{
T var;
func( &var ); // writes new value to var
}
If T is a pointer type Q *, it would look like
void func( Q **ptr )
{
*ptr = new_pointer_value;
}
void foo ( void )
{
Q *var;
func( &var ); // writes new pointer value to var
}
If Q is a pointer type R *, you would get
void func( R ***ptr )
{
*ptr = new_pointer_to_pointer_value;
}
void foo ( void )
{
R **var;
func( &var ); // writes new pointer to pointer value to var
}
The pattern is the same in all three cases; you're passing the address of the variable var, so the formal parameter ptr has to have one more level of indirection than the actual parameter var.
One sylistic nit: instead of writing
p = (int *) malloc( sizeof (int) );
use
p = malloc( sizeof *p );
instead.
In C (as of the 1989 standard), you don't need to cast the result of malloc; void pointers can be assigned to other pointer types and vice versa without needing a cast (this is not true in C++, but if you're writing C++, you should be using the new operator instead of malloc anyway). Also, under the 1989 version of the language, using the cast would mask a bug if you forgot to include stdlib.h or otherwise didn't have a declaration for malloc in scope. That hasn't been a problem since the 1999 version, though, so now it's more a matter of readability than anything else.
The type of the expression *p is int, so the result of sizeof *p is the same as the result of sizeof (int). This way, if you ever change the type of p, you don't have to modify the malloc call.
To allocate an array of values, you'd use something like
T *p = malloc( sizeof *p * NUM_ELEMENTS );
or, if you want everything to be zeroed out initially, use
T *p = calloc( sizeof *p, NUM_ELEMENTS );

Understanding Stack Frames in C

I am trying to understand the stack frame in C, so I wrote a simple C code to analyze the stack frame.
First of all the fun1() returns an address of a local variable which is initialized to 10 to ptr which leads to a warning but that's ok... If I print the value of *ptr now it prints 10, even that's fine...
Next fun2() returns an address of a local variable which is not even initialized and if I try to print the value of *ptr now it prints 10 no matter if i'm returning an address of a or b...
To understand what is actually happening here I made use of gdb.
Using gdb, I started step by step debugging and when I reached the line "return &a" in fun2(), I tried to print address of b, print &b but it printed
Can't take address of "b" which isn't an lvalue.
I don't understand when I try to print the address of a, print &a it prints absolutely fine then why not address of b.
* Why isn't b an lvalue when a is?
# include <stdio.h>
int * fun1() {
int a = 10;
return &a;
}
int * fun2()
{
int a;
int b;
return &a; // return &b;
}
int main ()
{
int *ptr;
ptr = fun1();
ptr = fun2();
printf ("*ptr = %d, fun2() called...\n", *ptr);
return 0;
}
The compiler is optimizing away some code in fun2.
If you return &a, it is optimizing away int b;. If you return &b, it is optimizing away int a;. If you add some dummy computation, you will see that the addresses of returned values will be different.
int * fun2()
{
int a;
int b;
int* p = &a;
p = &b;
return p;
}
Change main to print the returned values of fun1 and fun2.
int main ()
{
int *ptr;
ptr = fun1();
printf ("ptr = %p, fun1() called...\n", ptr);
ptr = fun2();
printf ("ptr = %p, fun2() called...\n", ptr);
printf ("*ptr = %d, fun2() called...\n", *ptr);
return 0;
}
When I run this code, I get the following sample output:
ptr = 0x7ffff98c70ec, fun1() called...
ptr = 0x7ffff98c70e4, fun2() called...
*ptr = 32749, fun2() called...
It compiles for me just fine when returning the address to b. But you aren't supposed to return the address of a local variable. Check out this link.

Returning a pointer from a function

This is in reference to this question: Why is a pointer to pointer needed to allocate memory in this function?
The answer to the question explained why this didn't work:
void three(int * p)
{
p = (int *) malloc(sizeof(int));
*p = 3;
}
void main()
{
int *p = 0;
three(p);
printf("%d", *p);
}
... but this works:
void three(int ** p)
{
*p = (int *) malloc(sizeof(int));
**p = 3;
}
void main()
{
int *p = 0;
three(&p);
printf("%d", *p);
}
This also works, by returning a pointer from the function. Why is that?
int* three(int * p)
{
p = (int *) malloc(sizeof(int));
*p = 3;
return p;
}
void main()
{
int *p = 0;
p = three(p);
printf("%d", *p);
}
int* three(int * p)
{
p = (int *) malloc(sizeof(int));
*p=3;
return p;
}
Because here you're returning a copy of the pointer p and this pointer now points to valid memory, which contains the value 3.
You originally passed in a copy of your p as an argument, so you're not changing the one you passed in, but a copy. Then you return that copy, and assign it.
From the comment, which is a very valid point, this will also work just as well:
int* three()
{
//no need to pass anything in. Just return it.
int * p = (int *) malloc(sizeof(int));
*p=3;
return p;
}
They're completely different (and if you truly understand why the first works, you'd see there's no connection).
By returning, you're not attempting to modify the already existing pointer from inside the function. You're just returning a new pointer, and assigning its value outside.
Look at it as a question of scope.
In main() you have a pointer p.
int *p = 0;
p in main is set to NULL. When you make a call to the three function passing it p:
three(p);
You are passing a pointer to NULL. What happens to it is outside the scope of main(). main() does not know, nor does it care what happens. main() only cares about its copy of p, which at this point is still set to NULL.
Unless I reassign p within the scope of main() (including handing off the address of p), p is still just a pointer pointing to NULL.
If I give you this code:
void main()
{
int *p = 0;
funcX(p);
printf("%d",*p);
}
You can tell me definitively what is going to happen (Segmentation fault) without ever knowing what funcX() does because we're passing a copy of the pointer to this function, but a copy doesn't affect the original.
But if I give you this code:
void main()
{
int *p = 0;
funcX(&p);
printf("%d",*p);
}
You can't tell me what will happen unless you know what funcX() is doing.
That make sense?

Resources