2010-05-24 64 views
8

好吧,我的C有点生疏,但我想我会在C下做我的下一个(小)项目,所以我可以重新打磨它,少于20行我已经有一个seg故障。铸造char [] []为char **会导致段错误?

这是我的完整代码:

#define ROWS 4 
#define COLS 4 

char main_map[ROWS][COLS+1]={ 
    "a.bb", 
    "a.c.", 
    "adc.", 
    ".dc."}; 

void print_map(char** map){ 
    int i; 
    for(i=0;i<ROWS;i++){ 
    puts(map[i]); //segfault here 
    } 
} 



int main(){ 
    print_map(main_map); //if I comment out this line it will work. 
    puts(main_map[3]); 
    return 0; 
} 

我完全困惑,这是怎么造成段错误。当从[][]投射到**时发生了什么?!这是我得到的唯一警告。

 
rushhour.c:23:3: warning: passing argument 1 of ‘print_map’ from incompatible pointer type 
rushhour.c:13:7: note: expected ‘char **’ but argument is of type ‘char (*)[5]’ 

[][]**真的不兼容的指针类型?他们看起来像他们只是我的语法。

+2

“不兼容的指针类型”?你什么意思?你的'[] []'类型是*数组类型,而不是指针类型。你为什么将'[] []'作为指针类型? – AnT 2010-05-24 07:48:06

+0

@Andrey这是我C语言知识中一个巨大的巨大差距。我完全理解指针,但不是数组。 :) – Earlz 2010-05-24 07:53:15

回答

35

A char[ROWS][COLS+1]不能投入char**。的print_map输入参数应该是

void print_map(char map[][COLS+1]) 

void print_map(char (*map)[COLS+1]) 

的区别在于,一个char**意味着指向的东西,可以解除引用这样的:

(char**)map 
     | 
     v 
    +--------+--------+------+--------+-- ... 
    | 0x1200 | 0x1238 | NULL | 0x1200 | 
    +----|---+----|---+--|---+----|---+-- ... 
     v  |  =  | 
    +-------+ |    | 
    | "foo" | <-----------------' 
    +-------+ | 
       v 
      +---------------+ 
      | "hello world" | 
      +---------------+ 

char(*)[n]是指向连续内存区域ñ这样

(char(*)[5])map 
     | 
     v 
    +-----------+---------+---------+-------------+-- ... 
    | "foo\0\0" | "hello" | " worl" | "d\0\0\0\0" | 
    +-----------+---------+---------+-------------+-- ... 

如果治疗(char(*)[5])作为(char**)你会得到垃圾:

(char**)map 
     | 
     v 
    +-----------+---------+---------+-------------+-- ... 
    | "foo\0\0" | "hello" | " worl" | "d\0\0\0\0" | 
    +-----------+---------+---------+-------------+-- ... 
     force cast (char[5]) into (char*): 
    +----------+------------+------------+------------+-- ... 
    | 0x6f6f66 | 0x6c686500 | 0x77206f6c | 0x646c726f | 
    +----|-----+---------|--+------|-----+------|-----+-- ... 
     v    |   |   | 
    +---------------+ |   |   v 
    | "hsd®yœâñ~22" | |   |  launch a missile 
    +---------------+ |   | 
         v   v 
       none of your process memory 
         SEGFAULT 
+0

虽然这有点丑:/或者我只是被其他语言宠坏了.. – Earlz 2010-05-24 07:37:31

+0

感谢您更新您的问题,并解释为什么:)现在我很困惑,哪个答案更好,但 – Earlz 2010-05-24 07:51:42

+6

+1可爱的ascii艺术和指向数组的指针。 – 2010-05-24 08:07:55

1

看着我的代码,我意识到,列的数量是恒定的,但它实际上并没有此事因为它只是一个字符串。所以我改变它,所以main_map是一个字符串数组(呃,字符指针)。这使得它,所以我可以只使用**周边的传递也:

char *main_map[ROWS]={ 
    "a.bb", 
    "a.c.", 
    "adc.", 
    ".dc."}; 
3

当你这样做的声明:

char main_map[ROWS][COLS+1]={ 
    "a.bb", 
    "a.c.", 
    "adc.", 
    ".dc."}; 

您创建一个数组,数组-的炭的。一个字符数组只是一个字符块,而一个数组数组只是一个数组块 - 所以整体来说,main_map只是一堆字符。它看起来像这样:

| 'a' | '.' | 'b' | 'b' | 0 | 'a' | '.' | 'c' | '.' | 0 | ... | 'd' | 'c' | '.' | 0 | 

当传递到main_mapprint_map(),它是评估main_map作为指针到所述阵列的所述第一元件 - 所以该指针是在该存储器块的开始指向。您强制编译器将其转换为char **类型。

当您在函数内(例如,对于循环的第一次迭代)评估map[0]时,它会提取map指向的char *值。不幸的是,从ASCII艺术中可以看出,map不是指向char * - 它指向一堆普通的char s。根本没有char *的值。此时,您将加载一些char值(4或8或其他数字,具体取决于您的平台上有多大的char *),并尝试将其解释为char *的值。

puts()然后试图跟随那个虚假char *价值,你会得到你的分段错误。

+0

这就是我想要的。是一个解释不只是一个快速解决。感谢那 :) – Earlz 2010-05-24 07:48:41