C语言 C 警告:函数返回局部变量的地址

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6897914/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 09:17:01  来源:igfitidea点击:

C Warning: Function returns address of local variable

cpointersmalloc

提问by Frank Vilea

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.

下面的函数采用包含应用程序调用路径的 argv[0] 参数并替换最后一位,直到它遇到一个“/”,其中包含我想要生成的位于同一文件夹中的新应用程序的名称。

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.

顺便说一句:我声明了一个全局 argv 变量,以便函数可以访问它,因为我不想在每个函数调用中传递信息。

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?

作为初学者 C 程序员,我想知道解决这个问题的最优雅/最简单的方法是什么?

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] = '
function(buf, length);
'; else pathToApp[0] = '
char bidbotPath[strlen(getcwd(NULL,0)) + strlen(pathToApp) + 1 + 6];
'; // 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; }

回答by Moo-Juice

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?)

其他一些答案建议你 malloc 一些东西并返回它。这与在 C++ 中的意义相同,这是一种不好的做法,当您在函数中添加新内容并且调用者应该删除它时(谁拥有所有权?)

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

许多 C API 具有以下格式是有原因的:

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

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.

这意味着 CALLER 提供缓冲区及其长度。分配和取消分配这个缓冲区是调用者的责任,你的函数应该使用它,并检查你不会溢出长度。

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

不要 malloc 并返回。这只是自找麻烦。

回答by Luchian Grigore

Replace

代替

void returnFullPath(char* fullPath, int maxLength)

with

strncpy(fullPath, bidbotPath, maxLength);

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

这样你的变量是在堆上而不是在堆栈上分配的,所以它不会在函数返回后被删除。

回答by David Heffernan

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 possibleclause. 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.

现在,这个问题的关键是if possible条款。有时内存的大小只能在函数执行过程中确定。一个典型的例子是一个以空字符结尾的字符串的函数。当您遇到这种情况时,您通常最好求助于在函数内部的堆上分配内存,并要求您的客户在完成后释放内存。

回答by coya

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.

一种可能是,正如 Moo-Juice 建议的那样,向您的调用添加一些参数,委派在函数调用之后使信息持久化的责任。

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

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 ( http://www.cplusplus.com/reference/cstring/strncpy/)将结果复制到输出参数。

static char bidbotPath[....];

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 thisfor further detail on ADTs. In this case, a complete ADT seems an absurd overkill for what you're doing, but goes with the idea.

但是,还有另一种方法也被这种语言接受。例如,它是由 stdio.h 库使用的。如果要打开文件,请使用结构 FILE 作为指针。在这种情况下,stdio 为我们提供了两个函数 fopen 和 fclose,一个用于分配资源,另一个用于取消分配。这利用了一个叫做抽象数据类型的概念,它是我们在结构化编程中见过的最接近对象的东西。见对ADT的进一步的细节。在这种情况下,一个完整的 ADT 对你正在做的事情来说似乎是一种荒谬的矫枉过正,但符合这个想法。

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

对于这种情况,将需要分配和取消分配这两个功能。

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

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

这样,您就可以 malloc 所需的确切内存量



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

关于你的问题,我想发表一些评论。

  • Whenever you are able, try to stick to the ANSI standard. Thisis 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
  • 只要有能力,就尽量坚持 ANSI 标准。是维基百科,但似乎准确。
  • 现在您正在使用 C,您应该检查该语言的样式约定。检查这个
  • 使用 strrchar 查找路径中的最后一个“/”:在这里
  • 最后但并非最不重要的一点:避免静态全局变量,它们只是令人头疼的问题

回答by J-16 SDiZ

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 staticvariable. static local variable are not freed on function exit.

1)使用static变量。函数退出时不释放静态局部变量。

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

BUT! it won't work with variable length.

但!它不适用于可变长度。

2) Use malloc

2) 使用 malloc

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

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

并且您应该free(bidbotPath)在所有使用它之后调用。

回答by Diego Sevilla

You have to assign bidbotPathvariable memory dynamically using mallocor 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.

您必须bidbotPath使用malloc或动态分配变量内存calloc。然后,确保调用您的函数的代码实际上正在释放您返回的 malloc 内存。这是一种常见的做法,也是返回指向“生成”数组的指针的 C 函数的常见习惯用法。

##代码##

回答by Gilbert

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.

由于 BidotPath 在函数体的范围内被声明为一个普通的堆栈变量,它会在函数返回时消失。虽然您的程序现在可能可以工作,但这只是运气,如果其他代码在您的调用者之前重用旧的堆栈区域,它可能会在稍后开始失败。

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.

您可以将 bobotPath 声明为静态,这样可以保留它,但会阻止该函数成为线程安全的。您可以执行适当长度的 malloc 并返回它以保持函数线程安全,但是调用者需要释放内存以避免泄漏。 最好提供一个字符数组和长度,将数据放入函数的参数中。想想这里的snprintf()。在内部使用strncpy()和类似的例程复制到目标,但请注意strncat()对您来说可能不太安全。

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.

此外,您的代码需要处理这样一个事实,即 argv[0] 中可能没有斜杠……只是可执行文件的名称。

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:

不完全是您需要的,但这是我使用的一些代码。我把它作为练习留给学生来获得你需要的东西:

##代码##

回答by rohit

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

当您尝试调用任何函数时,会自动在堆栈上分配内存,但通常在执行函数定义后,堆栈帧会从堆栈内存中丢弃,特别是如果您希望函数返回地址,然后创建函数中使用的变量定义为静态