intの配列へのポインタのためのスカラー初期化子の余分な要素

I’m working on an exercise in K&R (ex. 5–9) and I was trying to convert the original program’s 2D array of

static char daytab[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

13個のintの配列へのポインタを使う

static char (*daytab)[13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

しかし、コンパイラは 警告:スカラー初期化子の余分な要素 を表示します。

Googling did not help and even K&R writes when passing the array to a function,

myFunction(int daytab[2][13]) {...}

〜と同じです

myFunction(int (*daytab)[13]) {...}
24

2 答え

2つは部分的に同等です。違いは次のとおりです。

static char daytab[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

2次元配列を宣言します。この配列には、配列のスペースを確保し、そのメモリを参照する daytab を確保します。しかしながら:

static char (*daytab)[13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

...ポインタだけを宣言します。したがって、期待どおりに動作しない配列初期化子でポインタを初期化しようとしています。配列はありません。配列にはメモリが用意されていません。代わりに、イニシャライザの最初の数値がポインタ daytab に割り当てられているだけです。警告が表示され、破棄されたばかりの追加値がたくさん指定されています。初期化子の最初の数字は 0 なので、 daytabNULL に設定するのは、

したがって、このような初期化を行う場合は、最初のバージョンを使用します。これは、2番目のバージョンで明示的に宣言したものと同じポインタ型に崩壊するため、同じ方法で使用できます。配列ポインタを持つ2番目のバージョンは、配列を動的に割り当てるか、すでに存在する別の配列への参照を取得する場合に必要です。

だからあなたはこれを行うことができます:

static char arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
static char (*ptr)[3] = NULL;

ptr = arr;

... ptrarr を同じ意味で使用してください。またはこれ:

static char (*ptr)[3] = NULL;

ptr = malloc(2 * sizeof(*ptr));

...動的に割り当てられた2次元配列(1D配列へのポインタの配列ではなく、実際の2D配列)を取得する。もちろん、その場合は初期化されません。

2つのバリエーションの「同値」は、2D配列が最初の要素へのポインタに減衰するとき、2番目のバリエーションで宣言されたポインタの型に減衰することを意味します。ポインタバージョンが実際に配列を指すと、その2つは同等です。しかし、2D配列バージョンでは、配列のメモリが設定されています。ポインタ宣言ではそうではありません。ポインタには、2D配列変数ではできない新しい値(別の配列をポイント)を割り当てることができます。

C99では、少なくとも( static ではなく)これを行うことができます:

char (*daytab)[13] = (char [][13]){
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
25
追加された
@BrianGordonが修正されました...私はその部分を入力している間に "静的"を忘れていました(私はそれはずっと前でした)。
追加された 著者 Dmitri,
スタックスペース?それが静的ならば、データセクションに入ります。
追加された 著者 Brian Gordon,
この(*(daytab + leap))[i] のようにポインタにアクセスすることができます(練習問題に関して)
追加された 著者 Vladimir,

@Dmitriはそれをうまく説明しましたが、

static char (*daytab)[13] { ... };

is a char pointer to an array of 13 chars. As K&R explained, without the parentheses, brackets [] have higher precedence, so

static char *daytab[2] { ... };

2つのcharポインタの配列を持つ望ましい効果が得られます。これで、適切な char [] 配列を参照するために2つのポインタを初期化するだけです。

オプション1:

static char *daytab[2] {
    (char []) {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    (char []) {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    };

オプション2:

static char nonleap[]  = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static char leap[]     = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static char *daytab[2] = {nonleap, leap}
0
追加された