[英]casting char[][] to char** causes segfault?
好吧我的C有點生疏,但我想我會在C中制作我的下一個(小)項目,所以我可以對它進行修改,不到20行,我已經有了一個seg錯誤。
這是我的完整代碼:
#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]’
[][]
和**
真的不兼容指針類型嗎? 他們似乎只是我的語法。
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
當你做這個聲明時:
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]
(例如,對於循環的第一次迭代),它會獲取map
指向的char *
值。 不幸的是,正如你從ASCII藝術中看到的那樣, map
並沒有指向一個char *
- 它指向一堆普通的char
。 那里根本沒有char *
值。 此時,您將加載其中一些char
值(4或8,或其他一些數字,具體取決於您的平台上char *
大小),並嘗試將其解釋為char *
值。
當puts()
嘗試遵循偽造的char *
值時,就會出現分段錯誤。
看着我的代碼,我意識到列的數量是不變的,但它實際上並不重要,因為它只是一個字符串。 所以我改了它,所以main_map是一個字符串數組(呃,char指針)。 這使得我可以使用**
來傳遞它:
char *main_map[ROWS]={
"a.bb",
"a.c.",
"adc.",
".dc."};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.