2010-03-29 19 views
9

tengo la función con firma siguiente:puntero incompatible tipo

void box_sort(int**, int, int) 

y variable de tipo siguiente:

int boxes[MAX_BOXES][MAX_DIMENSIONALITY+1] 

Cuando yo estoy llamando a la función

box_sort(boxes, a, b) 

GCC me da dos advertencias:

103.c:79: warning: passing argument 1 of ‘box_sort’ from incompatible pointer type (string where i am calling the function) 
103.c:42: note: expected ‘int **’ but argument is of type ‘int (*)[11] (string where the function is defined) 

La pregunta es ¿por qué? Si int x [] [] e int ** x (y en realidad int * x []) no son los mismos tipos en C?

+0

¿Qué son 'MAX_BOXES' y' MAX_DIMENSIONALITY'? ¿Son macros, constantes, ...? – Jacob

Respuesta

13

Sé que hubo una pregunta casi así hace un par de días ... pero ahora no puedo encontrarla.

La respuesta es int[size][] (ver nota en la parte inferior) y int** definitivamente no son del mismo tipo. Puede usar int[] y int* indistintamente en muchos casos, en particular en casos como este porque la matriz decae a un puntero al primer elemento cuando lo pasa a una función. Pero para una matriz bidimensional, estos son métodos de almacenamiento muy diferentes.

Esto es lo que se verían al igual que en la memoria para una matriz de 2x2:

int a[2][2]: 

__a[0][0]__|__a[0][1]__|__a[1][0]__|__a[1][1]__ 
    (int)  (int)  (int)  (int) 

int **a (e.g. dynamically allocated with nested mallocs) 

__a__ 
(int**) 
    | 
    v 
__a[0]__|__a[1]__ 
    (int*) (int*) 
    |  | 
    |  | 
    v  ------------------> 
__a[0][0]__|__a[0][1]__  __a[1][0]__|__a[1][1]__ 
    (int)  (int)    (int)  (int) 

Se podría construir el segundo uno como este:

int **a = malloc(2 * sizeof(int*)); 
a[0] = malloc(2 * sizeof(int)); 
a[1] = malloc(2 * sizeof(int)); 

Nota: Como otros han señalado, int[][] ISN no es un tipo real; solo uno de los tamaños puede ser no especificado. Pero el núcleo de la pregunta aquí es si una matriz bidimensional y una doble puntero son la misma cosa.

+0

Cool ASCII-art, pero creo que tiene el primer índice incorrecto para los cuadros señalados por la flecha. –

+0

@RaphaelISP: Gracias, simplemente un error de copiado, obviamente. – Cascabel

+0

Me gusta la explicación visual. Sin embargo, me pregunto si han permitido que * y [] funcionen de forma intercambiable, ¿por qué no para * {n} y [] {n}? ¿Simplemente fue demasiado difícil? – NomeN

1

Nunca construyó una serie de punteros como lo requiere la firma.

Hay dos formas de hacer matrices 2D en C. En un caso, simplemente tiene mucho de lo que se necesita y al compilador se le informa cuáles son las dimensiones. Calcula el comienzo de la fila al multiplicar el índice de la fila por el número de columnas y luego agrega el índice de la columna para encontrar el elemento dentro de esa fila.

La otra forma es con un vector de punteros, donde el compilador simplemente elimina la referencia del vector para encontrar el comienzo de la fila, pero el compilador no hará esto automáticamente, tiene que hacerlo usted mismo.

Su objeto real es uno de los primeros, pero su prototipo de función está solicitando el segundo tipo.

Por lo tanto, debe cambiar el prototipo para que coincida con el objeto o construir un vector de punteros de fila para pasar a la función.

+1

Bien explicado, DigitalRoss. Para obtener más información, consulte también http://c-faq.com/aryptr/index.html –

1

No existe ningún tipo en C como int[][], solo la primera parte de una matriz multidimensional puede no especificarse. Entonces int[][5] está bien.

Además de las otras respuestas publicadas aquí, si se puede usar C99, puede utilizar matrices de variables para lograr lo que desea:

void box_sort(int N, int M, int x[M][N]); 

Esto funcionará en la mayoría de las plataformas excepto Visual C++ de Microsoft.

0

Cuando aparece una expresión de matriz en la mayoría de contextos, su tipo se convierte implícitamente de "N-elemento matriz de T" a "puntero a T", y su valor se establece en la dirección del primer elemento en la matriz. Las excepciones a esta regla son cuando la expresión de matriz es un operando de los operadores sizeof o address-of (&), o si la expresión de matriz es un literal de cadena que se utiliza para inicializar otra matriz en una declaración.

Lo que esto significa en el contexto de su código es que en su llamada a box_sort, el tipo de la expresión boxes se convierte implícitamente de M-element array of N-element array of int a pointer to N-element array of int, o int (*)[MAX_DIMENSIONALITY+1], por lo que su función debe estar esperando tipos de parámetros como:

void box_sort(int (*arr)[MAX_DIMENSIONALITY+1], int x, int y) 
{ 
    ... 
} 

Desde int *a y int a[] son sinónimos de una declaración de parámetros de función, se deduce que int (*a)[N] es sinónimo de int a[][N], por lo que podría escribir lo anterior como

void box_sort(int arr[][MAX_DIMENSIONALITY+1], int x, int y) 
{ 
} 

aunque personalmente prefiero la notación del puntero, ya que refleja con mayor precisión lo que está sucediendo. Tenga en cuenta que en su función, que le subíndice arr como normales:

arr[x][y] = ...; 

ya que la expresión es equivalente a arr[x]*(arr + x), el puntero se elimina la referencia implícita.

Si desea box_sort para trabajar en matrices arbitraria de tamaño (es decir, matrices, donde la segunda dimensión no es necesariamente MAX_DIMENSIONALITY + 1), a continuación, un enfoque consiste en hacer lo siguiente:

int boxes[X][Y]; 
... 
box_sort (&boxes[0], X, Y, x, y); 
... 
void box_sort(int *arr, size_t rows, size_t cols, int x, int y) 
{ 
    ... 
    arr[x*cols + y] = ...; 
} 

Básicamente, está tratando boxes como una matriz de 1-d de int y calculando los desplazamientos manualmente.

Cuestiones relacionadas