搜索
bottom↓
回复: 6

C语言入门之返回函数里的数组

[复制链接]

出0入4汤圆

发表于 2017-3-17 18:07:37 | 显示全部楼层 |阅读模式
本帖最后由 ztrx 于 2017-3-17 18:14 编辑

C语言入门之返回函数里的数组
  我们首先要写个函数,在函数里先定义个数,返回这个数组,调用这个函数。我们先这样写:
  1. #include<stdio.h>

  2. int * fun ( void )

  3. {

  4.     int arr[10];

  5.     arr[0] = 10;

  6.     arr[1] = 20;

  7.     return arr;

  8. }

  9. int main()

  10. {

  11.     int * ptr  = fun();

  12.     printf ( "%d,%d\n", ptr[0] , ptr[1] );

  13.     return 0;

  14. }
复制代码


输出:10,20 ,似乎我们已经成功了。别着急,我们再加一行代码:
  1. int main()

  2. {

  3.     int * ptr  = fun();

  4.     printf ( "%d,%d\n", ptr[0] , ptr[1] );

  5.     printf ( "%d,%d\n", ptr[0] , ptr[1] );

  6.     return 0;

  7. }
复制代码
  编译运行,输出:
  1. 10,20
  2. 4235364,2686676
复制代码
  怎么两行的输出不一样,问题出在哪里?我们先分析下这个函数int * fun ( void ),返回值是个指针,指向函数内arr数组,调用这个函数int * ptr  = fun(); ptr就指向arr数组。arr数组是个局部变量,我们知道,局部变量作用域仅限于自身所在的函数内部,出界便无效。所以使用这种方法是错误的。
  那么我们应该怎么写这个函数呢?
第一种方法,使用静态变量:
  把数组定义在函数外(全局变量)或者加static修饰,调用函数结束时,静态存储变量不消失并且保留原值。
  1. int * fun ( void )

  2. {

  3.     static int arr[10];

  4.     arr[0] = 10;

  5.     arr[1] = 20;

  6.     return arr;

  7. }
复制代码

输出:
  1. 10,20
  2. 10,20
复制代码


第二种方法,使用结构体:
  定义一个结构体,把这个数组放在这个结构体里。函数返回类型为结构体。
  1. #include<stdio.h>

  2. typedef struct St

  3. {

  4.     int arr[10];

  5. } Sarr;

  6. Sarr fun ( void )

  7. {

  8.     Sarr a;

  9.     a.arr[0] = 10;

  10.     a.arr[1] = 20;

  11.     return a;

  12. }

  13. int main()

  14. {

  15.     Sarr a  = fun();

  16.     printf ( "%d,%d\n", a.arr[0] , a.arr[1] );

  17.     printf ( "%d,%d\n", a.arr[0], a.arr[1] );

  18.     return 0;

  19. }
复制代码

输出:
  1. 10,20
  2. 10,20
复制代码

第三种方法,使用malloc:
  1. #include<stdio.h>

  2. #include<stdlib.h>

  3. int * fun()

  4. {

  5.     int * arr = malloc ( 10 * sizeof ( int ) );

  6.     arr[0] = 10;

  7.     arr[1] = 20;

  8.     return arr;

  9. }

  10. int main()

  11. {

  12.     int * ptr  = fun();

  13.     printf ( "%d,%d\n", ptr[0] , ptr[1] );

  14.     printf ( "%d,%d\n", ptr[0] , ptr[1] );

  15.     free ( ptr );

  16.     return 0;

  17. }
复制代码

输出:
  1. 10,20
  2. 10,20
复制代码

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2017-3-17 18:44:51 | 显示全部楼层
思路挺多,不过第3种malloc和free的写法用在多人协作的大项目中将是一场灾难

出0入93汤圆

发表于 2017-3-18 07:40:55 来自手机 | 显示全部楼层
malloc的有隐患,我一般是谁申请谁释放,然后当参数传递过去,跨函数很容易就内存泄露。

出0入0汤圆

发表于 2017-3-18 09:18:06 | 显示全部楼层
不错,谢谢分享

出0入0汤圆

发表于 2017-3-18 09:45:58 | 显示全部楼层
第一种写法返回的就是一个无效指针,变量是在栈中分配的,返回后自动释放了。这个就和{char * str; retuen str;}是一个意思;
返回的指针就是一个野指针,第一次对应该是这个地址没有被占用;

另外我个人写代码的时候还是加上Lint工具的检查比较好,可以减少一部分错误;

有使用Lint的可以一起来交流一下;

出200入2554汤圆

发表于 2017-3-19 13:37:36 | 显示全部楼层
在C++里返回指向局部实例的类指针,也是这个毛病,基本上直接就是 exception 然后爆了。
类似的返回引用也是有这个隐患,源始(局部变量那个)的被清空了,指针引用都是坑。

另外返回结构体的那个,和返回类实例一样,实则是编译器帮你把局部的结构体直接复制了一份,然后拷贝到函数外边的接收处了。
这样虽然可以工作,但是内存有点浪费(尤其当结构体很大之时),如果是C++,还可能造成“访问的实例并非原来版本”之类隐患。

总之有这么几点建议:
① 用 static 最保险高效,缺点是永远不释放;
② 用结构体返回最简洁,缺点是时间+内存浪费,副本问题;
③ malloc/free 也就纯 C 没啥别的可用了再考虑吧,为了返回个数组这样牺牲略大;
④ 真的到这个要返回数组的份上,还是调用方准备缓冲,用指针传进去吧,或者直接全局。

出0入0汤圆

发表于 2017-3-19 15:02:47 | 显示全部楼层
我不认为楼主的第二种方法是合理的。
对于单片机一类的裸奔C系统,程序运行时候,非malloc分配的内存,均分配在栈上的。也就是说函数内局部变量,均是在分配在栈上,函数退出以后,这些局部变量
变得不可控,你读取正确,只是可能还没有别的函数来操作这块栈区。不要以为你弄个结构体就可以了。

至少我认为keil 的C 编译器,还不能牛逼到识别我函数内的结构体,还能动态从堆上给我分配来,然后再合适的时间,释放这个结构体。
对于高级一点的C++,jAVA等,具备这个功能
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 23:34

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表