私はCに大きな配列を持っています(それが違いを生むのであればC++ではありません)。すべてのメンバを同じ値に初期化したいです。私はかつてこれをする簡単な方法を知っていたと誓うことができました。私の場合はmemset()
を使うことができますが、Cの構文に組み込まれているこれを行う方法はありませんか?
その値が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値へのポインタなどが初期化されます。)
コンパイラがGCCの場合は、次の構文を使用できます。
int array[1024] = {[0 ... 1023] = 5};
詳細な説明をご覧ください。 http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html
コピーペーストを複数回行わずに、同じ値で大きな配列を静的に初期化するために、次のマクロを使用できます。
#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) };
マクロ名は交渉可能です。
配列のすべてのメンバが明示的に初期化されるようにしたい場合は、宣言から次元を省略してください。
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} };
そうではありません。
私はこの構文を使ったいくつかのコードを見ました:
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を書いたとしても、これは物事を順番に保ちます。
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...
配列のサイズを変更します。
上で詳述したように、静的初期化子全体のことを行うことができますが、配列サイズが変わると(配列が適切に初期化子を追加しないとゴミになってしまうと)、大変なことになります。
memsetを使用すると、実行時にランタイムヒットが発生しますが、コードサイズのヒットが正しく行われても、配列サイズの変更による影響は受けません。私がこの解決法を使用するのは、配列が例えば数十個の要素よりも大きい場合です。
配列が静的に宣言されていることが本当に重要な場合は、プログラムを作成してそれをビルドプロセスの一部にするプログラムを作成します。
これは別の方法です:
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拡張を使うことができますか?
上記のコードサンプルは組み込みシステムにあり、他のコンパイラからの光を見ることは決してありません。
ちょっと頬の答え。文を書く
array = initial_value
あなたの好きな配列対応言語(私のものはFortranですが、他にもたくさんあります)でそれをあなたのCコードにリンクしてくださいあなたはおそらくそれを外部関数にまとめることを望みます。
(int配列のような) '通常の'データ型を初期化するために、大かっこ記法を使うことができますが、配列にまだスペースがあるなら、最後の値の後で値をゼロにします:
// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
もし配列がintやintのサイズ、あるいはmem-patternのサイズがintに正確に収まる(つまり、すべて0または0xA5A5A5A5)場合は、 memset() を使用するのが最善です。
それ以外の場合は、インデックスを移動するループ内でmemcpy()を呼び出します。
与えられた値で任意の型の配列を初期化するための速い方法があります。これは大規模配列では非常にうまく機能します。アルゴリズムは以下のとおりです。
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;
}
例: int array [10]; memset(array、-1、10 * sizeof(int));
すべての雑談を切り抜いて、短い答えはあなたがコンパイル時に最適化をオンにした場合、あなたがこれより良いことはしないということです:
int i,value=5,array[1000];
for(i=0;i<1000;i++) array[i]=value;
追加されたボーナス:コードは実際に読みやすいです:)
初期化された配列の要素にアクセスするためのインデックスの順序については、だれも言及していません。私のコード例はそれに実例を与えます。
#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
遅延初期化(つまりクラスメンバコンストラクタの初期化)の場合
int a[4];
unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
a[i] = 0;
#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 ......全体の配列のサイズまで
その日に戻って(そしてそれは良い考えだとは言っていませんが)、最初の要素を設定してから、次のようにします。
memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]);
(memcpyの実装に依存するであろう)それがこれ以上機能するとは限らないが、最初の要素を次の要素に繰り返しコピーすることによって機能する - 構造体の配列に対しても機能する。
私はユーザ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 で試してみることができます。