1

Possible Duplicate:
Difference between - returning a ‘local’ char* from a function vs returning a ‘local’ int* from a function

Here is a simple code, where in 3 different functions [ localStrPtr, localIntPtr, localCharPtr] return a pointer to their local variables [string, integer, char] in their respective functions.

CODE:

#include <stdio.h>

char*  localStrPtr (char*);
int*   localIntPtr (int, int);
char*  localCharPtr (char);

main()
{
    int *pInt;
    char *pChar;

    printf( "localStrPtr = %s\n", localStrPtr("abcd") );

    pInt = (int*) localIntPtr(3, 5);
    printf( "localIntPtr = %d\n", *pInt );

    pChar = (char*) localCharPtr('y');
    printf( "localCharPtr = %c\n", *pChar );
}

char* localStrPtr(char* argu)
{
    char str[20];
    // char* str = (char*) malloc (20);

    strcpy (str, argu);
    return str;
}

int* localIntPtr (int argu1, int argu2)
{
    int local;
    local = argu1 + argu2;
    return (&local);
}

char* localCharPtr (char argu)
{
    char local;
    local = argu;
    return (&local);
}

COMPILE LOG:

stringManip.c: In function `localStrPtr':
stringManip.c:27: warning: function returns address of local variable
stringManip.c: In function `localIntPtr':
stringManip.c:34: warning: function returns address of local variable
stringManip.c: In function `localCharPtr':
stringManip.c:41: warning: function returns address of local variable

RUN LOG:

localStrPtr =
localIntPtr = 8
localCharPtr = y

As you can see in the log file, localStrPtr returns "some garbage", whereas localIntPtr and localCharPtr return "expected" values.

But, in the function localStrPtr, if I change char str[20] -to-> char* str = (char*) malloc (20), localStrPtr returns the string "abcd" correctly. Here is the RUN LOG, once the above change is made.

NEW RUN LOG:

localStrPtr = abcd
localIntPtr = 8
localCharPtr = y

QUESTIONS:

[1] In functions localIntPtr and localCharPtr, contents of the returned local variable addresses WORKED, but for the function localStrPtr, correct value is returned "only" with malloc, but will not with local char str[20]. Why doesn't it work with str[20] while works with local variables char and int ?

[2] Why do we see in the COMPILE LOG, the lines below for all the 3 functions ?

  • stringManip.c:27: warning: function returns address of local variable
  • stringManip.c:34: warning: function returns address of local variable
  • stringManip.c:41: warning: function returns address of local variable
trincot
  • 317,000
  • 35
  • 244
  • 286
Mike
  • 1,205
  • 3
  • 12
  • 21

5 Answers5

8

You cannot return local variables from a function. Local variables live on the stack, and once the function completes, that stack space is released and can be used by the next function call.

If you use malloc it allocates memory on the heap. This memory is not freed when the function ends, so you can return it and that memory is still allocated in the space of the calling function (this is also why malloc can lead to memory leaks, but local arrays don't).

This is not as clear as it seems since the return value is always passed by value. If you return a local int, it returns the value of that int and it works fine. If you return a local array, it returns the value of the pointer to that array, which will not be okay if that pointer is no longer pointing to a useful part of memory.

BostonJohn
  • 2,631
  • 2
  • 26
  • 48
  • Wrong. he uses `strcpy`. The problem is the input. – Ed S. Jan 09 '13 at 00:22
  • if you return a local array, you are still going to end up in a world of hurt. Also, strcpy does not affect the value of the pointer, so that can't affect the return value – BostonJohn Jan 09 '13 at 00:24
  • @EdS. Comments like yours will make the OP think it's ok to return the address of a local variable. – StoryTeller - Unslander Monica Jan 09 '13 at 00:25
  • You're right. When I first skimmed the code I thought he was copying the contents of the local array *into* the input via `strcpy`, which would be fine in most cases, but he was passing in a string literal. He is copying the input into the local array and returning that however, so you're correct. +1 – Ed S. Jan 09 '13 at 00:25
  • @StoryTeller: I misread the code at first. I left a comment explaining my misunderstanding. – Ed S. Jan 09 '13 at 00:26
  • @BostonJohn If I return the value, there is NO issue. Here I 'm returning the 'address' of the local variable. Why it works in the case of "integer" and "char" and fails in case of string. – Mike Jan 09 '13 at 00:54
3

If you declare your variable in a function it becomes local to that function, so, when that function ends, it frees all its local variables. Since you're returning a pointer to that memory space that is going to be automatically freed, you're making a mistake and getting a warning. With malloc you ask for space from the process virtual memory (heap) and you assume responsibility for that memory: You ask for it, so you shall free it(when you want but not if you want. Is a must do).

Thinking of C memory allocation only as an instrument for later initialization/allocation is a mistake, is much more than that.

So, for your second question, is almost explained in my answer above, but basically is what the compiler is saying: You are returning the address of something that only belongs to your local function. You're probably returning a pointer to garbage.

[EDIT] Just one more thing: Returns and 'non reference passed arguments' are copies of variables and not 'THE' variables. That is important so you understand why it would work if, for example, you had:

int localIntPtr(){
 int hi;
 ...
 return hi;
}

Hope this helps.

Afonso Tsukamoto
  • 1,184
  • 1
  • 12
  • 21
1

The warnings in your compiler log are there for a reason. You should never return a pointer to a local variable. The memory used by these variables may be reused at any time. This is why you see garbage in your output for localStrPtr(). You are lucky that the output for the other two functions are correct. This is not guaranteed to happen.

The reason that using malloc() works as you expect is because it allocates memory which will not be reclaimed until you explicitly tell the computer to do so with a corresponding call to free(). For local variables, the computer is able to reuse the memory any time it wishes.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
1

As the compiler mentions you are returning an address on the stack. After you do the return the value in the stack may or may not be overwritten by some other function call coming in later. The fact that you get an int or a char is just chance. if you issue another printf( "localIntPtr = %d\n", *pInt ); just before your return again you are likely to see that the pInt has been overwritten already.

user1952500
  • 6,611
  • 3
  • 24
  • 37
0

Whilst the answers given so far explain very well why returning a pointer to a local variable is NEVER acceptable, there are alternatives to using malloc(). The most common one is to pass in a pointer to the data that needs to be filled in. For example, we can pass an empty char array to a function that fills it in with a string. Or we can pass a pointer to an integer to a function that fills in the pointer with a value.

To allocate memory in a function, only so that the function can return a pointer to some data, is typically a poor choice. It forces the caller of that function to free the data [or there will be a leak, which is a bad thing]. It is better to have a function that allows the caller freedom to either allocate or use local variables in the calling function.

Obviously, in some cases, this means that the same variable has to be passed several layers of function calls from the lower layers of functions to the "top" function which fills something in, and then on the way back it gets processed at various levels, and possibly also stored in a malloc'd memory location. This is perfectly good practice, and should be encouraged.

Malloc should be used only when either the amount of data is previously unknown, so a caller would not be able to know how much memory to allocate, or the data actually needs to be stored for some time, and local variables won't "do". But always remmeber to free the memory which is allocated.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227