web-dev-qa-db-ja.com

C構造体内の配列を初期化する

構造内に可変長配列を含めたいのですが、正しく初期化できません。

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

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

私が試みるすべては私に「エラー:柔軟な配列メンバーの非静的な初期化」エラーを与えます。

22
user35288

構造体をstaticまたはグローバルにすることにより、gccでそれを機能させることができますが、柔軟な配列メンバーの初期化は非準拠であるため、gcc以外では機能しない可能性があります。 C99準拠の機能を使用する方法は次のとおりです...

#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);
12
DigitalRoss

これが私のバージョンです:

#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 );
}
27
sambowry

しないでください構造に可変長配列(VLA)があります。構造内にあるものはフレキシブル配列メンバーと呼ばれます。フレキシブルアレイメンバーは、VLAとはまったく関係ありません。 Cには柔軟な配列メンバーが存在し、古き良き「構造体ハック」イディオムを合法化してサポートします。

柔軟な配列メンバーは、集約イニシャライザーでは初期化できません。これは、コードで試みているようです。あなたがここでしようとしていることは単に不可能です。 Cにはそのような機能はありません。

一方、コンパイラによって生成されたエラーメッセージのテキストは、拡張機能としてこのようなものをサポートしていることを示唆しているようです。これは正しいかもしれませんが、これは決して標準のC機能ではないことに注意してください。

4
AnT

これが可能またはサポートされているとは思いません。 DigitalRoss が指摘しているように、static配列の場合はリテラルから初期化できます...これが標準に含まれているか、一般的なものに含まれているかはまだわかりません拡張。 gccが明示的にサポートする であることがわかりますが、柔軟な配列のリテラル初期化をサポートする句を標準で見つけることができないようです。

1
D.Shawley