2009-10-13 11 views
22

Desidero avere una matrice di lunghezza variabile contenuta in una struttura, ma sto avendo problemi a inizializzarla correttamente.C inizializzare la matrice all'interno della struttura

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

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

Tutto ciò che provo mi dà un 'errore: inizializzazione non statica di un errore di membro di array flessibile'.

+1

come stai facendo? – Macarse

+1

Ho modificato la domanda di cui sopra per illustrare ... –

+1

Quale compilatore, su quale piattaforma? –

risposta

12

È possibile eseguire tale operazione in gcc rendendo la struttura static o globale, ma risulta che l'inizializzazione di membri di array flessibili non è conforme e pertanto è probabile che non funzioni se non con gcc. Ecco un modo per farlo che appena utilizza le funzionalità C99 conformi ...

#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

Io farò +1 se lo distingui un po 'in modo che sia leggermente più leggibile. : P –

+0

Intendevo separarli in istruzioni separate, ma anche questa è una buona idea. –

+0

Credo che tu sia bloccato con la limitazione della classe di memoria 'static', perché non c'è proprio modo di ottenere che il compilatore realizzi una struttura di lunghezza variabile con la classe di memoria' auto'. Ci sono matrici di lunghezza variabile in C99, quindi è possibile allocare lo spazio nello stack con una matrice di lunghezza variabile e quindi inizializzare un puntatore a 'struct Grid' dal suo indirizzo. Probabilmente sarebbe anche un programma conforme purché la memoria fosse accessibile esclusivamente tramite 'struct *'. Si potrebbe anche 'malloc' it. Quindi si potrebbe 'memcpy' dalla struct' static' a 'auto'. – DigitalRoss

0

Una versione con 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)' non funzionerà come credi. Le matrici si degradano ai puntatori quando passano come una funzione, in modo che la linea sia la stessa di 'sizeof (int *)' - non è ciò che si desidera. –

+0

Inoltre, c'è qualche ragione per non andare avanti e renderlo un array _real_ bidimensionale? –

+0

Chris: hai ragione. Grazie per segnalarlo. Il modo corretto sarebbe passare e il parametro addizionale sizeof (vec)/sizeof (vec [0]) come dimensione del vec. – Macarse

1

Non credo che questo sia possibile o supportato. Come sottolinea DigitalRoss, è possibile inizializzare da un valore letterale nel caso degli array static ... anche se non sono ancora sicuro se questo è incluso nello standard o solo un'estensione comune. Non riesco a trovare una clausola nello standard che supporti l'inizializzazione letterale di array flessibili, anche se posso vedere che gcc explicitly supports it.

+0

Comeau lo rifiuta. – AnT

+0

@Andrey - Comeau è un compilatore C++, non un compilatore C, quindi è previsto il rifiuto del codice C99 poiché lo standard C99 non è incluso in C++. –

+0

@ Chris Lutz: No. Comeau è un compilatore C++, C89/90 e C99, che nega come lo si invoca. – AnT

3

È non avere una matrice di lunghezza variabile (VLA) nella struttura. Quello che hai nella tua struttura è chiamato membro dell'array flessibile. Il membro della matrice flessibile non ha assolutamente nulla a che fare con VLA. I membri di array flessibili in C esistono per legalizzare e supportare il vecchio idioma "struct hack", che si basa sull'allocazione dinamica della memoria per gli oggetti struct con array finali di dimensioni diverse.

I membri della matrice flessibile non possono essere inizializzati con gli inizializzatori aggregati, che è ciò che sembra tentare nel codice. Quello che stai cercando di fare qui è semplicemente impossibile. Non esiste una funzionalità di questo tipo in C.

Nel frattempo, il testo del messaggio di errore generato dal compilatore sembra suggerire che supporti qualcosa di simile come un'estensione. Questo potrebbe essere vero, ma tieni presente che questa non è in alcun modo una caratteristica C standard.

+0

Anche in questo caso, non si applica ai membri di array flessibili. Si noti inoltre che GCC, uno dei compilatori che supporta questa estensione, lo documenta chiaramente e esplicitamente come estensione specifica per GCC. – AnT

+0

Inutile dire che invocare GCC nella modalità '-ansi -pedantic' genera un avviso per un tentativo di inizializzare un membro di array flessibile. – AnT

+0

Credo che AudreyT sia corretto - altrove lo standard dice esplicitamente _ "Un tipo di struttura contenente un membro di array flessibile è un tipo incompleto che non può essere completato." _ – caf

27

Ecco la mia versione:

#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

So che questo è un thread vecchio, ma che ha appena risolto un grosso problema che stavo avendo. Il bit utile è che gli array possono essere di dimensioni diverse. Sono sorpreso di non riuscire a trovare la risposta da nessun'altra parte. Grazie. – kainosnous

+1

Anche molto utile per me! Altre risposte sembrano non affrontare il requisito essenziale della domanda. Grazie molto! – basicthinker

+0

Grazie. Finalmente ho trovato quella soluzione ad hoc che guardavo di tanto in tanto da mesi. – mesmerizingr