C语言return数组的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gracehunter
V2EX    问与答

C语言return数组的问题

  •  
  •   grachunter 2012-12-05 12:56:03 +08:00 5952 次点击
    这是一个创建于 4694 天前的主题,其中的信息可能已经有所发展或是发生改变。
    char* funA(){
    char A[] = "Hello, world.";
    return A;
    }

    这样写有什么问题吗?
    18 条回复    1970-01-01 08:00:00 +08:00
    yuelang85
        1
    yuelang85  
       2012-12-05 12:56:57 +08:00
    ??楼主想说啥?
    gracehunter
        2
    gracehunter  
    OP
       2012-12-05 13:00:07 +08:00
    @yuelang85 刚才不小心点了发布,现在改好了
    vampirekiss
        3
    vampirekiss  
       2012-12-05 13:10:23 +08:00
    返回了一个指向临时变量的指针,当函数执行完时,A会被销毁,指针指向的内容是未知的。
    laskuma
        4
    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
        5
    ShadowStar  
       2012-12-05 14:11:57 +08:00
    局部变量存储于栈空间,函数调用返回后就会失效,被其他函数复用相同栈空间。

    但是!对于@gracehunter 以及@laskuma 的代码来说,是可以的。
    因为对于""中的字符串会被编码在.rodata段,是静态存储的,返回的是这个字符串的地址。
    raptium
        6
    raptium  
       2012-12-05 14:51:08 +08:00
    @laskuma malloc 的候度要加 1 吧,不然 a 最後的 '\0' 可能到外面去了
    laskuma
        7
    laskuma  
       2012-12-05 21:42:57 +08:00
    @ShadowStar LZ的方法不行
    raptium
        8
    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
        9
    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
        10
    dhysum  
       2012-12-06 02:18:53 +08:00
    @raptium 分配的内存是在堆上的。
    timonwong
        11
    timonwong  
       2012-12-06 02:51:17 +08:00
    @magicsilence
    字符数组应该是不保证一定在.rodata上的,尤其A还定义的还是个可写的数组。

    你的代码展示的是 指向string literal的字符串指针,由于GCC默认就开了string pooling,应该是直接放到.rodata段中的,其它不默认开string pooling的编译器(比如MSVC),结果就很难说了。
    raptium
        12
    raptium  
       2012-12-06 11:05:57 +08:00
    @magicsilence 是在 rodata 上有 但是返回的时候会先整段复制到栈里 然后返回栈地址
    clowwindy
        13
    clowwindy  
       2012-12-06 11:11:15 +08:00
    养成好习惯,const char *
    raptium
        14
    raptium  
       2012-12-06 11:18:11 +08:00
    @magicsilence 不,在上看
    你的程序和主的不一 char *p = "...." 和 char p[] = "...." 不是一意思
    你直接返回指向 .rodata 的地址就行了
    chap p[] 在上分配空的
    raptium
        15
    raptium  
       2012-12-06 11:20:15 +08:00
    @dhysum malloc 的在堆上,如果只是局部量 char A[] 那就是在上
    ShadowStar
        16
    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
        17
    magicsilence  
       2012-12-06 13:50:51 +08:00
    @raptium 嗯,对, char* 和char []分配的不一样。我贴的代码和楼主的意思有差了。

    @ShadowStar 这个结果重现不出来,猜测是不是gcc版本导致的?
    timonwong
        18
    timonwong  
       2012-12-06 14:51:26 +08:00
    @magicsilence
    我是不加-O优化选项就能看到
    这种未定义行为,重现了也没有什么意义就是了。
    关于   &nbp; 帮助文档     自助推广系统     博客     API     FAQ     Solana     2712 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 12:06 PVG 20:06 LAX 05:06 JFK 08:06
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86