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

2018-04-19 07:43:57 +08:00
 xzpjerry731

假设我有个函数 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;
}

请问哪里出了问题?

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

array to pointer decay 真是害死人啊(叹气
tempdban
2018-04-19 08:16:49 +08:00
*(buff+i*size+j) = 'a';
ghostheaven
2018-04-19 08:30:41 +08:00
二维数组是一个连续的内存空间,可以当成 NxN 的一维数组来看。数组指针的方式相当于第一维保存的是指针,指向每个第二维的数组开头。
omph
2018-04-19 08:34:28 +08:00
```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
2018-04-19 08:47:25 +08:00
因为内存结构不一样
Danswerme
2018-04-19 08:59:15 +08:00
惊了,我才发现居然有 C++节点
heiher
2018-04-19 09:54:34 +08:00
其实在写动态分配版时就应该能发现问题呀,eg2[size][size] 对应的内存里怎么会有地址呢?
wizardoz
2018-04-19 10:06:52 +08:00
数组地址是常量,为啥要作为三指针传?
另外,好像对数组名取地址还是一样的地址,所以你传进去的指针实际差了一层。
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
2018-04-19 10:10:25 +08:00
C 不熟了····
只记得二维数组没出现过三个***的,但一时间没找到问题,看了楼上回复才恍然大悟。
araraloren
2018-04-19 13:12:29 +08:00
...
...
Your index has out of bound!
picasso2501
2018-04-19 13:22:31 +08:00
a[M][N] 是 a[M*N]的语法糖
seancheer
2018-04-19 19:48:06 +08:00
只传过一维的,不会有问题,二维的没试过。。不过楼上大佬说的对,c 里面数据和指针并不是一个东西。
hackpro
2018-04-20 10:14:05 +08:00
@heiher #8 C99 之后 VLA 支持推迟到运行时
@xzpjerry731 实际上你的问题在于:(*buff)[i][j] = 'a';
buff 解引用之后是个 char **
你这里直接用数组下标操作符[i] 相当于偏移一个 MACHINE WORD

所以 @gnaggnoyil #2 说 [] -> * 一般没啥问题 反过来要掂量掂量

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

https://www.v2ex.com/t/448011

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

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

© 2021 V2EX