C Warning: Function returns address of local varia

2020-01-28 06:13发布

问题:

The function below takes the argv[0] argument that contains the calling path of the application and replaces the last bit until it hits a "/" with the name of the new app I want to spawn that sits in the same folder.

BTW: I'm declaring a global argv variable so the function can have access to it because I did not want to pass the info in every function call.

When I compile my code, all seems to work, but I get the above warning.

I know that I'm declaring the variable and that as soon as the function returns it will be destroyed.

Being a beginner C programmer I wanted to know what the most elegant/easiest way of solving this problem would be?

Should I pass a pointer to the function or malloc some memory?

char *returnFullPath()
{
    char pathToApp[strlen(argv[0])+1];
    strcpy(pathToApp, argv[0]);
    int path_length = strlen(argv[0]);

    while (pathToApp[path_length] != '/')
    {
        path_length--;
    }

    if (path_length > 2)
        pathToApp[path_length+1] = '\0';
    else
        pathToApp[0] = '\0';

    // length of getcwd + length of pathtoapp + 1 for zero plus 6 for "bidbot"
    char bidbotPath[strlen(getcwd(NULL,0)) + strlen(pathToApp) + 1 + 6];

    sprintf(bidbotPath, "%s/%sbidbot", getcwd(NULL,0), pathToApp);

    return bidbotPath;
}

回答1:

Some other answers suggest that you malloc something and return it. This is bad practice in the same sense as in C++, when you new something in a function and the caller is supposed to delete it (who has ownership?)

There is a reason that many C APIs have the format of:

function(buf, length);

Meaning that the CALLER supplies the buffer and how long it is. IT is the caller's responsibility to allocate and de-allocate this buffer and your function should use it, and check that you're not going to overflow the length.

Do not malloc and return. It's just asking for trouble.



回答2:

Replace

char bidbotPath[strlen(getcwd(NULL,0)) + strlen(pathToApp) + 1 + 6];

with

char* bidbotPath = malloc(strlen(getcwd(NULL,0)) + strlen(pathToApp) + 1 + 6);

That way your variable is allocated on the heap and not on the stack, so it will not be deleted after the function returns.



回答3:

If possible, it is always better the function a pointer to the memory in which the returned value can be written. I say so because you allow your clients (the callers of the function) the choice of where to locate the memory: on the stack or the heap, or perhaps even somewhere more exotic.

Now, the kicker in this is the if possible clause. Sometimes the size of the memory can only be determined during the implementation of the function. A typical example would be a function that null-terminated string. When you come across this scenario you are typically best resorting to allocating the memory on the heap inside the function, and requiring your clients to free the memory when they are done with it.



回答4:

As a first thing to say, the warning you're getting, could be consider an error. Any subsecuent call to a new function, will inevitably write over the memory that was holding the information you intended to return. This being said, there are a couple of ways to work this issue around.

Client-sided ownership

One could be, as Moo-Juice suggested, add some parameters to your invocation, delegating the responsability of making the information persistent after the function call.

void returnFullPath(char* fullPath, int maxLength)

and before you are done, copy your result to the output parameter with a call to strncpy (http://www.cplusplus.com/reference/cstring/strncpy/).

strncpy(fullPath, bidbotPath, maxLength);

This way, you make sure the function caller, is the owner of the memory, allocating and de-allocating it. And that you won't try to use un-allocated memory.

Provider-sided ownership

There is, though, another approach, also accepted for this language. And it is the one used, for instance, by the stdio.h library. If you want to open a file, you use the structure FILE, as a pointer. In this case, the stdio provides us with both functions fopen and fclose, one that allocates the resources, and the other one that de-allocates them. This makes use of a concept called Abstract Data Type, which is the closest thing to an object we'll ever see in structured programming. See this for further detail on ADTs. In this case, a complete ADT seems an absurd overkill for what you're doing, but goes with the idea.

For this case, would require both functions, allocation and de-allocation.

char* getFullPath(); /* here is where you do malloc*/
void disposeFullPath(char* fullPath); /* and here, free */

This way, you can malloc the exact amount of memory you need


Related to your question, i'd like to make some few comments.

  • Whenever you are able, try to stick to the ANSI standard. This is wikipedia but seems accurate.
  • Now that you are using C, you should check the style conventions for the language. Check this.
  • Use strrchar to find the last '/' in the path: here you go
  • And last but not least: Avoid static global variables, they are nothing but headaches


回答5:

When a function return, the local variable will be freed (deallocated), and the memory will be used for something else. If you return the address of a local variable, it may (and shall) cause problem.

There are two ways of solving this.

1) use static variable. static local variable are not freed on function exit.

static char bidbotPath[....];

BUT! it won't work with variable length.

2) Use malloc

char *bidbotPath = malloc(strlen(getcwd(NULL,0)) + strlen(pathToApp) + 1 + 6);

and you should call free(bidbotPath) after all uses of it.



回答6:

You have to assign bidbotPath variable memory dynamically using malloc or calloc. Then, be sure that the code calling your function is actually freeing the malloc'ed memory you return. This is a common practice, and a common idiom for C functions that return pointers to a "generated" array.

char * bidbotPath = (char*)malloc(strlen(getcwd(NULL,0)) + strlen(pathToApp) + 1 + 6);


回答7:

As BidotPath is declared within the scope of the function body as a normal stack variable it will go away when the function returns. While your program might work now, it is just by luck and it can start failing later if other code reuses the old stack area before your caller does.

You can declare bobotPath static, which keeps it around, but prevents the function from being thread safe. You could do a malloc of the proper length and return that to keep the function thread safe, but but the caller would need to free the memory to avoid leaks. Best would to provide a char array, and length, to put the data into in the argument to your function. Think snprintf() here. Inside use strncpy(), and similar routines, to copy to the target, but be aware that strncat() may not be much safe for you.

Also, your code needs to cope with the fact that there might not be a slash in argv[0]... just the name of the executable.

Not quite what you need, but here is some code I have used. I leave it as an exercise to the student to get what you need:

  cp = strrchr( argv[0], '/' );
  if ( cp )
     cp++;
  else
    cp = argv[0];


回答8:

when your trying to call any function then automatically memory gets allocated on the stack,but normally after execution of the function definition stack frame is discarded from the stack memory as specially if you want your function to return address then make variables that are used in function definition as static