2010-05-24 30 views
8

Ok mi C está un poco oxidado pero pensé que haría mi próximo (pequeño) proyecto en C para poder pulir de nuevo en él y menos de 20 líneas en que ya tengo un fallo seg.casting char [] [] a char ** provoca segfault?

Este es mi código completo:

#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; 
} 

estoy completamente confundido en cuanto a cómo esto está causando una violación de segmento. ¿Qué sucede cuando se lanzan desde el [][] al **? Esa es la única advertencia que recibo.

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

son [][] y realmente no ** tipos de puntero compatible? Parecen que son solo sintaxis para mí.

+2

"Tipos de punteros no compatibles"? ¿Qué quieres decir? Su tipo '[] []' es un tipo * array *, no un tipo de puntero. ¿Por qué te refieres a '[] []' como un tipo de puntero ??? – AnT

+0

@Andrey es una gran brecha obvia en mi conocimiento de C. Entiendo completamente los punteros pero no las matrices. :) – Earlz

Respuesta

35

A char[ROWS][COLS+1] no se puede convertir en char**. El argumento de entrada de print_map debe ser

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

o

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

la diferencia de que un char** significa para apuntar a algo que puede ser dereferenced así:

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

Mientras que un char(*)[n] es un punto a una regio de memoria continua n como esta

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

Si se trata a un (char(*)[5]) como (char**) se obtiene de basura:

(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

Eso es un poco feo:/o tal vez estoy arruinado por otros idiomas .. – Earlz

+0

Gracias por actualizar su pregunta con una explicación de por qué :) Ahora estoy confundido para que la respuesta es mejor aunque – Earlz

+6

+1 para el lindo ascii-art y el puntero a array. –

1

Mirando mi código que se dio cuenta de que la cantidad de columnas es constante, pero en realidad no importa porque es solo una cadena. Así que lo cambié así que main_map es una matriz de cadenas (er, char punteros). Esto hace que sea por lo que sólo puede utilizar ** para pasar alrededor también:

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

Al hacer esta declaración:

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

se crea una matriz de-arrays-de-char. Una matriz de caracteres es solo un bloque de caracteres, y una matriz de matrices es solo un bloque de matrices, por lo que, en general, main_map es solo un montón de caracteres. Se ve así:

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

Cuando se pasa a main_mapprint_map(), que está evaluando main_map como un puntero al primer elemento de la matriz - por lo que este indicador está señalando en el inicio de ese bloque de memoria. Fuerza al compilador a convertir esto al tipo char **.

Cuando evalúa map[0] dentro de la función (por ejemplo, para la primera iteración del ciclo), obtiene el valor char * apuntado por map.Desafortunadamente, como se puede ver en ASCII-art, mapno indica a char * - apunta a un grupo de char s simples. No hay ningún valor de char * allí. En este punto, carga algunos de esos valores char (4, u 8, o algún otro número dependiendo de cuán grande sea char * en su plataforma) y trate de interpretarlos como un valor char *.

Cuando puts() intenta seguir ese valor falso char *, obtiene su error de segmentación.

+0

Esto era lo que yo quería. Fue una explicación no solo una solución rápida. Gracias por eso :) – Earlz