2010-08-20 3 views
9

dada la función firma siguiente:¿Cuál es la razón por la que el compilador de C exige que se defina el número de columnas en una matriz de 2d?

void readFileData(FILE* fp, double inputMatrix[][], int parameters[]) 

esto no compila.

y corregida:

void readFileData(FILE* fp, double inputMatrix[][NUM], int parameters[]) 

mi pregunta es, ¿por qué se definirá las demandas del compilador que el número de columnas al manipular una matriz 2D en C? ¿Hay alguna manera de pasar una matriz 2D a una función con dimensiones desconocidas?

que

+0

Agregue el mensaje de error, el nombre del compilador y la versión a su pregunta. –

Respuesta

2

C no tiene ningún soporte específico para matrices multidimensionales. Una matriz bidimensional como double inputMatrix[N][M] es solo una matriz de longitud N cuyos elementos son matrices de longitud M de dobles.

Hay circunstancias en las que puede dejar fuera el número de elementos en un tipo de matriz. Esto da como resultado un tipo incompleto - un tipo cuyos requisitos de almacenamiento son desconocidos. Por lo tanto, puede declarar double vector[], que es una matriz de tamaño no especificado de dobles. Sin embargo, no puede colocar objetos de tipos incompletos en una matriz, porque el compilador necesita saber el tamaño del elemento cuando accede a los elementos. Por ejemplo, puede escribir double inputMatrix[][M], que declara una matriz de longitud no especificada cuyos elementos son matrices de longitud M de dobles. El compilador sabe entonces que la dirección de inputMatrix[i] es i*sizeof(double[M]) bytes más allá de la dirección de inputMatrix[0] (y por lo tanto la dirección de inputMatrix[i][j] es i*sizeof(double[M])+j*sizeof(double) bytes). Tenga en cuenta que necesita saber el valor de M; esta es la razón por la que no puede dejar M en la declaración de inputMatrix.

Una consecuencia teórica de cómo se presentan las matrices es que inputMatrix[i][j] denota la misma dirección que inputMatrix + M * i + j

Una consecuencia práctica de esta disposición es que, para un código eficiente, se debe organizar las matrices de manera que la dimensión que varía más a menudo viene último. Por ejemplo, si tiene un par de bucles anidados, hará un mejor uso de la memoria caché con for (i=0; i<N; i++) for (j=0; j<M; j++) ... que con bucles anidados al revés. Si necesita cambiar entre el acceso a la fila y el acceso a la columna a mitad del programa, puede ser beneficioso transponer la matriz (lo que se hace mejor bloque por bloque en lugar de columnas o líneas).

C89 referencias: §3.5.4.2 (tipos de matriz), §3.3.2.1 (expresiones subíndice de matriz)
C99 referencias: §6.7.5.2 (tipos de matriz), §6.5.2.1-3 (expresiones subíndice de matriz) .

¹ Demostrar que esta expresión está bien definida se deja como un ejercicio para el lector. No es muy claro si inputMatrix[0][M] es una forma válida de acceder al inputMatrix[1][0], aunque sería extremadamente difícil para una implementación marcar la diferencia.

1

gracias Esto es porque en la memoria, esto es sólo un área contigua, una matriz de una sola dimensión si se quiere. Y para obtener el desplazamiento real de inputMatrix [x] [y], el compilador debe calcular (x * elementsPerColumn) + y. Por lo tanto, necesita saber elementsPerColumn y eso a su vez significa que necesita contarlo.

5

Como la matriz en C es pura memoria sin ninguna meta información sobre dimensiones, el compilador necesita saber cómo aplicar el índice de fila y columna cuando se dirige a un elemento de su matriz.

inputMatrix[i][j] se traduce internamente en algo equivalente a *(inputMatrix + i * NUM + j)

y aquí puede ver lo que se necesita NUM.

+0

+1: Buena explicación y definitivamente ayuda a usar 'NUM' como el tamaño para que coincida con la pregunta original. – DrAl

1

No, no hay. La situación es realmente simple: lo que la función recibe en realidad es solo un bloque lineal y único de memoria. Decirle el número de columnas le dice cómo traducir algo como block[x][y] en una dirección lineal en el bloque (es decir, necesita hacer algo como address = row * column_count + column).

18

Los arreglos multi-deminíferos incorporados en C (y en C++) se implementan utilizando el enfoque de "index-translation". Esto significa que la matriz 2D (3D, 4D, etc.) se presenta en la memoria como una matriz ordinaria 1D de tamaño suficiente, y el acceso a los elementos de dicha matriz se implementa recalculando los índices multidimensionales en un índice 1D correspondiente. Por ejemplo, si se define una matriz 2D de tamaño M x N

double inputMatrix[M][N] 

en la realidad, bajo el capó, el compilador crea una matriz de tamaño M * N

double inputMatrix_[M * N]; 

Cada vez que acceda al elemento de la matriz

inputMatrix[i][j] 

el compilador traduce en

inputMatrix_[i * N + j] 

Como puede ver, para realizar la traducción el compilador debe saber N, pero realmente no necesita saber M. Esta fórmula de traducción puede generalizarse fácilmente para matrices con cualquier cantidad de dimensiones. Implicará todos los tamaños de la matriz multidimensional excepto la primera. Esta es la razón por la que cada vez que declaras una matriz, debes especificar todos los tamaños excepto el primero.

+0

Buena explicación. Hubo un período en el que solía escribir código C con mis matrices aplanadas a medida que se ejecutaba más rápido hasta que comencé a compilar con -O2, desde donde el GCC hizo esa parte para mí y pude empezar a escribir código legible de nuevo \ o / –

1

Otras personas han explicado por qué, pero la forma de pasar una matriz 2D con dimensiones desconocidas es pasar un puntero.El compilador degrada los parámetros de matriz a punteros de todos modos. Solo asegúrese de que esté claro lo que espera en sus documentos API.

Cuestiones relacionadas