1091

私はCで大きな配列を持っています(違いがある場合はC ++ではありません)。同じ値のすべてのメンバーを初期化したい。

私はかつてこれを行う簡単な方法を知っていたと断言できます。私の場合は使用できますmemset()が、C 構文に組み込まれているこれを行う方法はありませんか?

4

26 に答える 26

1393

その値が 0 でない限り (この場合、初期化子の一部を省略でき、対応する要素が 0 に初期化されます)、簡単な方法はありません。

ただし、明らかな解決策を見逃さないでください。

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };

値が欠落している要素は 0 に初期化されます。

int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...

したがって、これはすべての要素を 0 に初期化します。

int myArray[10] = { 0 }; // all elements 0

C++ では、空の初期化リストもすべての要素を 0 に初期化します。これはCでは許可されていません。

int myArray[10] = {}; // all elements 0 in C++

初期化子が指定されていない場合、静的ストレージ期間を持つオブジェクトは 0 に初期化されることに注意してください。

static int myArray[10]; // all elements 0

そして、その「0」は必ずしも「すべてのビットがゼロ」を意味するわけではないため、上記を使用する方が memset() よりも優れており、移植性が高くなります。(浮動小数点値は +0 に初期化され、ポインタは null 値などに初期化されます。)

于 2008-10-14T13:17:23.130 に答える
436

コンパイラが GCC の場合、次の「GNU 拡張」構文を使用できます。

int array[1024] = {[0 ... 1023] = 5};

詳細な説明を確認してください: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html

于 2008-10-16T07:38:46.837 に答える
190

大きな配列を同じ値で静的に初期化するには、複数回のコピーと貼り付けを行わずに、マクロを使用できます。

#define VAL_1X     42
#define VAL_2X     VAL_1X,  VAL_1X
#define VAL_4X     VAL_2X,  VAL_2X
#define VAL_8X     VAL_4X,  VAL_4X
#define VAL_16X    VAL_8X,  VAL_8X
#define VAL_32X    VAL_16X, VAL_16X
#define VAL_64X    VAL_32X, VAL_32X

int myArray[53] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X };

値を変更する必要がある場合は、1 か所だけで置換を行う必要があります。

編集:便利な拡張機能の可能性

ジョナサン・レフラーの礼儀)

これを次のように簡単に一般化できます。

#define VAL_1(X) X
#define VAL_2(X) VAL_1(X), VAL_1(X)
/* etc. */

バリアントは、次を使用して作成できます。

#define STRUCTVAL_1(...) { __VA_ARGS__ }
#define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__)
/*etc */ 

構造体または複合配列で動作します。

#define STRUCTVAL_48(...) STRUCTVAL_32(__VA_ARGS__), STRUCTVAL_16(__VA_ARGS__)

struct Pair { char key[16]; char val[32]; };
struct Pair p_data[] = { STRUCTVAL_48("Key", "Value") };
int a_data[][4] = { STRUCTVAL_48(12, 19, 23, 37) };

マクロ名は交渉可能です。

于 2009-10-14T10:27:56.417 に答える
64

配列のすべてのメンバーが明示的に初期化されるようにする場合は、宣言から次元を省略します。

int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

コンパイラーは、初期化子リストから次元を推測します。残念ながら、多次元配列の場合、最も外側の次元のみを省略できます。

int myPoints[][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };

大丈夫ですが

int myPoints[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };

ではありません。

于 2008-10-14T18:30:25.917 に答える
56

次の構文を使用するコードを見ました。

char* array[] = 
{
    [0] = "Hello",
    [1] = "World"
};   

特に便利になるのは、列挙型をインデックスとして使用する配列を作成する場合です。

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

#define _ITEM(x) [x] = #x

char* array[] = 
{
    _ITEM(ERR_OK),
    _ITEM(ERR_FAIL),
    _ITEM(ERR_MEMORY)
};   

これにより、たまたまいくつかの列挙値を順不同で書いたとしても、順序が保たれます。

この手法の詳細については、こちらこちらをご覧ください。

于 2012-03-21T21:02:23.920 に答える
23
int i;
for (i = 0; i < ARRAY_SIZE; ++i)
{
  myArray[i] = VALUE;
}

これよりは良いと思います

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...

配列のサイズが変更された場合。

于 2008-10-14T13:34:02.830 に答える
12

上記のように静的初期化子全体を実行できますが、配列のサイズが変更された場合 (配列が肥大化した場合、適切な追加の初期化子を追加しないとガベージが発生します) は、非常に厄介な問題になる可能性があります。

memset は作業を実行するためのランタイム ヒットを提供しますが、配列サイズの変更の影響を受けないコード サイズ ヒットはありません。配列が数十個の要素よりも大きい場合、ほぼすべての場合にこのソリューションを使用します。

配列が静的に宣言されていることが本当に重要である場合は、プログラムを作成してプログラムを作成し、それをビルド プロセスの一部にします。

于 2008-10-14T13:29:25.633 に答える
9

別の方法は次のとおりです。

static void
unhandled_interrupt(struct trap_frame *frame, int irq, void *arg)
{
    //this code intentionally left blank
}

static struct irqtbl_s vector_tbl[XCHAL_NUM_INTERRUPTS] = {
    [0 ... XCHAL_NUM_INTERRUPTS-1] {unhandled_interrupt, NULL},
};

見る:

C 拡張機能

指定された初期化

次に、次の質問をします: C 拡張機能はいつ使用できますか?

上記のコード サンプルは組み込みシステムにあり、別のコンパイラからの光を見ることはありません。

于 2008-10-14T22:12:52.923 に答える
7

少し皮肉な答えです。声明を書く

array = initial_value

お気に入りの配列対応言語 (私の場合は Fortran ですが、他にもたくさんあります) で、それを C コードにリンクします。おそらく、外部関数になるようにラップしたいと思うでしょう。

于 2009-10-14T10:33:06.930 に答える
6

「通常の」データ型 (int 配列など) を初期化するには、ブラケット表記を使用できますが、配列にまだスペースがある場合、最後の値の後に値をゼロにします。

// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
于 2008-10-14T13:17:39.197 に答える
5

配列がintか、intのサイズの何か、またはmem-patternのサイズがintに正確に適合する場合(つまり、すべてゼロまたは0xA5A5A5A5)、最良の方法はmemset()を使用することです。

それ以外の場合は、インデックスを移動するループでmemcpy()を呼び出します。

于 2008-10-14T13:59:30.517 に答える
3

初期化された配列の要素にアクセスするためのインデックスの順序について誰も言及していません。私のコード例は、それを説明する例を示します。

#include <iostream>

void PrintArray(int a[3][3])
{
    std::cout << "a11 = " << a[0][0] << "\t\t" << "a12 = " << a[0][1] << "\t\t" << "a13 = " << a[0][2] << std::endl;
    std::cout << "a21 = " << a[1][0] << "\t\t" << "a22 = " << a[1][1] << "\t\t" << "a23 = " << a[1][2] << std::endl;
    std::cout << "a31 = " << a[2][0] << "\t\t" << "a32 = " << a[2][1] << "\t\t" << "a33 = " << a[2][2] << std::endl;
    std::cout << std::endl;
}

int wmain(int argc, wchar_t * argv[])
{
    int a1[3][3] =  {   11,     12,     13,     // The most
                        21,     22,     23,     // basic
                        31,     32,     33  };  // format.

    int a2[][3] =   {   11,     12,     13,     // The first (outer) dimension
                        21,     22,     23,     // may be omitted. The compiler
                        31,     32,     33  };  // will automatically deduce it.

    int a3[3][3] =  {   {11,    12,     13},    // The elements of each
                        {21,    22,     23},    // second (inner) dimension
                        {31,    32,     33} };  // can be grouped together.

    int a4[][3] =   {   {11,    12,     13},    // Again, the first dimension
                        {21,    22,     23},    // can be omitted when the 
                        {31,    32,     33} };  // inner elements are grouped.

    PrintArray(a1);
    PrintArray(a2);
    PrintArray(a3);
    PrintArray(a4);

    // This part shows in which order the elements are stored in the memory.
    int * b = (int *) a1;   // The output is the same for the all four arrays.
    for (int i=0; i<9; i++)
    {
        std::cout << b[i] << '\t';
    }

    return 0;
}

出力は次のとおりです。

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

11      12      13      21      22      23      31      32      33
于 2016-02-06T15:24:42.237 に答える
2

すべてのおしゃべりを切り抜けて、短い答えは、コンパイル時に最適化をオンにすると、これよりもうまくいかないということです:

int i,value=5,array[1000]; 
for(i=0;i<1000;i++) array[i]=value; 

追加ボーナス:コードは実際に判読可能です:)

于 2016-11-05T16:12:23.577 に答える
1

遅延初期化 (つまり、クラス メンバー コンストラクターの初期化) については、次の点を考慮してください。

int a[4];

unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
  a[i] = 0;
于 2018-10-19T17:08:44.263 に答える
-1

質問には要件がないため、解決策は一般的でなければなりません。初期メンバー値を持つ、未指定の可能性のある構造要素から構築された未指定の可能性のある多次元配列の初期化:

#include <string.h> 

void array_init( void *start, size_t element_size, size_t elements, void *initval ){
  memcpy(        start,              initval, element_size              );
  memcpy( (char*)start+element_size, start,   element_size*(elements-1) );
}

// testing
#include <stdio.h> 

struct s {
  int a;
  char b;
} array[2][3], init;

int main(){
  init = (struct s){.a = 3, .b = 'x'};
  array_init( array, sizeof(array[0][0]), 2*3, &init );

  for( int i=0; i<2; i++ )
    for( int j=0; j<3; j++ )
      printf("array[%i][%i].a = %i .b = '%c'\n",i,j,array[i][j].a,array[i][j].b);
}

結果:

array[0][0].a = 3 .b = 'x'
array[0][1].a = 3 .b = 'x'
array[0][2].a = 3 .b = 'x'
array[1][0].a = 3 .b = 'x'
array[1][1].a = 3 .b = 'x'
array[1][2].a = 3 .b = 'x'

編集: start+element_sizeに変更(char*)start+element_size

于 2009-10-13T23:40:25.983 に答える