C语言 从函数中返回数组

本文将探究如何从函数中返回一个数组。

一、问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
代码功能为:
fun函数新建一个数组,返回给main函数,
main函数通过指针接受并打印。
*/

int *fun(int n);
int main(){
int i,n=10;
int *a=fun(n);
for(i=0;i<10;i++) printf("%d\n",a[i]);
}
int *fun(int n){
int a[10];
int i;
for(i=0;i<10;i++) a[i]=i+n;
return a;
}

数组并不能被顺利返回,此段代码运行结果如图:

二、解决办法

1.动态分配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
改为通过动态分配的方式建立数组,其它代码与之前完全相同。
*/

int *fun(int n);
int main(){
int i,n=10;
int *a=fun(n);
for(i=0;i<10;i++) printf("%d\n",a[i]);
}
int *fun(int n){
int *a=(int*)malloc(sizeof(int)*10);
int i;
for(i=0;i<10;i++) a[i]=i+n;
return a;
}

数组被顺利地返回了,修改后的代码运行结果如图:

2.static数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
建立static数组,其它代码与之前完全相同。
*/

int *fun(int n);
int main(){
int i,n=10;
int *a=fun(n);
for(i=0;i<10;i++) printf("%d\n",a[i]);
}
int *fun(int n){
static int a[10];
int i;
for(i=0;i<10;i++) a[i]=i+n;
return a;
}

数组被顺利地返回了,修改后的代码运行结果如图:

三、为什么

1.生存期与作用域

从变量的生存期区分,变量的存储可分为静态存储和动态存储

静态存储:在程序运行期间由系统分配固定的存储空间。在程序开始时分配空间,直到程序结束时才释放空间。

动态存储:在程序运行期间由系统进行动态的空间分配。调用函数时,分配空间;函数结束时,释放空间。

从变量的作用域区分,变量可以分为局部变量和全局变量

局部变量:只能在对应区域内被使用。

全局变量:在全局内可使用。

在函数内部定义的变量,在函数中定义时才分配空间,并伴随着函数的结束而被释放空间。

2.返回值

① 对于普通变量,将数值作为返回值传递回去之后,便完成了历史使命。

② 对于数组变量,只能返回地址。但因为数组空间已经被释放,所以再对该地址做的任何操作都是 没有意义且不安全的

虽然有的编译器可能允许你返回数组,并且一定程度上是可用的(在没被新内容覆盖之前),但这是不安全的,不应该这么做!!!

3.动态分配

动态分配与上述存储类别都不相同,可以由编程者的意愿在需要是分配空间,并在不需要时释放空间,无需听从系统的安排。

因此,我们可以在函数中 malloc 一片空间,用数组的方式访问它。并且因为不用担心被销毁,所以它也可以安全地返回。

4.static数组

通过 static 声明静态局部变量,当函数结束后,变量不会被销毁。

静态本地变量会继续存在,保持原值,并且无法被外界访问。(当然函数外本来就无法访问局部变量)

对于数组而言,通过 static 声明后,数组不会被销毁,且数组的首地址通过函数返回值返回。因此便安全且成功地将数组返回。

注意区分 static 和 const :

  • static 是声明静态局部变量,存储于静态存储区,不会随着函数的结束而被释放。

  • const是声明常变量,定义后无法再修改。

4.返回指针

和返回数组类似,返回局部变量的地址是危险的。虽然编译器也许不会提示,但同样的,返回一个已经被销毁的变量的地址,并对其做操作是 没有意义且不安全的

参考