GCC: el tipo de matriz tiene un tipo de elemento incompleto

6 minutos de lectura

avatar de usuario
Joshua Soileau

he declarado un structy trato de pasar una matriz de esas estructuras (así como una double matriz de dobles y un entero) en una función. obtengo un “el tipo de matriz tiene un tipo de elemento incompleto” mensaje de gcc cuando lo compilo. ¿En qué me equivoqué al pasar el struct a la función?

typedef struct graph_node {
  int X;
  int Y;
  int active;
} g_node;

void print_graph(g_node graph_node[], double weight[][], int nodes);

yo tambien he probado struct g_node graph_node[]pero me sale lo mismo.

avatar de usuario
jonathan leffler

Es la matriz la que está causando problemas en:

void print_graph(g_node graph_node[], double weight[][], int nodes);

La segunda y siguientes dimensiones deben darse:

void print_graph(g_node graph_node[], double weight[][32], int nodes);

O simplemente puede dar un puntero a puntero:

void print_graph(g_node graph_node[], double **weight, int nodes);

Sin embargo, aunque se ven similares, son muy diferentes internamente.

Si usa C99, puede usar arreglos calificados de forma variable. Citando un ejemplo del estándar C99 (sección §6.7.5.2 Array Declarators):

void fvla(int m, int C[m][m]); // valid: VLA with prototype scope

void fvla(int m, int C[m][m])  // valid: adjusted to auto pointer to VLA
{
    typedef int VLA[m][m];     // valid: block scope typedef VLA
    struct tag {
        int (*y)[n];           // invalid: y not ordinary identifier
        int z[n];              // invalid: z not ordinary identifier
    };
    int D[m];                  // valid: auto VLA
    static int E[m];           // invalid: static block scope VLA
    extern int F[m];           // invalid: F has linkage and is VLA
    int (*s)[m];               // valid: auto pointer to VLA
    extern int (*r)[m];        // invalid: r has linkage and points to VLA
    static int (*q)[m] = &B;   // valid: q is a static block pointer to VLA
}

pregunta en comentarios

[…] En mi main(), la variable que intento pasar a la función es una double array[][], entonces, ¿cómo pasaría eso a la función? Paso array[0][0] en él me da un tipo de argumento incompatible, al igual que &array y &array[0][0].

En tus main()la variable debe ser:

double array[10][20];

o algo levemente similar; quizás

double array[][20] = { { 1.0, 0.0, ... }, ... };

Debería poder pasar eso con un código como este:

typedef struct graph_node
{
    int X;
    int Y;
    int active;
} g_node;

void print_graph(g_node graph_node[], double weight[][20], int nodes);

int main(void)
{
    g_node g[10];
    double array[10][20];
    int n = 10;

    print_graph(g, array, n);
    return 0;
}

Eso compila (al código objeto) limpiamente con GCC 4.2 (i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Basado en Apple Inc. compilación 5658) (LLVM compilación 2336.9.00)) y también con GCC 4.7.0 en Mac OS X 10.7.3 usando la línea de comando:

/usr/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c zzz.c

  • Esto es exactamente lo que necesitaba, se compila muy bien con esto. Tengo otra pregunta, en mi principal (), la variable que estoy tratando de pasar a la función es una ‘matriz doble[][]’, entonces, ¿cómo pasaría eso a la función? matriz de paso[0][0] en él me da un tipo de argumento incompatible, al igual que &array y &array[0][0].

    – Joshua Soileau

    4 de abril de 2012 a las 0:51

  • +1 Gran respuesta. También podría valer la pena mencionar que el argumento de la función double weight[][10] es lo mismo que double (*weight)[10]dado que los argumentos de matriz en las declaraciones de función se tratan como punteros al primer elemento (razón por la cual no necesita proporcionar el tamaño de la primera dimensión) C89 §6.7.1, probablemente en una ubicación similar en C99.

    – Timoteo Jones

    4 de abril de 2012 a las 1:26

El compilador necesita saber el tamaño de la segunda dimensión en su matriz bidimensional. Por ejemplo:

void print_graph(g_node graph_node[], double weight[][5], int nodes);

Publicar esto en caso de que alguien se encuentre con esta pregunta y se pregunte sobre las razones formales por las que [] obras y [][] no lo hace, en general. Hay varias reglas en juego: las reglas de lo que hace que una declaración de matriz sea válida y las reglas de cómo las matrices pasan como parámetros a las funciones “decaen” en un puntero al primer elemento.

C17 6.7.6.2/1 Declaradores de matrices:

El tipo de elemento no debe ser un tipo incompleto o de función.

En caso de double weight[][]el tipo de elemento es double[], un tipo incompleto (matriz), que no se puede declarar en ninguna parte, parámetro o no. Debido a que esta regla de declaración de matrices se aplica antes que la regla de “desintegración de matrices” de parámetros de funciones, que se encuentra en C17 6.7.6.3/7 Declaradores de funciones:

Una declaración de un parámetro como ”matriz de tipo” se ajustará a ”puntero calificado a tipo”

Esas reglas asumen que ya tenemos una declaración de la matriz, lo que debería hacerse de acuerdo con la regla 6.7.6.2 citada anteriormente.

En el caso de una matriz de una sola dimensión double[]entonces este es un tipo de matriz incompleta pero el tipo de elemento es double, que es un tipo completo. Tal declaración de matriz está permitida de acuerdo con C17 6.7.6.2/4:

Si el tamaño no está presente, el tipo de matriz es un tipo incompleto.

Siempre que se utilice una matriz de este tipo con una lista de inicializadores, double foo[] = { 1.0f }; luego C17 6.7.9/22 establece que se le da un tamaño dependiendo de los inicializadores y se convierte en un tipo completo al final de la declaración:

Si se inicializa una matriz de tamaño desconocido, su tamaño está determinado por el elemento indexado más grande con un inicializador explícito. El tipo de matriz se completa al final de su lista de inicializadores.

Si no se inicializa, sino que simplemente forma parte de una lista de parámetros de función, entonces se aplica la regla mencionada anteriormente de “desintegración de matriz” y double[] se reemplaza con double*.

Ahora, en caso de que tengamos un parámetro de matriz como double [][3]entonces es un tipo de matriz incompleta pero el tipo de elemento double [3] es un tipo de matriz completa, por lo que es una declaración válida. En ese caso, el parámetro se ajusta a un puntero a dicho tipo de elemento, double (*)[3]. Y esa es la razón por la cual la dimensión de matriz más a la izquierda en una declaración de parámetro de matriz multidimensional puede omitirse; en realidad, no importa qué tamaño escribamos allí.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad