2009-10-13 23 views
22

Quiero tener una matriz de longitud variable dentro de una estructura, pero tengo problemas para inicializarla correctamente.C inicializar matriz dentro de la estructura

struct Grid { 
    int rows; 
    int cols; 
    int grid[]; 
} 

int main() { 
    struct Grid testgrid = {1, 3, {4, 5, 6}}; 
} 

Todo lo que intento me da un error 'error: inicialización no estática de un miembro de matriz flexible' error.

+1

cómo lo haces? – Macarse

+1

He editado la pregunta anterior para ilustrar ... –

+1

¿Qué compilador, en qué plataforma? –

Respuesta

12

Puede hacer que funcione en gcc haciendo que la estructura sea static o global, pero resulta que inicializar los miembros del conjunto flexible no es conforme y por lo tanto es probable que no funcione excepto con gcc. Aquí hay una manera de hacerlo que sólo utiliza funciones C99 conformes ...

#include <stdlib.h> 
#include <stdarg.h> 

typedef struct Grid { 
    int rows; 
    int cols; 
    int grid[]; 
} *Grid; 

Grid newGrid(int, int, ...); 

Grid newGrid(int rows, int cols, ...) 
{ 
Grid g; 
va_list ap; 
int i, n = rows * cols; 

    if((g = malloc(sizeof(struct Grid) + rows * cols * sizeof(int))) == NULL) 
    return NULL; 
    g->rows = rows; 
    g->cols = cols; 
    va_start(ap, cols); 
    for(i = 0; i < n; ++i) 
    g->grid[i] = va_arg(ap, int); 
    va_end(ap); 
    return g; 
} 
. 
. 
. 
Grid g1, g2, g3; 
g1 = newGrid(1, 1, 123); 
g2 = newGrid(2, 3, 1, 1, 1, 
        2, 2, 2); 
g3 = newGrid(4, 5, 1, 2, 3, 4, 5, 
        6, 7, 8, 9, 10, 
        11, 12, 13, 14, 15, 
        16, 17, 18, 19, 20); 
+1

Voy a +1 si lo separa un poco para que sea un poco más legible. : P –

+0

Me refiero a separarlos en declaraciones separadas, pero eso también es una buena idea. –

+0

Creo que está atascado con la limitación de la clase de almacenamiento "estático", porque simplemente no hay forma de que el compilador haga una estructura de longitud variable con la clase de almacenamiento 'auto'. Hay arreglos de longitud variable en C99, por lo que podría asignar espacio en la pila con una matriz de longitud variable y luego inicializar un puntero a 'struct Grid' desde su dirección. Probablemente incluso sea un programa conforme, siempre y cuando la memoria se acceda de manera exclusiva a través de 'struct *'. También podrías 'malloc'. Entonces podrías 'memcpy' de la estructura' static' al 'auto'. – DigitalRoss

0

Una versión usando malloc:

#include <stdio.h> 
#include <stdlib.h> 

typedef struct Grid { 
    int rows; 
    int cols; 
    int *grid; 
} Grid; 

/* Should validate params */ 
Grid 
buildGrid(int rows, int cols, int vec[]) { 

    Grid grid; 
    grid.rows = rows; 
    grid.cols = cols; 
    int i; 

    if ((grid.grid = malloc(sizeof(vec))) == NULL) { 
     /* do something.*/ 
    } 

    for(i = 0; i < sizeof(vec) ; i++) { 
     grid.grid[i] = vec[i]; 
    } 

    return grid; 
} 
+2

'sizeof (vec)' no funcionará como usted cree que sucederá. Las matrices se degradan a punteros cuando pasa como una función, por lo que esa línea será igual a 'sizeof (int *)' - no lo que desea. –

+0

Además, ¿hay alguna razón para no continuar y convertirlo en una matriz real bidimensional? –

+0

Chris: Tienes razón. Gracias por mencionarlo. Una forma correcta sería pasar y el parámetro adicional sizeof (vec)/sizeof (vec [0]) como el tamaño del vec. – Macarse

1

No creo que esto es posible o compatible. Como señala DigitalRoss, puede inicializar desde un literal en el caso de las matrices static ... aunque todavía no estoy seguro de si esto está incluido en la extensión estándar o simplemente en una extensión común. Parece que no puedo encontrar una cláusula en el estándar que admita la inicialización literal de matrices flexibles, aunque puedo ver que gcc explicitly supports it.

+0

Comeau lo rechaza. – AnT

+0

@Andrey - Comeau es un compilador de C++, no un compilador de C, por lo que se espera que rechace el código C99 ya que el estándar C99 no está incluido en C++. –

+0

@ Chris Lutz: No. Comeau es un compilador C++, C89/90 y C99, que hace referencia a cómo lo invocas. – AnT

3

Usted no tienen una matriz de longitud variable (VLA) en su estructura. Lo que tiene en su estructura se llama miembro de matriz flexible. El miembro de matriz flexible no tiene absolutamente nada que ver con VLA. Los miembros flexibles de la matriz en C existen para legalizar y soportar la vieja jerga de "struct hack", que se basa en la asignación dinámica de memoria para objetos struct con matrices finales de diferentes tamaños.

Los miembros de matriz flexible no se pueden inicializar con inicializadores agregados, que es lo que parece intentar en su código. Lo que estás tratando de hacer aquí es simplemente imposible. No existe tal característica en C.

Mientras tanto, el texto del mensaje de error generado por el compilador parece sugerir que admite algo así como una extensión. Esto podría ser cierto, pero tenga en cuenta que esto no es de ninguna manera una característica estándar de C.

+0

De nuevo, no se aplica a los miembros de matriz flexibles. También tenga en cuenta que GCC, uno de los compiladores que admite esta extensión, lo documenta clara y explícitamente como una extensión específica de GCC. – AnT

+0

No hace falta decir que invocar GCC en modo '-ansi -pedantic' da como resultado una advertencia para intentar inicializar un miembro de matriz flexible. – AnT

+0

Creo que AudreyT está en lo correcto; en otro lugar el estándar dice explícitamente: "Un tipo de estructura que contiene un miembro de matriz flexible es un tipo incompleto que no se puede completar." – caf

27

Aquí está mi versión:

#include <stdio.h> 

struct matrix { 
    int rows; 
    int cols; 
    int **val; 
} a = {  .rows=3, .cols=1, 
     .val = (int*[3]){ (int[1]){1}, 
          (int[1]){2}, 
          (int[1]){3} } }, 

    b = {  .rows=3, .cols=4, 
     .val = (int*[3]){ (int[4]){1, 2, 3, 4}, 
          (int[4]){5, 6, 7, 8}, 
          (int[4]){9,10,11,12} } }; 

void print_matrix(char *name, struct matrix *m){ 
    for(int row=0;row<m->rows;row++) 
    for(int col=0;col<m->cols;col++) 
     printf("%s[%i][%i]: %i\n", name, row, col, m->val[row][col]); 
    puts(""); 
} 

int main(){ 
    print_matrix("a", &a); 
    print_matrix("b", &b); 
} 
+5

Sé que este es un hilo viejo, pero que acaba de resolver un gran problema que estaba teniendo. Lo útil es que las matrices pueden tener diferentes tamaños. Me sorprende que no pude encontrar la respuesta en ningún otro lado. Gracias. – kainosnous

+1

¡También bastante útil para mí! Otras respuestas parecen no abordar el requisito esencial de la pregunta. ¡Muchas gracias! – basicthinker

+0

Gracias. Finalmente encontré esa solución ad hoc que he estado buscando de vez en cuando durante meses. – mesmerizingr

Cuestiones relacionadas