ztrx 发表于 2017-3-17 18:07:37

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

本帖最后由 ztrx 于 2017-3-17 18:14 编辑

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

int * fun ( void )

{

    int arr;

    arr = 10;

    arr = 20;

    return arr;

}

int main()

{

    int * ptr= fun();

    printf ( "%d,%d\n", ptr , ptr );

    return 0;

}

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

{

    int * ptr= fun();

    printf ( "%d,%d\n", ptr , ptr );

    printf ( "%d,%d\n", ptr , ptr );

    return 0;

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

{

    static int arr;

    arr = 10;

    arr = 20;

    return arr;

}
输出:
10,20
10,20

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

typedef struct St

{

    int arr;

} Sarr;

Sarr fun ( void )

{

    Sarr a;

    a.arr = 10;

    a.arr = 20;

    return a;

}

int main()

{

    Sarr a= fun();

    printf ( "%d,%d\n", a.arr , a.arr );

    printf ( "%d,%d\n", a.arr, a.arr );

    return 0;

}
输出:
10,20
10,20
第三种方法,使用malloc:
#include<stdio.h>

#include<stdlib.h>

int * fun()

{

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

    arr = 10;

    arr = 20;

    return arr;

}

int main()

{

    int * ptr= fun();

    printf ( "%d,%d\n", ptr , ptr );

    printf ( "%d,%d\n", ptr , ptr );

    free ( ptr );

    return 0;

}
输出:
10,20
10,20

jathenal 发表于 2017-3-17 18:44:51

思路挺多,不过第3种malloc和free的写法用在多人协作的大项目中将是一场灾难

takashiki 发表于 2017-3-18 07:40:55

malloc的有隐患,我一般是谁申请谁释放,然后当参数传递过去,跨函数很容易就内存泄露。

hongmark 发表于 2017-3-18 09:18:06

不错,谢谢分享

jm2011 发表于 2017-3-18 09:45:58

第一种写法返回的就是一个无效指针,变量是在栈中分配的,返回后自动释放了。这个就和{char * str; retuen str;}是一个意思;
返回的指针就是一个野指针,第一次对应该是这个地址没有被占用;

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

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

t3486784401 发表于 2017-3-19 13:37:36

在C++里返回指向局部实例的类指针,也是这个毛病,基本上直接就是 exception 然后爆了。
类似的返回引用也是有这个隐患,源始(局部变量那个)的被清空了,指针引用都是坑。

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

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

semonpic 发表于 2017-3-19 15:02:47

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

至少我认为keil 的C 编译器,还不能牛逼到识别我函数内的结构体,还能动态从堆上给我分配来,然后再合适的时间,释放这个结构体。
对于高级一点的C++,jAVA等,具备这个功能
页: [1]
查看完整版本: C语言入门之返回函数里的数组