2
#include <stdio.h>
#include <stdlib.h>

int* test(int); // the prototype

int main()
{
    int var = -20;
    int *ptr = NULL;
    ptr = test(var);
    printf("This is what we got back in main(): %d \n", *ptr);
    return 0;
}

int* test(int k)
{
    int y = abs(k);
    int *ptr1 = &y;
    printf("The value of y in test() directly is %d \n", y);
    printf("The value of y in test() indirectly is %d \n", *ptr1);
    return ptr1;
}
The output is:
The value of y in test() directly is 20
The value of y in test() indirectly is 20
This is what we got back in main(): 20

Short Summary: The above mentioned code has a user defined function which returns a pointer that holds the address of a variable(i.e.,y). This variable is assigned an absolute value of the integer passed to the function (i.e.,x)

My book " Computer Programming for Beginners" by A.J.Gonzalez states the following: The variable y will cease to exist after the function exits, so the address returned to the calling function will turn out too be meaningless. However the value held in its address will persist and can be retrieved through the pointer.

My question is : How did we come to this conclusion that a value held in the address will persist and can be retrieved through the pointer from the following printf statements:

1st statement: giving value directly using y.

2nd statement: using a pointer to give the value.

3rd statement: getting the value from main.

All that is all right but then from there how does one make the conclusion that the direct use variable loses its value but the indirectly used variable (i.e., the pointer ) retains its value ? I tried looking at past questions but could not find anything relevant.

Will be grateful for your help. Thank You.

ShellCode
  • 1,072
  • 8
  • 17
  • 1
    Yeah, that sounds like bad advice. The variable `int y` exists in temporary storage only, most likely on the stack, and that memory could easily be used for another purpose. As soon as it's written to, there will no longer be a pattern of bits that can be interpreted as an integer of value 20. – Tim Randall May 25 '21 at 13:02
  • 4
    I would ditch that book; it’s giving you bad/dangerous advice. While the pointer might work one time, it might not - this sort of thing is called undefined behaviour and you don’t want UB in any code you write or have to maintain. – DisappointedByUnaccountableMod May 25 '21 at 13:06
  • Compile your code with `gcc -O3` and see what happens (illustrates the undefined behavior perfectly : because of optimization, values are not pushed on the stack anymore but are held in registers, causing a segfault on pointer dereference) – ShellCode May 25 '21 at 13:14
  • Maybe it's _really_ time to switch to some other book. I wouldn't dare to read a book that misguides me. – Kitswas May 25 '21 at 13:20

4 Answers4

4

This program is illustrating an effect of undefined behavior.

After test returns, the pointer value it returns points to a variable that no longer exists. Formally, this is undefined behavior which means that the C standard makes no guarantees what will happen when you attempt to use this pointer. In practice, the memory that was used by y was not yet overwritten by some other value so dereferencing the pointer will often yield the value that was stored there.

But again, there's no guarantee that will actually happen. As an example, if we change the main function as follows:

int main()
{
    int var = -20;
    int *ptr = NULL;
    ptr = test(var);
    printf("This is what we got back in main(): %d \n", *ptr);
    printf("%d %d %d %f\n", 1, 2, 3, 4.0);
    printf("This is what we got back in main(): %d \n", *ptr);
    return 0;
}

My machine outputs:

The value of y in test() directly is 20 
The value of y in test() indirectly is 20 
This is what we got back in main(): 20 
1 2 3 4.000000
This is what we got back in main(): 0 

Which demonstrates that the memory previously used by y has some other value.

The moral of the story: don't attempt to use a pointer to a variable which no longer exists.

dbush
  • 205,898
  • 23
  • 218
  • 273
1

The book's reasoning is somewhat correct, however it assumes an architecture that pushes parameters onto the stack, such as Intel.

What happens is that the location of y is not re-used until after its value has been retrieved through ptr of main to be pushed onto the stack for the call of printf.

However, an interrupt could re-use the location and so in general this is undefined behavior.

Note: this is used by compilers when returning a struct as function return. The compiler copies the struct variable of the called function to the struct of the caller, before anything else takes place, so the memory has not yet been re-used.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
1

My question is : How did we come to this conclusion that a value held in the address will persist and can be retrieved through the pointer

The function returns an address where a variable used to be stored, very likely somewhere on the stack. But since that address is no longer valid, what the pointer now contains is indeterminate. Meaning there's no guarantees of anything any longer. And you can't de-reference that pointer any longer, this code here is bugged:

printf("This is what we got back in main(): %d \n", *ptr);

It could print anything or cause a program crash, it is so-called "undefined behavior" (as per C standard C17 6.2.4/2), see What is undefined behavior and how does it work?.

What conclusions can we draw from this? Only one, returning a pointer to a local scope variable from a function is bad and a bug.

Other than that, there's nothing else to reason about, no deterministic behavior, no interesting phenomenon to study or learn anything meaningful from. See Can a local variable's memory be accessed outside its scope?

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

The program in your book is erroneous, as the function test() returns a pointer that has been initialized to point to an automatic local variable (the variable y in test() itself) that has ceased to exist as soon as the program returned from test(). So trying to use the pointer to access the value pointed to by it is undefined behaviour and this makes your program probably crash, show weird behaviour (as you show in your post). You cannot predict the value returned by it, as the pointer is pointing to memory that has ceased being used for its original purpose, and now is used for a different thing. The output you get is that, but can be completely different, with just changing the compiler version, optimization options or the machine architecture.

A book trying to illustrate this, not warning you about the undefined behaviour stated by the language, is showing, at least, very bad pedagogical manners, and using bad code to teach unusable things. I cannot guess why the output of the program can be of interest for anything. So, please, correct me.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • I am sorry, I missed your message regarding my question. The book is from a reputable publishing company called Springer and from the method the author has taken in the book " Computer Programming for Beginners" by A.J.Gonzalez I think he was trying to explain something using a bad example and considering it being a beginners book, the author may have not wanted to burden the reader with explanations regarding undefined behaviour. i have anyway given up on the book and picked up C programming a modern approach by K N King. Thank you for your help regarding this problem Regards – watercolour man Jun 02 '21 at 11:24
  • the problem is that the example is a bad pedagogical example of code. Even being a bad use, there's no sense in trying to dig what is happening there, because a different computer can be doing things completely different. So once the example is there, the only possible explanation for a beginner is that that has never to be used.... but not to try to explain what happens in one single implementation. Had the author shown two different behaviours on two computers, should suffice to illustrate... but you don't show but just a single behaviour. – Luis Colorado Jun 03 '21 at 19:50