кастинг символа [] [] для обугливания ** вызывает 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;
}

Я полностью смущен относительно того, как это вызывает segfault. От чего происходит при кастинге [][] кому: **!? Это - единственное предупреждение, что я добираюсь.

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]’

[][] и ** действительно не совместимые типы указателей? Они кажутся, что они - просто синтаксис мне.

8
задан Earlz 24 May 2010 в 07:29
поделиться

3 ответа

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" |
             +---------------+

Хотя a 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
36
ответ дан 5 December 2019 в 04:49
поделиться

Глядя на свой код, я понял, что количество столбцов постоянно, но на самом деле это не имеет значения, потому что это просто строка. Поэтому я изменил его так, что main_map - это массив строк (э-э, указатели на символы). Благодаря этому я могу просто использовать ** для его передачи:

char *main_map[ROWS]={
  "a.bb",
  "a.c.",
  "adc.",
  ".dc."};
1
ответ дан 5 December 2019 в 04:49
поделиться

Когда вы делаете это объявление:

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

Вы создаете массив массивов символов. Array-of-char - это просто блок символов, а array-of-array - это просто блок массивов, так что в целом main_map - это просто целая куча символов. Это выглядит так:

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

Когда вы передаете main_map в print_map () , он оценивает main_map как указатель на первый элемент массива - поэтому этот указатель указывает на начало этого блока памяти. Вы заставляете компилятор преобразовать это в тип char ** .

Когда вы оцениваете карту [0] внутри функции (например, для первой итерации цикла), она выбирает значение char * , на которое указывает карта . К сожалению, как вы можете видеть из ASCII-арта, map не указывает на char * - он указывает на набор простых char ] с. Здесь вообще нет значений char * . На этом этапе вы загружаете некоторые из этих значений char (4 или 8 или какое-то другое число в зависимости от размера char * на вашей платформе) и пытаетесь интерпретировать их как значение char * .

Когда put () затем пытается следовать за этим фиктивным значением char * , вы получаете ошибку сегментации.

3
ответ дан 5 December 2019 в 04:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: