質問

この例は問題なく動作します:

static char *daytab[] = {
    "hello",
    "world"
};

これはしません:

static char *daytab[] = {
    {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つの文字列リテラル(それ自体が配列です)へのポインターで満たされた配列が作成されます。 2番目の例であるIMOは同一である必要があります-配列を作成し、2つのchar配列へのポインターで埋めます。

2番目の例が間違っている理由を誰かに説明してもらえますか?

PSおそらく次のように書くことができます(テストしていません):

static char a[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static char b[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static char *daytab[] = {
    a,
    b
};

しかし、それはあまりにも多くの作業のように見えます:)。

役に立ちましたか?

解決

これ:

{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

単なる配列初期化子です。それ自体は配列を作成しません。最初の例では、文字列リテラルをポインターに割り当てたときに、DIDは静的ストレージにそれらの文字列を作成し(非表示)、ポインターを割り当てました。

したがって、基本的に、配列初期化子でchar *を初期化する方法はありません。実際の配列を作成し、それらに番号を割り当てる必要があります。次のようなことをする必要があります:

char a[][] = { {32, 30, 0}, {34, 32, 33, 0} }; // illegal

しかしそれは違法です。

配列を個別に構築し、最後の例のように配列に割り当てる必要があります。

他のヒント

試してください:

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}
};

これらはchar *ではありません。どちらもcharではありません。おそらく必要です:

static int daytab[][13] ...

まあ、このスレッドはすでに少し古いですが、私は同じ問題を扱っていて、配列へのポインターの配列を次のように初期化する方法を見つけました:

#include <iostream>
using namespace std;

int *a[] = {
  (int[]) { 0 } ,
  (int[]) { 1 , 2 } ,
  (int[]) { 3 , 4 , 5 } ,
  (int[]) { 6 , 7 , 8 , 9 }
};

main()
{
  cout
  << a[0][0] << endl
  << a[1][0] << " " << a[1][1] << endl
  << a[2][0] << " " << a[2][1] << " " << a[2][2] << endl
  << a[3][0] << " " << a[3][1] << " " << a[3][2] << " " << a[3][3] << endl;
}

そして、gnu g ++でコンパイルして出力を取得します

0
1 2
3 4 5
6 7 8 9

およびIntel icpcでコンパイル

0
1 1
40896 32767 -961756724
0 32767 4198878 0

そのため、おそらくこのスタイルの一般的な使用法の欠如のために、インテル®コンパイラーが構文を正しくサポートしていないという点で、構文は原則として正しいようです。


---編集---

これもCバージョンです(必要に応じて):

#include <stdio.h>

int *a[] = { 
  (int[]) { 0 } , 
  (int[]) { 1 , 2 } , 
  (int[]) { 3 , 4 , 5 } , 
  (int[]) { 6 , 7 , 8 , 9 } 
};

int main()
{
  printf( "%d\n" , a[0][0] );
  printf( "%d %d\n" , a[1][0] , a[1][1] );
  printf( "%d %d %d\n" , a[2][0] , a[2][1] , a[2][2] );
  printf( "%d %d %d %d\n" , a[3][0] , a[3][1] , a[3][2] , a[3][3] );
}

gccとclangでテストし、正しい結果を出力します。 ところでインテル®コンパイラーの誤った出力は、コンパイラーのバグでした。

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

2番目の例の構文は、多次元配列リテラルの構文です。

多次元配列は、配列へのポインタの配列ではありません。

宣言された型に応じて、あるものの構文が別のものの構文でもあるとしたら、驚くでしょう。

最初の例では、文字列リテラルは配列値ではなくポインターに評価されるため、値はポインターの配列として評価されます。配列リテラルはポインターではなく配列値として評価されるため、2番目の例は多次元配列-要素が配列値である配列であり、要素が配列値へのポインターである配列ではありません。

次のコードは、多次元配列、配列へのポインター、ポインターの配列、およびポインターへのポインターの組み合わせを示しています。これら3つのうち、ポインターの配列とポインターへのポインターのみが相互に互換性があります。

void multi_array (int x[][4], size_t len) // multidimensional array
{
    for (size_t i = 0; i < len; ++i)
        for (size_t j = 0; j < 4; ++j)
            putchar( 'a' + x[i][j] );
    putchar('\n');
}

void ptr_array (int (*x)[4], size_t len) // pointer to an array
{ ... as multi_array  }

void array_ptr (int *x[], size_t len) // array of pointers
{ ... as multi_array  }

void ptr_ptr (int **x, size_t len) // pointer to pointer
{ ... as multi_array  }

int main() {
    int a[][4] = { { 1,2,3,4 } };
    int b[] = { 1,2,3,4 };
    int* c[] = { b };

    multi_array( a, 1 );
    multi_array( (int[][4]) { { 1,2,3,4} }, 1 ); // literal syntax as value
    ptr_array( &b, 1 );
    array_ptr( c, 1 );
    ptr_ptr( c, 1 ); // only last two are the same

    return 0;
}

最初の例も機能しないことに注意してください。次のようにする必要があります:

static const char *daytab[] = {
    "hello",
    "world"
};

定数に注意してください。

編集:「うまくいかない」とは、悪い習慣であり、間違いを起こしやすいことを意味します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top