好吧我的C有点生疏,但我想我会在C中制作我的下一个(小)项目,所以我可以对它进行修改,不到20行,我已经有了一个段错误。
这是我的完整代码:
#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]’
[][]
和**
真的不兼容指针类型吗?他们似乎只是我的语法。
答案 0 :(得分:36)
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
答案 1 :(得分:3)
当你做这个宣言时:
char main_map[ROWS][COLS+1]={
"a.bb",
"a.c.",
"adc.",
".dc."};
您可以创建一个char-array数组。 char-array只是一个字符块,而数组数组只是一个数组块 - 所以总的来说,main_map
只是一堆字符。它看起来像这样:
| 'a' | '.' | 'b' | 'b' | 0 | 'a' | '.' | 'c' | '.' | 0 | ... | 'd' | 'c' | '.' | 0 |
当你将main_map
传递给print_map()
时,它正在评估main_map
作为指向数组第一个元素的指针 - 所以这个指针指向那个内存块的开头。您强制编译器将其转换为char **
类型。
当您在函数中评估map[0]
时(例如,对于循环的第一次迭代),它会获取char *
指向的map
值。不幸的是,正如您从ASCII艺术中看到的那样,map
不指向char *
- 它指向一堆普通的char
。那里根本没有char *
值。此时,您会加载其中一些char
值(4或8,或其他一些数字,具体取决于您的平台上char *
的大小),并尝试将其解释为{{1} }值。
当char *
尝试遵循虚假puts()
值时,您会遇到分段错误。
答案 2 :(得分:1)
查看我的代码,我意识到列的数量是不变的,但实际上并不重要,因为它只是一个字符串。所以我改了它,所以main_map是一个字符串数组(呃,char指针)。这使得我可以使用**
来传递它:
char *main_map[ROWS]={
"a.bb",
"a.c.",
"adc.",
".dc."};