-2

There is a claim that this code right here would not return the correct "Sum" because of the preceding PrintHelloWorld() being executed and displacing the value that the pointer *ptr points to. However, I get the correct value each time I run it and even ran the PrintHelloWorld() function a dozen or more times right before the printing of *ptr.

So why is my code working and returning the value even though the pointer is pointing to a value that's been popped off the stack as claimed?

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

void PrintHelloWorld()
{
    printf("Hello World\n");
}

int *Add(int *a, int *b)
{
    int c = (*a) + (*b);
    return &c;
}

int main()
{
    int a = 2, b = 4;
    int *ptr = Add(&a,&b);
    PrintHelloWorld();
    printf("Sum = %d\n", *ptr);

    return 0;
}
unixpipe
  • 75
  • 1
  • 9
  • 1
    It is probably undefined behaviour. So it may do anything, including possibly giving you the result you expect. However, it may not *always* be the case. – user12205 Apr 19 '15 at 00:04
  • You're just getting lucky. If you call a function that uses many local variables, your sum is more likely to get overwritten. – JS1 Apr 19 '15 at 00:06
  • possible duplicate of [Can a local variable's memory be accessed outside its scope?](http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope) – Steve Fallows Apr 19 '15 at 00:16

2 Answers2

2

That is called Undefined Behavior and it's undefined so anything can happen, you can't actually predict the behavior because it depends on the structure of the program and the running conditions of the same.

If you enable compilation warnings, the compiler must warn you about the mistake, returning the address of local variables and trying to read it's content is undefined behavior, because it was already deallocated when you returned from the function.

Since it's undefined behavior, anything could happen, for example, it could work "correctly".

You are returning the address of a local variable. The variable c where you store the result of *a + *b is local to the function Add() and it has automatic storage duration.

That means that, when the function returns, it gets deallocated. Since you returned the address to it, and it was deallocated, trying to print it will just output garbage.

Try this and see

int *Add(int a, int b, int *c)
 {
    *c = a + b;
    return c;
 } 

and then in main()

int main()
 {
    int a = 2, b = 4, c, *ptr;
    ptr = Add(a, b, &c);
    printf("Sum = %d\n", *ptr);

    return 0;
 }

as you can see, you passed c's address and modified it inside the Add() function.

The c variable is local to main() so passing it's address to Add() modifiying it, and then reading it in main() is perfectly ok because in main() it's still valid.

It gets deallocated only when it gets out of scope, which didn't happen in this case.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • I do understand that. The reason I made the post is because I am getting the correct value of 6 when I run this code in contrast to what you are saying and the narrator of the video found here https://www.youtube.com/watch?v=E8Yh4dw6Diw&list=PL2_aWCzGMAwLZp6LMUKI3cc7pgGsasm2_&index=14 – unixpipe Apr 19 '15 at 00:06
  • @unixpipe 1. The guy in the video used the incorrect format specifier to print the address of the variable. – Iharob Al Asimi Apr 19 '15 at 00:10
  • this is why I need a better guide to learning C. The above code from iharob returns the correct sum if I comment out the PrintHelloWorld() function since it isnt declared anywhere – unixpipe Apr 19 '15 at 00:12
  • @unixpipe true, but it's just that I copied your code. Also, the comments on the video are worst. And yes you need a better guide. – Iharob Al Asimi Apr 19 '15 at 00:13
  • Anyway, his solution is to call malloc to create a "static" variable which I do understand completely. allocating from heap. So does this indicate that when using pointers, I should always have to call malloc? – unixpipe Apr 19 '15 at 00:15
  • @unixpipe: No. For example, look at the code in this answer. – Bill Lynch Apr 19 '15 at 00:17
  • No, it doesn't. It depends on the use case, you can need `malloc()` but this is by far **not** the case. – Iharob Al Asimi Apr 19 '15 at 00:18
  • Was I supposed to get 6 from your code as the result or no? I'm not terribly new to C but I did start not too long ago. I understand all the concepts except pointers and how memory works – unixpipe Apr 19 '15 at 00:20
  • Ok I see that which makes sense, however that video was on pointers as function returns which is different. I'd like to see an example showing that without having to use malloc – unixpipe Apr 19 '15 at 00:22
  • @unixpipe I updated the answer, the idea is the same, you returned the address of `c` to `main()` where `c` is still valid. – Iharob Al Asimi Apr 19 '15 at 00:23
  • @unixpipe Not necessarily but most of the time it could be the case, although the technique exposed above is used by many functions from the standard library like `strcat()` `strcpy()`/`memcpy()` which return poitners and the returned pointers are one of the passed pointers. – Iharob Al Asimi Apr 19 '15 at 01:30
  • @iharob so basically your code returns a pointer as a function return. without the use of `malloc()` yes? When would calling `malloc()` actually be appropriate? just trying to piece the different types of code and compare them to see their differences. many variations of doing things. – unixpipe Apr 19 '15 at 01:51
  • Yes!, And suppose you have a pointer to a string, and you want to modify a copy of the string, then you would use `malloc()` and write the modified string to the newly allocated space, returning that from a function is a very common thing to do, you would however need to be careful to call `free()` when you no longer need the pointed to data. – Iharob Al Asimi Apr 19 '15 at 01:53
  • @iharbo I have a last question regarding the comparison of the code you had entered before you updated your answer. I think the forum may ban me if I post another duplicate. How can I send it, email? – unixpipe Apr 20 '15 at 06:42
  • @unixpipe There is no **forum** involved and the system doesn't ban for duplicates, if it's not the same question just post it. – Iharob Al Asimi Apr 20 '15 at 10:58
  • Ok its a bit of a pain to try to ask what I want here because I want to compare two pieces of code, the one you had originally and the one you updated so I pasted them at pastebin. I would like the know what the differences are between them and when would you use one over the other http://pastebin.com/Avnb8Hh6 and http://pastebin.com/Ef4QjQqG – unixpipe Apr 20 '15 at 17:44
  • You should post a question in a different site [Code Review](http://codereview.stackexchange.com/). – Iharob Al Asimi Apr 20 '15 at 17:48
  • I was not able to post my question unfortunately since the pack leaders jumped on me like a bunch of scavengers but I just wanted to thank you for answering my original question here and I guess one day I will just sort of figure out for myself by just reading and learning and not bother asking any questions on any forums since it didn't involve mathematical formulas for an atomic bomb or the latest exploit on bash or the kernel. – unixpipe Apr 20 '15 at 19:10
  • @iharob Code explanations are not within the scope of [codereview.se]. – nhgrif Apr 20 '15 at 21:03
0

When you write code that exhibits undefined behavior, it shouldn't be surprising that undefined behavior occurs. With the particular compiler on the particular operating system on the particular architecture that the guy in the video was using, he gets the output that you see there.

With other compilers, it's possible that you will get other forms of undefined behavior.

As an example, this code will print a different output value each time I try and run it on my computer:

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

int *Add(int *a, int *b)
{
    int c = (*a) + (*b);
    return &c;
}

int main()
{
    int a = 2, b = 4;
    int *ptr = Add(&a,&b);
    printf("Sum = %d\n", *ptr);
}

Some runs:

[7:15pm][wlynch@watermelon /tmp] ./a.out
Sum = 1595243208
[7:16pm][wlynch@watermelon /tmp] ./a.out
Sum = 1392249544
[7:16pm][wlynch@watermelon /tmp] ./a.out
Sum = 1577798344
[7:16pm][wlynch@watermelon /tmp] ./a.out
Sum = 1340385992
[7:16pm][wlynch@watermelon /tmp] ./a.out
Sum = 1549621960
[7:16pm][wlynch@watermelon /tmp] ./a.out
Sum = 1572055752
[7:16pm][wlynch@watermelon /tmp] ./a.out
Sum = 1440946888
[7:16pm][wlynch@watermelon /tmp] ./a.out
Sum = 1604803272
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173