I am trying to get deep acknowledge of pointers. while I am running this example it doesn't output any thing due to segmentation fault. But when I am trying to run the code line by line from GDB it works normally Look at screen shot.
#include <stdio.h>
struct s{
int a;
struct s* next;
};
struct s foo() {
struct s m ;
struct s f[10];
m.a = 55;
m.next =&(f[0]);
int i = 0;
while(i < 9) {
f[i].a = 28 i;
f[i].next = &(f[i 1]);
i ;
}
return f[0];
}
int main()
{
struct s f = (foo());
printf("%d ",f.a);
printf("%d ",f.next->a);
printf("%d ",f.next->next->a);
return 0;
}
if you change the main function to be like this :
int main(){
struct s f = (foo()); int a = f.a;
int b - f.next->a;
int c = f.next->next->a;
int d = f.next->next->next->a;
int g = f.next->next->next->next->a;
printf("%d %d %d %d %d\n", a, b , c ,d, g);
}
it will work fine. this screen shot is n't working when I am trying to call printf directly .
this is working when I am trying to store in variables first and then call printf on the variables ]
CodePudding user response:
In C, variables that are defined inside a function are either static or automatic (auto). The default is automatic. The lifetime of automatic variables ends when the function returns and its return value has been copied to another variable or used in an expression.
struct s foo() {
struct s f[10];
int i = 0;
while(i < 9) {
f[i].a = 28 i;
f[i].next = &(f[i 1]);
i ;
}
return f[0];
}
int main()
{
struct s f = (foo())
So after foo
's return value has been stored in main
's f
, foo
's f
array is no longer alive, and trying to access any part of it is an error.
So why does the following work?
int b = f.next->a;
int c = f.next->next->a;
int d = f.next->next->next->a;
int g = f.next->next->next->next->a;
printf("%d %d %d %d %d\n", a, b , c ,d, g);
The reason is that your implementation of C stores automatic variables in a stack, and doesn't shrink the stack after a function finishes. Instead, the variables remain undisturbed until another function is called. That function will reuse all or part of the stack space, overwriting variables without regard to their old types. A pointer may be overwritten by an integer, or a few character of a string, or something else.
So, although it's undefined behavior and you should never rely on this working, it does in this particular case.
Similarly, in your GDB session, since you've stopped your program after foo
returns but before printf has been called, GDB can safely access f.next->next->a
, etc., but it's still undefined behavior.
Your second version does call functions, and that's when you're going to run in trouble.
printf("%d ",f.a);
printf("%d ",f.next->a);
printf("%d ",f.next->next->a);
The first line, printf("%d ",f.a)
, will work fine. main
's f
is valid. But the call to printf is going to overwrite the stack previously used by foo
, including all or part of what used to be foo
's f
array.
Note that you won't see this output yet, because printf won't print out anything until you've asked it to print the end-of-line character.
The next line, printf("%d ",f.next->a);
, is going to print a seemingly random integer, because foo
's f[1].a
has been overwritten with whatever local variables printf uses. And, again, you won't see any output yet because of buffering.
The next line, printf("%d ",f.next->next->a)
, is where things come crashing down. foo
's f[1].next
is almost certainly not going to be a valid pointer, so you get a segmentation fault.
How can you make this work correctly? If you want foo
's f
array to stay alive for the entire duration of the program, just prefix the declaration with the keyword static
. That means there will be one copy of the f
array, no matter how many times you call foo
. If you want each call to foo
to allocate a new f
array, you can use the malloc function. Space allocated by malloc will remain alive until either you call free or the program exits.