-1

I'm actually going through some of the example code that demonstrates pointers in Kamran Amani's book, Extreme C. I edited the example and produced the code seen below:

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

int* create_an_integer(int value){
    int* var = (int*)malloc(sizeof(int));
    printf("Memory Address of value: %p\n", &value);
    var = &value;
    printf("Memory Address of var: %p\n", var);
    printf("Value at Memory Address of var: %d\n", *var);
    return var;
}
int main(void) {
    int* ptr = create_an_integer(3);
    printf("\n\n");
    printf("Memory Address of ptr: %p\n", ptr);
    printf("Value at the memory address returned: %d\n", *ptr);
    free(ptr);
    return EXIT_SUCCESS;
}

When the code is executing and tries to display the memory address of ptr and the value at said memory address of ptr, it will correctly display the memory address but then will not show the correct value. However, the funny thing is that if I omit the line printf("Memory Address of ptr: %p\n", ptr);, rebuild the code, and run it again, it correctly shows the value at the memory address in ptr, which in this case should be 3. Any help would be appreciated.

ztayuun
  • 9
  • 3
  • 3
    `var = &value;` creates a memory leak *and* a dangling pointer. You want `*var = value;` – UnholySheep Jun 26 '20 at 21:21
  • Does this answer your question? [Can a local variable's memory be accessed outside its scope?](https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope) – Raymond Chen Jun 26 '20 at 21:22
  • @RaymondChen: No, because the problem does not appear to be that the author is attempting to return the address of an automatic object but that the author does not know that the function parameter is an automatic object. They seem to think `&value` will refer to the `3` in the function call. – Eric Postpischil Jun 26 '20 at 21:27

1 Answers1

1

In int* create_an_integer(int value), the parameter value is a temporary object that is created automatically when the function is called. This object contains a copy of the passed value, 3. However, the memory for it is reserved only for the duration of function execution. When the function returns, the memory is no longer reserved and may be reused for other purposes.

Attempting to use that memory might or might not yield the 3 value that was there previously, depending on whether the memory has been reused and other factors. The fact that it might still contain 3 is why your program might output “3” in certain code arrangements and not others. This behavior is not reliable.

Further, the address of an automatic object becomes invalid when the object ceases to exist (when the memory is no longer reserved for it). That is, the address itself is not a valid value in the C model and should not be used. So a function should never return an address of an automatic object, and a calling routine should never use such an address.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • &value points to a stack place subsequently reused. value is a local automatic, created by pulling the stack pointer down 4 bytes. – David G. Pickett Jun 26 '20 at 22:18
  • @DavidG.Pickett: Likely not. A common method of handling stack with regard to function calls is that a new stack frame is created when a function is called, decreasing the stack pointer by enough for all of the function’s local objects (unless there are complications such as a function that uses variable length arrays). Individual stack pushes are often not used. I expect it would be wasteful to be changing the stack pointer frequently and cause complications in superscalar instruction execution by creating a global dependency between many instructions… – Eric Postpischil Jun 26 '20 at 22:30
  • … Further, `3` is probably passed in a register, and the machine code for `create_an_integer` has to manufacture an address for it by storing it somewhere inside its local stack frame. This results in `&value` pointing somewhere below the stack frame of `main`. Then, when `printf("\n\n");` is called, that location may be undisturbed, in part due to its simplicity. But `printf("Memory address of ptr: %p\n", ptr);` is more complicated and uses that location. This would explain why OP sees output of “3” with that line deleted but not with it present. – Eric Postpischil Jun 26 '20 at 22:32
  • I appreciate all the feedback, it seems that I have to brush up on my syntax and practice a little more when assigning values to pointers. I didn't really have a set use for this code, I was just modifying it and seeing if I could change snippets and see if it could still work. Thanks again! – ztayuun Jun 26 '20 at 22:56
  • Register optimizations are fine, but they emulate the stack behavior for local automatic variables. If data is in a register, what is a pointer to that value? The point is that a lease to a sand castle eaten by the waves is worthless. The pointer points to released, reused space at best. – David G. Pickett Jun 27 '20 at 22:01
  • Are these ARM64, MIPS, SPARC, 68000, or X86 registers in your C? – David G. Pickett Jun 27 '20 at 22:03
  • @DavidG.Pickett: The passing of `3` in a register I described is neither an optimization (by a compiler) nor emulation of stack behavior. It is a requirement of an ABI; the register **is** how the argument is passed. As I wrote, when a function takes the address of such a parameter, the compiler must **manufacture** an address for it. It does this by storing the parameter to an address on the stack and then using that location when the object is needed, whereas, in the absence of taking an address, it would simply use the register directly. – Eric Postpischil Jun 27 '20 at 22:21
  • @DavidG.Pickett: Further, this model explains the reported behavior: If the argument were passed by the caller putting it on the stack, it would necessarily be overwritten by an intervening function call (as the one to `printf("\n\n");`). But the fact that the compiler puts it in a manufactured address means it can be deeper in the stack, where it can be left alone by a simple function call yet disturbed by a more complicated call. So this model fits the observations well. – Eric Postpischil Jun 27 '20 at 22:23
  • Deeper in the stack, like time travel, registers saved and restored? Register optimization may be more forgiving than the traditional stack behavior, but good programmers do not write code that depends on the right optimization. I feel there is no need, as good code is as fast, and stable, robust. – David G. Pickett Jun 27 '20 at 23:24
  • @DavidG.Pickett: Nobody is saying to write code that depends on this. – Eric Postpischil Jun 28 '20 at 00:15