# 實驗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;
}
```