c语言 返回局部变量 局部指针 局部数组

时间:2021-04-11 01:15:08
纯c(非c++下的c)

返回局部变量 、局部指针、 局部数组
这三种情况,
那些是正确的,那些是错误的容易出问题的?



我已经知道返回局部指针不正确,但如果局部指针指向静态区常量还是不会出错的。
但是返回局部变量 和 返回局部数组还不清楚。

希望有深度的回答。

25 个解决方案

#1


返回局部变量,其实是拷贝的副本,所以没问题。
返回局部指针,指针指向的内容会随函数失效,所以不妥。
返回局部数组,你想用什么语法返回?一般没试过返回数组。

#2


局部变量:如果是基本变量,可以直接返回;如果是自定义变量,基本都是使用指针参数带出。


int Sum( int a, int b )  // 基本变量没什么问题。
{
    return (a+b);
}

int DoSomething( const struct MyStruct * pParamIn1, const struct MyStruct * pParamIn2, strct MyStruct * pParamOut )
{
    // 在这里处理pParamIn1和pParamIn2指向的结构体,将结果保存到pParamOut指向的结构体中
     // 带出函数,返回值只表示函数处理成功还是失败以及可能的失败原因
}


局部指针:如果指针指向的内存是在函数内部申请的,基本不干返回指针这种事,做这种事情很有可能是在给自己找麻烦,多数做的都是在可以释放的地方申请好内存,通过指针传递进函数,申请和释放都在同一函数中。


void ToBeCalledByFun( SomeType * pParam )  // 被调用函数不申请堆内存
{
    // Do something to *pParam
}

void Fun( /*some parameters*/ )
{
    SomeType * pCallMem = (SomeType *)malloc( sizeof(SomeType) );
    // 内存申请放在free的同一个函数里

    ToBeCalledByFun( pCallMem );

    // Do something

    free( pCallMem );
    pCallMem = NULL;
}


局部数组:我相信没什么人想返回这个东西。

#3


局部指针的话,通常人都认为指向的局部变量失效,那该地址存的是垃圾值,其实不然,系统要在接到你要操作这个内存的指令后才会把它清0,它并不是立刻清0,就好比文件一样,并不是接到指令立刻把文件全清0,只是标记告诉系统这个空间可用,文件一般是在的。
数组也是一样,下面有个小实例,第一个能正常输入,第二个则不行,因为在它之前操作了这块内存,操作了这块内存。

#include "stdafx.h"
char * Cstr(void)
{
char a[10] = "like";
return a;
}

int main(void) 

char *a=Cstr();
printf("%c\n",*(a+1));
printf("%c\n",*(a+1));
return 0; 

#4


上面是输出,打错个字。

#5


局部变量的返回是值传递,这个是没有问题的
局部指针不必说
局部数组返回是不可以的,因为数组是一片连续的内存区域,如果是局部数组,那就是在栈上分配,而在这里数组名和指针是一样的,函数返回后,内存空间就会被回收

#6


引用楼主 deep_pro 的回复:
纯c(非c++下的c)

返回局部变量 、局部指针、 局部数组
这三种情况,
那些是正确的,那些是错误的容易出问题的?


我已经知道返回局部指针不正确,但如果局部指针指向静态区常量还是不会出错的。
但是返回局部变量 和 返回局部数组还不清楚。

希望有深度的回答。


你说的返回局部数组就考虑了,不知道你怎么返回的

考虑返回局部变量和局部变量指针

return语句
调用函数的时候,会在调用函数的地方生成一个临时变量,return语句将你要的返回值赋给这个临时变量,也就是临时变量得到返回值的一个副本

其实很简单,如果指针指向的是一段栈区(局部变量就放在这里啦),函数结束后返回,这段栈被释放了,你能通过return得到指针的副本,但是这是指针指向的空间已经无效啦,你让指针咋办呢?

对比局部变量,返回它,就是让上面说的临时变量得到它的一个副本嘛,然后你想对这个副本干嘛就干嘛咯

#7


引用楼主 deep_pro 的回复:
纯c(非c++下的c)

返回局部变量 、局部指针、 局部数组
这三种情况,
那些是正确的,那些是错误的容易出问题的?


我已经知道返回局部指针不正确,但如果局部指针指向静态区常量还是不会出错的。
但是返回局部变量 和 返回局部数组还不清楚。

希望有深度的回答。


局部变量里面还得分为自动还是静态,两者结果是不同的,得分开描述。

数组是不能作为函数的返回值的,原因是数组名是一个不可修改的左值,例如这样的代码是非法的:

int func( void )[5]; 

返回一个数组一般用返回指向这个数组的指针代替,而且这个指针不能指向一个自动数组,因为函数结束后自动数组被抛弃,但可以返回一个指向静态局部数组的指针,因为静态存储期是从对象定义到程序结束的。例如:

int* func( void )
{
     static int a[10];
     ........
     return a;
}

局部变量也*部自动变量和局部静态变量,由于c返回的是值,因此返回一个局部变量是可以的,无论自动还是静态,因为这时候返回的是这个局部变量的值,但不应该返回指向局部自动变量的指针,因为函数调用结束后该局部自动变量被抛弃,这个指针指向一个不再存在的对象,是无意义的。但可以返回指向局部静态变量的指针,因为静态变量的生存期从定义起到程序结束。例如:

int func()
{
      int a;
      ....
      return a;     //允许
}                     

int * func()
{
      int a;
      ....
      return &a;     //无意义,不应该这样做
}

局部指针跟上面所述的局部变量一样。可以返回一个局部指针的值,也可以返回一个局部静态指针的地址,但不应该返回一个局部自动指针的地址。

#8


学习

#9


引用 7 楼 supermegaboy 的回复:
引用楼主 deep_pro 的回复:
纯c(非c++下的c)

返回局部变量 、局部指针、 局部数组
这三种情况,
那些是正确的,那些是错误的容易出问题的?


我已经知道返回局部指针不正确,但如果局部指针指向静态区常量还是不会出错的。
但是返回局部变量 和 返回局部数组还不清楚。

希望有深度的回答。


局部变量里面还得分为自动还是静态,两者结果是不同的,得分开描述。

数组是不能作为函数的返回值的,原因是数组名是一个不可修改的左值,例如这样的代码是非法的:

int func( void )[5];

返回一个数组一般用返回指向这个数组的指针代替,而且这个指针不能指向一个自动数组,因为函数结束后自动数组被抛弃,但可以返回一个指向静态局部数组的指针,因为静态存储期是从对象定义到程序结束的。例如:

int* func( void )
{
    static int a[10];
    ........
    return a;
}

局部变量也*部自动变量和局部静态变量,由于c返回的是值,因此返回一个局部变量是可以的,无论自动还是静态,因为这时候返回的是这个局部变量的值,但不应该返回指向局部自动变量的指针,因为函数调用结束后该局部自动变量被抛弃,这个指针指向一个不再存在的对象,是无意义的。但可以返回指向局部静态变量的指针,因为静态变量的生存期从定义起到程序结束。例如:

int func()
{
      int a;
      ....
      return a;    //允许
}                   

int * func()
{
      int a;
      ....
      return &a;    //无意义,不应该这样做
}

局部指针跟上面所述的局部变量一样。可以返回一个局部指针的值,也可以返回一个局部静态指针的地址,但不应该返回一个局部自动指针的地址。

复议!

#10


局部变量:如果是值上的返回,没问题.
局部指针:和指针的指向有关.
局部数组:不能返回数组的.

#11


说的很好啊
整个return机制就大概这么多吧,不知还有人知道return还能返回什么其他的类型吗?

#12


引用 1 楼 hairetz 的回复:
返回局部变量,其实是拷贝的副本,所以没问题。
返回局部指针,指针指向的内容会随函数失效,所以不妥。
返回局部数组,你想用什么语法返回?一般没试过返回数组。


UP

#13


总之,条款里说:禁止返回局部变量的指针或引用。
是有道理的

#14


这还要分情况讨论,例如局部指针:

int * func(void)
{
    int i = 10;
    int * p = &i;
    return p;
}

是有问题的,如果这样:

int * func(void)
{
    int * p = molloc(10 * sizeof(int));
    return p;
}

在用的时候这样:

int * q = func();
//...
free(q);

就没有问题

#15


引用 13 楼 hairetz 的回复:
总之,条款里说:禁止返回局部变量的指针或引用。
是有道理的

条例说的没错,但是如果返回的是堆上的局部指针,而不是栈上的,就没有问题,当然,在这种情况下,一定要记得释放内存。

#16


条例说的没错,但是如果返回的是堆上的局部指针,而不是栈上的,就没有问题,当然,在这种情况下,一定要记得释放内存。

返回的是堆上的局部指针
也是不好的写法,这种情况其实你需要智能指针。

#17


上面各位说的很好了,我就提一点,其实这些都是关于变量的生存周期和变量作用域的问题。

#18


我觉得这个主要是要了解一下变量、参数的作用域的问题,以及参数是如何传递的问题。
在C专家编程里面有比较详细的说明

#19


引用 17 楼 cheng_fengming 的回复:
上面各位说的很好了,我就提一点,其实这些都是关于变量的生存周期和变量作用域的问题。

这个哥们说的好!只是书面了一些。你喜欢深的看下面

我来深一点!
return?什么叫return?程序原本是没有return的,自从有了C这样的高级语言后才有return这种形式。
是形式,真正实现还是汇编。对应寄存器eax !!(x86体系)

那么什么样的东西可以return呢?返回局部变量 、局部指针、 局部数组。。。。
只要是你在后边能够正常访问的东西即可,text,data中的持久数据肯定是可以的。那么stack中的呢?这要看你的程序返回后stack是否还有效?如果操作系统或者你自己的系统,在程序返回后不主动清空stack,那么你完全可以使用它。

C的美丽就在于直接操作内存和cpu,从机器运行本质看问题。一切问题都不是问题。

#20


引用 6 楼 abcdef0966 的回复:
 ...........
 对比局部变量,返回它,就是让上面说的临时变量得到它的一个副本嘛,然后你想对这个副本干嘛就干嘛咯

上面说的虽然深入,但抽象了点,:)
下面针对这位哥们的深入,希望能够浅出!

副本:(非山口山副本!)
用深入的概念讨论一下副本,
int test()
{
......
int i=3;
return i;//这里返回i的副本
}
对应汇编: 手头没有编译器,随便写,意思意思
__test:
 push 
 mv eax 3 ;这里返回i的副本
 pop
 ret
所谓的”返回 i 这个局部变量的副本“,其实就是他的值3放到exa中。

语言表达能力欠缺,希望大家能够明白我的意思。

#21


引用 18 楼 sh365 的回复:
我觉得这个主要是要了解一下变量、参数的作用域的问题,以及参数是如何传递的问题。
在C专家编程里面有比较详细的说明


建议楼主读一下
《C专家编程》
然后你就会豁然开朗了!

这个问题是C比较深入的东西了,
一言难尽啊

#22


很多很好很强大的回复
谢谢各位

#23


学习学习~~~~

#24


Agree with layer7, 10, 14, 19

#25


可不可以这么个理解呢?return返回了指针指向的堆空间的副本,而指针却是在栈中的,你没有把他给释放掉,所以这个指针还仍可以访问这段堆内存内的值;而如果是返回数组名的话应该也是如此,只不过你返回的是局部变量,在堆中会被很快释放掉(用完就被释放);

#1


返回局部变量,其实是拷贝的副本,所以没问题。
返回局部指针,指针指向的内容会随函数失效,所以不妥。
返回局部数组,你想用什么语法返回?一般没试过返回数组。

#2


局部变量:如果是基本变量,可以直接返回;如果是自定义变量,基本都是使用指针参数带出。


int Sum( int a, int b )  // 基本变量没什么问题。
{
    return (a+b);
}

int DoSomething( const struct MyStruct * pParamIn1, const struct MyStruct * pParamIn2, strct MyStruct * pParamOut )
{
    // 在这里处理pParamIn1和pParamIn2指向的结构体,将结果保存到pParamOut指向的结构体中
     // 带出函数,返回值只表示函数处理成功还是失败以及可能的失败原因
}


局部指针:如果指针指向的内存是在函数内部申请的,基本不干返回指针这种事,做这种事情很有可能是在给自己找麻烦,多数做的都是在可以释放的地方申请好内存,通过指针传递进函数,申请和释放都在同一函数中。


void ToBeCalledByFun( SomeType * pParam )  // 被调用函数不申请堆内存
{
    // Do something to *pParam
}

void Fun( /*some parameters*/ )
{
    SomeType * pCallMem = (SomeType *)malloc( sizeof(SomeType) );
    // 内存申请放在free的同一个函数里

    ToBeCalledByFun( pCallMem );

    // Do something

    free( pCallMem );
    pCallMem = NULL;
}


局部数组:我相信没什么人想返回这个东西。

#3


局部指针的话,通常人都认为指向的局部变量失效,那该地址存的是垃圾值,其实不然,系统要在接到你要操作这个内存的指令后才会把它清0,它并不是立刻清0,就好比文件一样,并不是接到指令立刻把文件全清0,只是标记告诉系统这个空间可用,文件一般是在的。
数组也是一样,下面有个小实例,第一个能正常输入,第二个则不行,因为在它之前操作了这块内存,操作了这块内存。

#include "stdafx.h"
char * Cstr(void)
{
char a[10] = "like";
return a;
}

int main(void) 

char *a=Cstr();
printf("%c\n",*(a+1));
printf("%c\n",*(a+1));
return 0; 

#4


上面是输出,打错个字。

#5


局部变量的返回是值传递,这个是没有问题的
局部指针不必说
局部数组返回是不可以的,因为数组是一片连续的内存区域,如果是局部数组,那就是在栈上分配,而在这里数组名和指针是一样的,函数返回后,内存空间就会被回收

#6


引用楼主 deep_pro 的回复:
纯c(非c++下的c)

返回局部变量 、局部指针、 局部数组
这三种情况,
那些是正确的,那些是错误的容易出问题的?


我已经知道返回局部指针不正确,但如果局部指针指向静态区常量还是不会出错的。
但是返回局部变量 和 返回局部数组还不清楚。

希望有深度的回答。


你说的返回局部数组就考虑了,不知道你怎么返回的

考虑返回局部变量和局部变量指针

return语句
调用函数的时候,会在调用函数的地方生成一个临时变量,return语句将你要的返回值赋给这个临时变量,也就是临时变量得到返回值的一个副本

其实很简单,如果指针指向的是一段栈区(局部变量就放在这里啦),函数结束后返回,这段栈被释放了,你能通过return得到指针的副本,但是这是指针指向的空间已经无效啦,你让指针咋办呢?

对比局部变量,返回它,就是让上面说的临时变量得到它的一个副本嘛,然后你想对这个副本干嘛就干嘛咯

#7


引用楼主 deep_pro 的回复:
纯c(非c++下的c)

返回局部变量 、局部指针、 局部数组
这三种情况,
那些是正确的,那些是错误的容易出问题的?


我已经知道返回局部指针不正确,但如果局部指针指向静态区常量还是不会出错的。
但是返回局部变量 和 返回局部数组还不清楚。

希望有深度的回答。


局部变量里面还得分为自动还是静态,两者结果是不同的,得分开描述。

数组是不能作为函数的返回值的,原因是数组名是一个不可修改的左值,例如这样的代码是非法的:

int func( void )[5]; 

返回一个数组一般用返回指向这个数组的指针代替,而且这个指针不能指向一个自动数组,因为函数结束后自动数组被抛弃,但可以返回一个指向静态局部数组的指针,因为静态存储期是从对象定义到程序结束的。例如:

int* func( void )
{
     static int a[10];
     ........
     return a;
}

局部变量也*部自动变量和局部静态变量,由于c返回的是值,因此返回一个局部变量是可以的,无论自动还是静态,因为这时候返回的是这个局部变量的值,但不应该返回指向局部自动变量的指针,因为函数调用结束后该局部自动变量被抛弃,这个指针指向一个不再存在的对象,是无意义的。但可以返回指向局部静态变量的指针,因为静态变量的生存期从定义起到程序结束。例如:

int func()
{
      int a;
      ....
      return a;     //允许
}                     

int * func()
{
      int a;
      ....
      return &a;     //无意义,不应该这样做
}

局部指针跟上面所述的局部变量一样。可以返回一个局部指针的值,也可以返回一个局部静态指针的地址,但不应该返回一个局部自动指针的地址。

#8


学习

#9


引用 7 楼 supermegaboy 的回复:
引用楼主 deep_pro 的回复:
纯c(非c++下的c)

返回局部变量 、局部指针、 局部数组
这三种情况,
那些是正确的,那些是错误的容易出问题的?


我已经知道返回局部指针不正确,但如果局部指针指向静态区常量还是不会出错的。
但是返回局部变量 和 返回局部数组还不清楚。

希望有深度的回答。


局部变量里面还得分为自动还是静态,两者结果是不同的,得分开描述。

数组是不能作为函数的返回值的,原因是数组名是一个不可修改的左值,例如这样的代码是非法的:

int func( void )[5];

返回一个数组一般用返回指向这个数组的指针代替,而且这个指针不能指向一个自动数组,因为函数结束后自动数组被抛弃,但可以返回一个指向静态局部数组的指针,因为静态存储期是从对象定义到程序结束的。例如:

int* func( void )
{
    static int a[10];
    ........
    return a;
}

局部变量也*部自动变量和局部静态变量,由于c返回的是值,因此返回一个局部变量是可以的,无论自动还是静态,因为这时候返回的是这个局部变量的值,但不应该返回指向局部自动变量的指针,因为函数调用结束后该局部自动变量被抛弃,这个指针指向一个不再存在的对象,是无意义的。但可以返回指向局部静态变量的指针,因为静态变量的生存期从定义起到程序结束。例如:

int func()
{
      int a;
      ....
      return a;    //允许
}                   

int * func()
{
      int a;
      ....
      return &a;    //无意义,不应该这样做
}

局部指针跟上面所述的局部变量一样。可以返回一个局部指针的值,也可以返回一个局部静态指针的地址,但不应该返回一个局部自动指针的地址。

复议!

#10


局部变量:如果是值上的返回,没问题.
局部指针:和指针的指向有关.
局部数组:不能返回数组的.

#11


说的很好啊
整个return机制就大概这么多吧,不知还有人知道return还能返回什么其他的类型吗?

#12


引用 1 楼 hairetz 的回复:
返回局部变量,其实是拷贝的副本,所以没问题。
返回局部指针,指针指向的内容会随函数失效,所以不妥。
返回局部数组,你想用什么语法返回?一般没试过返回数组。


UP

#13


总之,条款里说:禁止返回局部变量的指针或引用。
是有道理的

#14


这还要分情况讨论,例如局部指针:

int * func(void)
{
    int i = 10;
    int * p = &i;
    return p;
}

是有问题的,如果这样:

int * func(void)
{
    int * p = molloc(10 * sizeof(int));
    return p;
}

在用的时候这样:

int * q = func();
//...
free(q);

就没有问题

#15


引用 13 楼 hairetz 的回复:
总之,条款里说:禁止返回局部变量的指针或引用。
是有道理的

条例说的没错,但是如果返回的是堆上的局部指针,而不是栈上的,就没有问题,当然,在这种情况下,一定要记得释放内存。

#16


条例说的没错,但是如果返回的是堆上的局部指针,而不是栈上的,就没有问题,当然,在这种情况下,一定要记得释放内存。

返回的是堆上的局部指针
也是不好的写法,这种情况其实你需要智能指针。

#17


上面各位说的很好了,我就提一点,其实这些都是关于变量的生存周期和变量作用域的问题。

#18


我觉得这个主要是要了解一下变量、参数的作用域的问题,以及参数是如何传递的问题。
在C专家编程里面有比较详细的说明

#19


引用 17 楼 cheng_fengming 的回复:
上面各位说的很好了,我就提一点,其实这些都是关于变量的生存周期和变量作用域的问题。

这个哥们说的好!只是书面了一些。你喜欢深的看下面

我来深一点!
return?什么叫return?程序原本是没有return的,自从有了C这样的高级语言后才有return这种形式。
是形式,真正实现还是汇编。对应寄存器eax !!(x86体系)

那么什么样的东西可以return呢?返回局部变量 、局部指针、 局部数组。。。。
只要是你在后边能够正常访问的东西即可,text,data中的持久数据肯定是可以的。那么stack中的呢?这要看你的程序返回后stack是否还有效?如果操作系统或者你自己的系统,在程序返回后不主动清空stack,那么你完全可以使用它。

C的美丽就在于直接操作内存和cpu,从机器运行本质看问题。一切问题都不是问题。

#20


引用 6 楼 abcdef0966 的回复:
 ...........
 对比局部变量,返回它,就是让上面说的临时变量得到它的一个副本嘛,然后你想对这个副本干嘛就干嘛咯

上面说的虽然深入,但抽象了点,:)
下面针对这位哥们的深入,希望能够浅出!

副本:(非山口山副本!)
用深入的概念讨论一下副本,
int test()
{
......
int i=3;
return i;//这里返回i的副本
}
对应汇编: 手头没有编译器,随便写,意思意思
__test:
 push 
 mv eax 3 ;这里返回i的副本
 pop
 ret
所谓的”返回 i 这个局部变量的副本“,其实就是他的值3放到exa中。

语言表达能力欠缺,希望大家能够明白我的意思。

#21


引用 18 楼 sh365 的回复:
我觉得这个主要是要了解一下变量、参数的作用域的问题,以及参数是如何传递的问题。
在C专家编程里面有比较详细的说明


建议楼主读一下
《C专家编程》
然后你就会豁然开朗了!

这个问题是C比较深入的东西了,
一言难尽啊

#22


很多很好很强大的回复
谢谢各位

#23


学习学习~~~~

#24


Agree with layer7, 10, 14, 19

#25


可不可以这么个理解呢?return返回了指针指向的堆空间的副本,而指针却是在栈中的,你没有把他给释放掉,所以这个指针还仍可以访问这段堆内存内的值;而如果是返回数组名的话应该也是如此,只不过你返回的是局部变量,在堆中会被很快释放掉(用完就被释放);