# 实验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; } ```