C语言return数组的问题

2012-12-05 12:56:03 +08:00
 gracehunter
char* funA(){
char A[] = "Hello, world.";
return A;
}

这样写有什么问题吗?
5659 次点击
所在节点    问与答
18 条回复
yuelang85
2012-12-05 12:56:57 +08:00
??楼主想说啥?
gracehunter
2012-12-05 13:00:07 +08:00
@yuelang85 刚才不小心点了发布,现在改好了
vampirekiss
2012-12-05 13:10:23 +08:00
返回了一个指向临时变量的指针,当函数执行完时,A会被销毁,指针指向的内容是未知的。
laskuma
2012-12-05 13:44:58 +08:00
local variable的scope只到本function结尾。之后就失效。如果stack再次增长的话会被覆盖成奇怪的东西。
改成
char* funA()
{
char *b = "Hello, world.";
char *a = (char *)malloc(sizeof(char) * strlen(b));
strcpy(a, b);
return a;
}
ShadowStar
2012-12-05 14:11:57 +08:00
局部变量存储于栈空间,函数调用返回后就会失效,被其他函数复用相同栈空间。

但是!对于@gracehunter 以及@laskuma 的代码来说,是可以的。
因为对于""中的字符串会被编码在.rodata段,是静态存储的,返回的是这个字符串的地址。
raptium
2012-12-05 14:51:08 +08:00
@laskuma malloc 的時候長度要加 1 吧,不然 a 最後的 '\0' 可能寫到外面去了
laskuma
2012-12-05 21:42:57 +08:00
@ShadowStar LZ的方法不行
raptium
2012-12-05 22:23:19 +08:00
@ShadowStar 本來我以為你這麼說是對的
但是看了一下 gcc -S 編譯出來的 asm 似乎不是這樣
"hello world" 不是在 .rodata 段的,而是直接四句 mov 寫到 stack 上的(一句 mov 可以過去 4 個字符),所以返回是會出問題的
於是我想可能是字符串太短了,嘗試把 hello world 改成一個很長很長的字符串,這樣編譯出來字符串的確保存在 .rodata 段了。但是,再看一下後面代碼很長,基本就是好不容易算出來了兩個指針地址,然後用 rep movsd 把 .rodata 裏的數據複製到了 A 的位置,所以還是在 stack 上。
綜上,樓主怎麼寫是不行的。
magicsilence
2012-12-06 01:07:46 +08:00
@raptium 是在.rodata段中, gcc 4.6
-----
[lithium@ubuntu:~/code/gcc/test]
> cat t.c
#include <stdio.h>

char* t() {
char* p = "this is a test prog";
return p;
}

int main(int argc, char *argv[]) {
char* p = t();

printf("Addr p: %x\n", p);
return 0;
}


[lithium@ubuntu:~/code/gcc/test]
> ./a.out
Addr p: 40063c
[lithium@ubuntu:~/code/gcc/test]
> objdump -hs a.out | grep ".rodata" -3
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .fini 0000000e 0000000000400628 0000000000400628 00000628 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .rodata 00000024 0000000000400638 0000000000400638 00000638 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
15 .eh_frame_hdr 00000034 000000000040065c 000000000040065c 0000065c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
--
400620 83c4085b 5dc39090 ...[]...
Contents of section .fini:
400628 4883ec08 e82ffeff ff4883c4 08c3 H..../...H....
Contents of section .rodata:
400638 01000200 74686973 20697320 61207465 ....this is a te
400648 73742070 726f6700 41646472 20703a20 st prog.Addr p:
400658 25780a00 %x..
dhysum
2012-12-06 02:18:53 +08:00
@raptium 分配的内存是在堆上的。
timonwong
2012-12-06 02:51:17 +08:00
@magicsilence
字符数组应该是不保证一定在.rodata上的,尤其A还定义的还是个可写的数组。

你的代码展示的是 指向string literal的字符串指针,由于GCC默认就开了string pooling,应该是直接放到.rodata段中的,其它不默认开string pooling的编译器(比如MSVC),结果就很难说了。
raptium
2012-12-06 11:05:57 +08:00
@magicsilence 是在 rodata 上有 但是返回的时候会先整段复制到栈里 然后返回栈地址
clowwindy
2012-12-06 11:11:15 +08:00
养成好习惯,const char *
raptium
2012-12-06 11:18:11 +08:00
@magicsilence 不對,剛在車上沒細看
你的程序和樓主的不一樣 char *p = "...." 和 char p[] = "...." 不是一個意思
你這個直接返回指向 .rodata 的地址就行了
chap p[] 會在棧上分配空間的
raptium
2012-12-06 11:20:15 +08:00
@dhysum malloc 的會在堆上,如果只是局部變量 char A[] 那就是在棧上
ShadowStar
2012-12-06 12:28:37 +08:00
@raptium 抱歉,我确实有点想当然了。
因为Mac自带的toolchain没有objdump等工具,所以我只能用mips64的toolchain验证一下。
/tmp % cat c.c
#include <stdio.h>
#include <stdlib.h>
char* funA(){
char A[] = "Hello, world.";
return A;
}
int main ( int argc, char *argv[] )
{
printf("%s\n", funA());
return EXIT_SUCCESS;
}
/* ---- end of function main ---- */
/tmp % mips64-octeon-linux-gnu-gcc -O2 -o c c.c
c.c: In function 'funA':
c.c:6: warning: function returns address of local variable
/tmp % mips64-octeon-linux-gnu-objdump -s c | sed -n '/\.rodata/,/Contents/p'
Contents of section .rodata:
120000b40 00020001 00000000 48656c6c 6f2c2077 ........Hello, w
120000b50 6f726c64 2e000000 orld....
Contents of section .interp:
/tmp %
magicsilence
2012-12-06 13:50:51 +08:00
@raptium 嗯,对, char* 和char []分配的不一样。我贴的代码和楼主的意思有差了。

@ShadowStar 这个结果重现不出来,猜测是不是gcc版本导致的?
timonwong
2012-12-06 14:51:26 +08:00
@magicsilence
我是不加-O优化选项就能看到
这种未定义行为,重现了也没有什么意义就是了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/54136

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX