char *fun()
{
char str[] = "hello";
return str;
}
這個函數的返回值?以及這個函數在棧上的存儲佈局
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *fun()
{
char ptr[] = "fda";
int a = 3;
int b = 4; printf("test: %x %x %d\n", ptr, &ptr[1], sizeof(ptr));
printf(" ptr a b :%x %x %x\n", ptr, &a, &b);
return ptr;
}
int main(int argc, const char *argv[])
{
char a1 = '7';
char *p = fun();
char a2 = '9';
printf("a1 a2 p(fun): %x %x %x\n", &a1, &a2, p);
char a = 4;
char b = 4;
printf("%x %x\n", &a, &b);
return 0;
}
就函數而言,返回局部變量的地址這種做法是錯誤的,但是這個函數不管是在VS還是在gcc上編譯時都只會有一個警告
局部變量的地址在出了作用域後就沒有意義了,可能被其他數據覆蓋
➜ 1009 git:(master) ✗ gcc test1.c
test1.c: 在函數‘fun’中:
test1.c:12:5: 警告:函數返回局部變量的地址 [-Wreturn-local-addr]
return ptr;
^
➜ 1009 git:(master) ✗ ./a.out
test:bfe416fc bfe416fd 4
ptr a b :bfe416fc bfe416f8 bfe416f4
a1 a2 p(fun): bfe4171b bfe4171a bfe416fc
bfe41719 bfe41718
可以看看地址的分佈情況:
...171b a1
....171a a2
....1719 a
.....1718 b
.....分配給fun函數棧...
...
....16ff ptr[3 '\0'
....16fe ptr[2] 'a'
...16fd ptr[1] 'd'
...16fc ptr[0] 'f ' ---》如果字符串長度加1 不爲4的倍數會有內存對齊
....16f8 int a
....16f4 int b
函數退出後再定義變量,又回到171a處
可以看出大致結構,給函數分配棧時並不是直接接着上面的,雖然函數退出後沒有清空或者初始化剛剛函數佔用的棧,但是後續的數據可以覆蓋上去
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *fun()
{
char ptr[] = "fda";
int a = 3;
int b = 4;
printf(" fun :%x %x %d\n", ptr, &ptr[1], sizeof(ptr));
printf("ptr a b :%x %x %x\n", ptr, &a, &b);
return ptr;
}
int main(int argc, const char *argv[])
{
char a1 = '7';
char *p = fun();
printf("p: %d\n", *p);
char a2 = '9';
printf("a1 a2 p(fun): %x %x %x\n", &a1, &a2, p);
char a = 4;
char b = 4;
printf("main a b :%x %x\n", &a, &b);
printf("p: %d\n", *p);
return 0;
}
結果:
➜ 1009 git:(master) ✗ gcc test1.c
test1.c: 在函數‘fun’中:
test1.c:12:5: 警告:函數返回局部變量的地址 [-Wreturn-local-addr]
return ptr;
^
➜ 1009 git:(master) ✗ ./a.out
fun :bffbedfc bffbedfd 4
ptr a b :bffbedfc bffbedf8 bffbedf4
p: 102
a1 a2 p(fun): bffbee1b bffbee1a bffbedfc
main a b :bffbee19 bffbee18
p: -33
剛退出函數時打印的是函數中的那個字符 f對應的ascii值是102, 後面定義了2個int型 就把空間覆蓋了導致輸出的是-33