web-dev-qa-db-ja.com

配列のすべてのメンバを同じ値に初期化する方法

私はCに大きな配列を持っています(それが違いを生むのであればC++ではありません)。すべてのメンバを同じ値に初期化したいです。私はかつてこれをする簡単な方法を知っていたと誓うことができました。私の場合はmemset()を使うことができますが、Cの構文に組み込まれているこれを行う方法はありませんか?

880
Matt

その値が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"は必ずしも "all-bits-zero"を意味するわけではないので、上記を使用することはmemset()よりも優れていて移植性があります。 (浮動小数点値は+0に初期化され、null値へのポインタなどが初期化されます。)

1116
aib

コンパイラがGCCの場合は、次の構文を使用できます。

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

詳細な説明をご覧ください。 http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html

364
qrdl

コピーペーストを複数回行わずに、同じ値で大きな配列を静的に初期化するために、次のマクロを使用できます。

#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か所だけで交換する必要があります。

編集:可能な便利な拡張

(提供: Jonathan Leffler

あなたは簡単にこれを一般化することができます:

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

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

169
mouviciel

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

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

そうではありません。

61
Frank Szczerba

私はこの構文を使ったいくつかのコードを見ました:

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

たとえあなたが偶然にいくつかのenum-valuesを書いたとしても、これは物事を順番に保ちます。

このテクニックについての詳細は here および here にあります。

47
abelenky
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...

配列のサイズを変更します。

21
Tarski

上で詳述したように、静的初期化子全体のことを行うことができますが、配列サイズが変わると(配列が適切に初期化子を追加しないとゴミになってしまうと)、大変なことになります。

memsetを使用すると、実行時にランタイムヒットが発生しますが、コードサイズのヒットが正しく行われても、配列サイズの変更による影響は受けません。私がこの解決法を使用するのは、配列が例えば数十個の要素よりも大きい場合です。

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

11
plinth

これは別の方法です:

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拡張を使うことができますか?

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

7
humble_guru

ちょっと頬の答え。文を書く

array = initial_value

あなたの好きな配列対応言語(私のものはFortranですが、他にもたくさんあります)でそれをあなたのCコードにリンクしてくださいあなたはおそらくそれを外部関数にまとめることを望みます。

(int配列のような) '通常の'データ型を初期化するために、大かっこ記法を使うことができますが、配列にまだスペースがあるなら、最後の値の後で値をゼロにします:

// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
5
warren

もし配列がintやintのサイズ、あるいはmem-patternのサイズがintに正確に収まる(つまり、すべて0または0xA5A5A5A5)場合は、 memset() を使用するのが最善です。

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

4
ddimitrov

与えられた値で任意の型の配列を初期化するための速い方法があります。これは大規模配列では非常にうまく機能します。アルゴリズムは以下のとおりです。

  • 配列の最初の要素を初期化する(通常の方法)
  • 設定されていない部分を設定されていない部分にコピーし、次の各コピー操作でサイズを2倍にします。

1 000 000要素int配列の場合、通常のループ初期化より4倍高速です(i5、2コア、2.3 GHz、4GiBメモリ、64ビット)

loop runtime 0.004248 [seconds]

memfill() runtime 0.001085 [seconds] 


#include <stdio.h>
#include <time.h>
#include <string.h>
#define ARR_SIZE 1000000

void memfill(void *dest, size_t destsize, size_t elemsize) {
   char   *nextdest = (char *) dest + elemsize;
   size_t movesize, donesize = elemsize;

   destsize -= elemsize;
   while (destsize) {
      movesize = (donesize < destsize) ? donesize : destsize;
      memcpy(nextdest, dest, movesize);
      nextdest += movesize; destsize -= movesize; donesize += movesize;
   }
}    
int main() {
    clock_t timeStart;
    double  runTime;
    int     i, a[ARR_SIZE];

    timeStart = clock();
    for (i = 0; i < ARR_SIZE; i++)
        a[i] = 9;    
    runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
    printf("loop runtime %f [seconds]\n",runTime);

    timeStart = clock();
    a[0] = 10;
    memfill(a, sizeof(a), sizeof(a[0]));
    runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
    printf("memfill() runtime %f [seconds]\n",runTime);
    return 0;
}
3
Maciej
  1. 配列が静的として宣言されているかグローバルである場合、配列内のすべての要素はすでにデフォルトのデフォルト値0になっています。
  2. 一部のコンパイラは、デバッグモードでarray'sをデフォルトの0に設定します。 
  3. デフォルトを0に設定するのは簡単です。 int array [10] = {0}; 
  4. ただし、他の値の場合は、memset()またはloopを使用してください。

例: int array [10]; memset(array、-1、10 * sizeof(int));

1
Hannah Zhang

すべての雑談を切り抜いて、短い答えはあなたがコンパイル時に最適化をオンにした場合、あなたがこれより良いことはしないということです: 

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

追加されたボーナス:コードは実際に読みやすいです:)

1
JWDN

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

#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
1
hkBattousai

遅延初期化(つまりクラスメンバコンストラクタの初期化)の場合

int a[4];

unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
  a[i] = 0;
0
nikc
#include<stdio.h>
int main(){
int i,a[50];
for (i=0;i<50;i++){
    a[i]=5;// set value 5 to all the array index
}
for (i=0;i<50;i++)
printf("%d\n",a[i]);
   return 0;
}

それはo/pを与えるでしょう5 5 5 5 5 5 ......全体の配列のサイズまで

0
Dadhich Sourav

その日に戻って(そしてそれは良い考えだとは言っていませんが)、最初の要素を設定してから、次のようにします。

memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]); 

(memcpyの実装に依存するであろう)それがこれ以上機能するとは限らないが、最初の要素を次の要素に繰り返しコピーすることによって機能する - 構造体の配列に対しても機能する。

0
Mike

私はユーザTarskiが同様の方法でこの質問に答えたことを知っていますが、私はもう少し詳細を加えました。私はC++を使いたいと思う傾向があるので、少し錆びているので、私のCの一部を許してください。


あなたが前もって配列のサイズを知っているなら...

#include <stdio.h>

typedef const unsigned int cUINT;
typedef unsigned int UINT;

cUINT size = 10;
cUINT initVal = 5;

void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal );
void printArray( UINT* myArray ); 

int main() {        
    UINT myArray[size]; 
    /* Not initialized during declaration but can be
    initialized using a function for the appropriate TYPE*/
    arrayInitializer( myArray, size, initVal );

    printArray( myArray );

    return 0;
}

void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal ) {
    for ( UINT n = 0; n < size; n++ ) {
        myArray[n] = initVal;
    }
}

void printArray( UINT* myArray ) {
    printf( "myArray = { " );
    for ( UINT n = 0; n < size; n++ ) {
        printf( "%u", myArray[n] );

        if ( n < size-1 )
            printf( ", " );
    }
    printf( " }\n" );
}

上記の注意点がいくつかあります。 1つは、UINT myArray[size];は宣言時に直接初期化されないということです。ただし、次のコードブロックまたは関数呼び出しでは、配列の各要素を必要な値に初期化します。もう一つの注意点は、あなたがサポートするそれぞれのtypeに対してinitializing functionを書く必要があり、またそれらの型をサポートするためにprintArray()関数を修正する必要があるということです。


このコードはオンラインのコンパイラで here で試してみることができます。

0
Francis Cugler