私がいつもしていたことは次のとおりです。
int arr[] = {2, 3, 4};
そしてそれは常に機能しました。
ポインターを使用して、新しい配列を初期化するより良い方法を聞いたことがあります。
int *arr = {2, 3, 4};
ただし、どのIDEでも機能せず、、、int differs in levels of indirection from intまたはのようなエラーがスローされtoo many initializersます。どうすればいいですか?
int arr[] = {2, 3, 4};
は問題なく、完全に正しいです。変更する必要はありません。
その初期化は、gccでうまくいくようですが、正しくはありません。
int *arr = {2, 3, 4}; //weird behaviour, stores first value `2` as read-only
int arr[] = {2, 3, 4}; //array decl
前者は配列を初期化する正しい方法ではありません。
char*の場合、より理にかなっています
char* arr = "abcde"; //Pointer to a read-only char array in memory
char[] arr = "abcde"; //Normal char array
違い:
前者はアセンブリのRodata (定数、読み取り専用データ) セクションに書き込まれ、後者は読み取り/書き込みData-Segmentに存在します。前者を変更しようとすると、segmentation-faultが発生する可能性があります。
値が格納される場所が異なります。
char* arr = "abcde";
arr[1] = 'f'; //(undefined behavior)
char[] arr2 = "abcde";
arr2[1] = 'f'; //no issue
「配列を初期化」したい場合は、ポインタではなく配列を初期化する必要があります。
とにかく、C99 では複合リテラルを使用でき、ポインターを次のように初期化できます。
int *arr = (int []) {2, 3, 4};
これはあなたがやろうとしていたことに近いです。「ANSI C」という用語は、この機能が利用できない C89/90 を指すためによく使用されますが。
このアプローチに「優れた」ものはありません。配列ではなくポインターを提供するだけなので、本当に何が必要かという問題です。
2 番目のバージョンが最初のバージョンよりも優れているのはなぜですか?
少なくとも最初のバージョンは明示的です。指定された要素で int 配列を定義します。これを最適に行う方法をコンパイラーに判断させます。
あなたのコメントからエヴァン・リーに行きます(「文字列も一種の配列であり、ポインターで初期化されます。したがって、配列もこの方法で初期化する必要があります。」)。インストラクターが実際にあなたにこれを言った場合、彼は物事について混乱しているので、私は新しいインストラクターを見つけることを真剣に考えます.
文字列リテラルは配列式です。リテラル「Hello」は、char( const charC++ では) の 6 要素配列です。文字列リテラルは、プログラムの存続期間にわたってメモリが割り当てられるような方法で格納されます。このメモリは、プラットフォームに応じて、読み取り専用である場合とそうでない場合があります。文字列リテラルの内容を変更しようとしたときの動作はundefinedです。つまり、segfault が発生したり、文字列が変更されたり、その他のことが起こる可能性があります。
sizeof配列式がまたは 単項演算子のオペランドとして以外のコンテキストに現れる場合、&または宣言で別の配列を初期化するために使用される文字列リテラルである場合、式の型は "N -要素T" へのポインタ "の配列でTあり、式の値は配列の最初の要素のアドレスです。
そのため、次のように書くことができます
char *foo = "This is a test";
文字列リテラル"This is a test"は、タイプ "15 要素の配列 " の配列式charです。sizeofor演算子のオペランドではなく、 の&別の配列を初期化するために使用されていないためchar、式の型は「へのポインタchar」になり、最初の文字のアドレスが に割り当てられfooます。比較すると、
char foo[] = "This is a test";
;の配列fooとして宣言します。サイズは初期化文字列 (15 文字) のサイズから計算され、文字列リテラルの内容が にコピーされます。 charfoo
文字列は配列式です。中括弧で囲まれた値のリストは ではありません。
int *foo = {1, 2, 3};
の 3 要素配列を作成せずint、最初の要素のアドレスを に割り当てfooます。代わりに、これを正しく読んでいる場合、これは制約違反である必要があります。
6.7.9 初期化の
制約
2 初期化子は、初期化されるエンティティに含まれていないオブジェクトに値を提供しようと試みてはなりません。
C99 では、複合リテラルと呼ばれるものを次のように使用できます。
int *foo = (int []) {1, 2, 3};
キャスト式(int [])が必要です。これにより、 の新しい 3 要素配列が作成intされ、最初の要素のアドレスが に割り当てられfooます。文字列リテラルとは異なり、このような複合リテラルは、囲んでいるブロック1の間だけ存在します。IOW、次のようなことをした場合
int *foo = NULL;
if (condition())
{
foo = (int []){1, 2, 3};
// do stuff
}
// do more stuff
が指す無名配列オブジェクトは、ブロックfoo内にのみ存在します。ブロックが終了すると、配列は存在しなくなり、の値は無効になりifます。 iffoo
static、期間があり、プログラムの存続期間中存在します。
int arr[] = {2, 3, 4}; 大丈夫です。
ポインターを使用する場合は、malloc などでメモリを割り当てる必要があります。そんな感じ :
int *arr = malloc(sizeof(int)*4);
arr[0]=1;
arr[1]=2;
arr[2]=3;
arr[3]=4;
//display
printf("%d %d %d %d\n",arr[0],arr[1],arr[2],arr[3]);
free(arr);