V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xzpjerry731
V2EX  ›  C

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

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

    假设我有个函数 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 int 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   ·   实用小工具   ·   1186 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 18:02 · PVG 02:02 · LAX 10:02 · JFK 13:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.