问一个 C 传固定大小数组(by reference)的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xzpjerry731
V2EX    C

问一个 C 传固定大小数组(by reference)的问题

  •  
  •   xzpjerry731 2018-04-19 07:43:57 +08:00 2981 次点击
    这是一个创建于 2773 天前的主题,其中的信息可能已经有所发展或是发生改变。

    假设我有个函数 foo:

    void foo(char ***buff, int size) { for(int i = 0; i != size; i++){ for(int j = 0; j != size; j++) { (*buff)[i][j] = 'a'; printf("%c\t", (*buff)[i][j]); } printf("\n"); } } 

    如果我给它传入一个动态 2d 数组的地址,一切安好:

    int main(){ static int size = 3; char **eg = (char**)malloc(size * sizeof(char*)); if(eg != NULL){ for(int i = 0; i != size; i++){ eg[i] = (char*)malloc(size * sizeof(char)); if(eg[i] == NULL){ for(int j = 0; j != i; j++) free(eg[j]); free(eg); exit(1); } } foo(&eg, size); } return 0; } 

    但是如果我给它传入一个固定大小的 2d 数组的地址时,就报 seg fault 了:

    int main(){ static int size = 3; char eg2[size][size]; foo(&eg2, size); return 0; } 

    请问哪里出了问题?

    15 条回复    2018-04-20 10:14:05 +08:00
    innoink
        1
    innoink  
       2018-04-19 08:11:05 +08:00 via Android   1
    因为数组名取地址并不是你想的那个结果
    gnaggnoyil
        2
    gnaggnoyil  
       2018-04-19 08:16:04 +08:00   3
    C 语言标准中只允许 T []的左值到 T *右值的转换,因此 char [][]和 char **没有五毛钱关系.换句话说,char (*)[][]和 char ***所指向的类型是 incompatible 的,强行指向同一个对象的后果是未定义行为.C++中 implicit conversion 的要求更严格,char (*)[][]强转 char ***的结果是 ill-formed.

    array to pointer decay 真是害死人啊(叹气
    tempdban
        3
    tempdban  
       2018-04-19 08:16:49 +08:00   1
    *(buff+i*size+j) = 'a';
    ghostheaven
        4
    ghostheaven  
       2018-04-19 08:30:41 +08:00 via Android   1
    二维数组是一个连续的内存空间,可以当成 NxN 的一维数组来看。数组指针的方式相当于第一维保存的是指针,指向每个第二维的数组开头。
    omph
        5
    omph  
       2018-04-19 08:34:28 +08:00   1
    ```C
    #include <stdio.h>

    int main(){
    char eg2[3][3] = {0};
    char ***q = &eg2;
    printf("eg2=%p\n", eg2);
    printf("q=%p\n", q);
    printf("*q=%p\n", *q);
    printf("**q=%p\n", **q);
    return 0;
    }
    ```
    owt5008137
        6
    owt5008137  
       2018-04-19 08:47:25 +08:00 via Android
    因为内存结构不一样
    Danswerme
        7
    Danswerme  
       2018-04-19 08:59:15 +08:00 via Android   1
    惊了,我才发现居然有 C++节点
    heiher
        8
    heiher  
       2018-04-19 09:54:34 +08:00   1
    其实在写动态分配版时就应该能发现问题呀,eg2[size][size] 对应的内存里怎么会有地址呢?
    wizardoz
        9
    wizardoz  
       2018-04-19 10:06:52 +08:00   1
    数组地址是常量,为啥要作为三指针传?
    另外,好像对数组名取地址还是一样的地址,所以你传进去的指针实际差了一层。
    wizardoz
        10
    wizardoz  
       2018-04-19 10:08:37 +08:00
    你这样试试看?

    int main(){
    static in size = 3;

    char eg2[size][size];
    char** tmp = eg2;

    foo(&tmp, size);
    return 0;
    }
    acros
        11
    acros  
       2018-04-19 10:10:25 +08:00   1
    C 不熟了
    只记得二维数组没出现过三个***的,但一时间没找到问题,看了楼上回复才恍然大悟。
    araraloren
        12
    araraloren  
       2018-04-19 13:12:29 +08:00   1
    ...
    ...
    Your index has out of bound!
    picasso2501
        13
    picasso2501  
       2018-04-19 13:22:31 +08:00   1
    a[M][N] 是 a[M*N]的语法糖
    seancheer
        14
    seancheer  
       2018-04-19 19:48:06 +08:00   1
    只传过一维的,不会有问题,二维的没试过。。不过楼上大佬说的对,c 里面数据和指针并不是一个东西。
    hackpro
        15
    hackpro  
       2018-04-20 10:14:05 +08:00   1
    @heiher #8 C99 之后 VLA 支持推迟到运行时
    @xzpjerry731 实际上你的问题在于:(*buff)[i][j] = 'a';
    buff 解引用之后是个 char **
    你这里直接用数组下标操作符[i] 相当于偏移一个 MACHINE WORD

    所以 @gnaggnoyil #2 说 [] -> * 一般没啥问题 反过来要掂量掂量
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5551 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 01:51 PVG 09:51 LAX 17:51 JFK 20:51
    Do have faith in what you're doing.
    ubao msn 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