# 实验1
假如我们有一个函数`a`,他的返回值是一个`int`,然后我们需要在`main`函数里接收`a`的返回值。
```c
#include <stdio.h>
int a();
int main(int argc, char const *argv[]) {
printf("%d",a());
return 0;
}
int a()
{
int b = 1;
return b;
}
```
# 实验2
现在改为返回一个`char *`字符串
```c
#include <stdio.h>
char * a();
int main(int argc, char const *argv[]) {
printf("%s",a());
return 0;
}
char * a()
{
char *b = "string";
return b;
}
```
# 实验3
如果是返回一个字符数组或者一个int数组呢?
```c
#include <stdio.h>
char * a();
int main(int argc, char const *argv[]) {
printf("%s",a());
return 0;
}
char * a()
{
char b[] = {'a','b','\0'};
return b;
}
```
**新人困惑:为什么明明是数组,却要返回一个指针呢?**
数组在 C 语言里是无法返回的,假设可以返回数组,那么返回返回值类型如何写呢?既然是函数都是动态的,返回数组的长度也是动态的,所以只能返回一个指针。
因为数组是连续的内存,而指针的类型正好可以用来计算数组各个元素内存的步长(需要偏移的字节数),这样就可以依次取出数组中的值了。这里我们用了一个`\0`来标识字符的结束。
**编译出错,为什么呢?**
```js
$ gcc test.c -o test
test.c:15:12: warning: address of stack memory associated with local variable
'b' returned [-Wreturn-stack-address]
return b;
^
1 warning generated.
```
因为`b`是在栈上分配的,当函数执行完毕之后就内存就回收了,所以返回`b`的首地址是没有意义的,里面的数据已经被清空。这就是局部变量的作用域。
**相比之,`实验2`也是返回的指针,为什么就没问题呢?**
因为字符串是在常量区申请的内存,函数结束后,内存不会回收。
参考 [字符串初始化的原理](https://mengkang.net/993.html#blog-title-8)
# 堆内存的使用
假如就是要返回数组,那应该怎么办呢?那么堆内存就可以派上用场了,因为堆上内存是使用者自己来控制内存申请和释放。
```c
#include <stdio.h>
#include <stdlib.h>
char *a();
int main(int argc, char const *argv[]) {
char *c = a();
printf("%s", c);
free(c);// 记得释放内存哦
return 0;
}
char *a() {
char *b = (char *) malloc(sizeof(char) * 3);
b[0] = 'a';
b[1] = 'b';
b[2] = '\0';
return b;
}
```