Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 函数局部变量的return是如何工作的?_C_Function_Pointers_Return_Local Variables - Fatal编程技术网

C 函数局部变量的return是如何工作的?

C 函数局部变量的return是如何工作的?,c,function,pointers,return,local-variables,C,Function,Pointers,Return,Local Variables,我对局部变量的return重新分级感到困惑:变量、它的地址和使用指针的返回地址 第一名: #include <stdio.h> int returner(void); int main(void) { printf("The value I got is = %d\n", returner()); return 0; } int returner(void) { int a = 10; return a; } The val

我对局部变量的
return
重新分级感到困惑:变量、它的地址和使用指针的返回地址

第一名:

#include <stdio.h>

int returner(void);

int main(void)
{
    printf("The value I got is = %d\n", returner());
    return 0;
}

int returner(void)
{
    int a = 10;
    return a;
}
The value I got is = 10
#include <stdio.h>

int *returner(void);

int main(void)
{
    int *pointer = returner();
    printf("The value I got is = %d\n", *pointer);
    return 0;
}

int *returner(void)
{
    int a = 10;
    return &a;
}
Test.c: In function 'returner':
Test.c:15:12: warning: function returns address of local variable [-Wreturn-local-addr]
   15 |     return &a;
#include <stdio.h>

int *returner(void);

int main(void)
{
    int *pointer = returner();
    printf("The value I got is = %d\n", *pointer);
    return 0;
}

int *returner(void)
{
    int a = 10;
    int *ptr = &a;
    return ptr;
}
The value I got is = 10
局部变量被返回,尽管它在函数返回后应该超出范围,但它是如何工作的

秒:

#include <stdio.h>

int returner(void);

int main(void)
{
    printf("The value I got is = %d\n", returner());
    return 0;
}

int returner(void)
{
    int a = 10;
    return a;
}
The value I got is = 10
#include <stdio.h>

int *returner(void);

int main(void)
{
    int *pointer = returner();
    printf("The value I got is = %d\n", *pointer);
    return 0;
}

int *returner(void)
{
    int a = 10;
    return &a;
}
Test.c: In function 'returner':
Test.c:15:12: warning: function returns address of local variable [-Wreturn-local-addr]
   15 |     return &a;
#include <stdio.h>

int *returner(void);

int main(void)
{
    int *pointer = returner();
    printf("The value I got is = %d\n", *pointer);
    return 0;
}

int *returner(void)
{
    int a = 10;
    int *ptr = &a;
    return ptr;
}
The value I got is = 10
尽管返回的值与第一个示例中的值相同,但为什么不返回地址

第三名:

#include <stdio.h>

int returner(void);

int main(void)
{
    printf("The value I got is = %d\n", returner());
    return 0;
}

int returner(void)
{
    int a = 10;
    return a;
}
The value I got is = 10
#include <stdio.h>

int *returner(void);

int main(void)
{
    int *pointer = returner();
    printf("The value I got is = %d\n", *pointer);
    return 0;
}

int *returner(void)
{
    int a = 10;
    return &a;
}
Test.c: In function 'returner':
Test.c:15:12: warning: function returns address of local variable [-Wreturn-local-addr]
   15 |     return &a;
#include <stdio.h>

int *returner(void);

int main(void)
{
    int *pointer = returner();
    printf("The value I got is = %d\n", *pointer);
    return 0;
}

int *returner(void)
{
    int a = 10;
    int *ptr = &a;
    return ptr;
}
The value I got is = 10
现在,这个方法如何返回局部变量的地址并打印其正确的值,尽管该变量应该超出范围/在函数返回后被销毁

请解释这三种方法的工作原理。

  • 首先输出:返回值(没有作用域)
  • 第二个输出:您试图返回超出范围的内容的地址
  • 输出第三:尽管您正尝试执行与前面相同的操作,但编译器没有检测到问题。然而,返回的指针同样有问题
上述函数返回一个
int
by值,只要返回,就相当于编写了
return10

int *returner(void)
{
    int a = 10;
    return &a;
}
上面是一个他们称之为“未定义行为”的例子——它有时可能有效,但并不可靠。返回的地址是指函数调用堆栈上用于存储函数局部变量的位置。在
returner
返回后,该内存不再保留用于保存
int a
,尽管它可能没有被重用,并且可能在该地址仍具有
10
值,但在之后的一段时间内,无法保证


第三个例子与第二个没有太大区别。该行为可能与第二种不同,因为堆栈分配不同,但这两种行为都不应持续工作或可移植。

函数返回的是
a的值,就像传递给函数的是其参数的值一样

您唯一需要担心超出范围的时间是在返回指向具有自动存储持续时间的本地函数变量的指针时,即:

int *badFunction ()
{
   int ret[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
   return ret;
}
在这种情况下,返回的值是指向数组
ret
的指针,但是,由于
ret
退出
badFunction
时超出范围,因此返回的指针显然无效。解决方法是使用带有
static
存储持续时间或堆的变量


在您的例子中,使用普通的
int
,您不需要担心范围。

在C中,返回值是按值的

第一个代码返回
a
的值,即10,这很好,它只是局部变量
a
的一个副本

第二个代码返回指向
a
的指针的值,这是它的地址。恰好在函数超出作用域后,该地址将无效,并且存储在该地址中的局部变量的生存期结束。编译器足够聪明,可以检测到这一点并向您发出警告

第三个代码不同,有一个来自另一个指针的地址赋值,编译器不会进一步检查所分配的地址是否有效,额外的间接层会使编译器失效

输出仍然是
10
,但这是偶然的,因此,这是可能的结果之一。这种构造没有标准化的行为,为了证明这一点,我稍微调整了一下。正如您在这里看到的,启用了优化
-O3

使用
clang
程序输出一些随机值:

并没有发出警告

鉴于
gcc
进一步验证并检测到有问题的分配:


在这两种情况下,值不再正确,
clang
的行为与
gcc

int a
->
static int a
@alex01011使用
static
需要充分了解其功能。我不会断章取义地放弃这样一个建议。这不是核物理。只要看一下文件,他就能确切地理解它的作用。这是未定义的行为。当变量的值超出范围时,C不会擦除它们。这实际上是一个问题。根据:当指针指向(或刚刚过去)的对象到达其生命周期结束时,指针的值将变得不确定。