Cに大きな配列があります(違いがある場合はC ++ではありません)。同じ値のすべてのメンバーを初期化したい。
私はかつてこれを行う簡単な方法を知っていたと誓うことができました。memset()
私の場合は使用できますが、C構文に組み込まれている方法はありませんか?
memset()
具体的な議論は:stackoverflow.com/questions/7202411/...私はそれだけで0のために働くと思う
Cに大きな配列があります(違いがある場合はC ++ではありません)。同じ値のすべてのメンバーを初期化したい。
私はかつてこれを行う簡単な方法を知っていたと誓うことができました。memset()
私の場合は使用できますが、C構文に組み込まれている方法はありませんか?
memset()
具体的な議論は:stackoverflow.com/questions/7202411/...私はそれだけで0のために働くと思う
回答:
その値が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値へのポインターなどに初期化されます)
コンパイラがGCCの場合、次の構文を使用できます。
int array[1024] = {[0 ... 1023] = 5};
詳細な説明を確認してください:http : //gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html
int
静的データ(256 K)に65536 秒を追加する必要があります。これは、実際に確認したサイズの増加です。
int
ように、静的に65536 秒を初期化int foo1 = 1, foo2 = 1, ..., foo65536 =1;
すると、同じサイズが増加します。
bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}
場合、完全な形式よりも読みやすいかどうかはわかりません。
複数のコピーと貼り付けなしで、同じ値で大きな配列を静的に初期化するには、マクロを使用できます。
#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) };
マクロ名は交渉可能です。
VAL_1X
が単一の整数ではなくリストの場合も、このメソッドを使用できることに注意してください。移行可能な状態と同様に、これは、EEPROMまたはフラッシュメモリの初期値を定義する組み込みシステムでの方法でもあります。どちらの場合も使用できませんmemset()
。
配列のすべてのメンバーが明示的に初期化されるようにするには、宣言から次元を省略します。
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} };
ではありません。
int myPoints[10][] = { { 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-valueの一部が順不同で記述された場合でも、物事の順序が保持されます。
このテクニックの詳細については、こちらとこちらをご覧ください。
char const *array[] = { ... };
たりchar const * const array[] = { ... };
、にしたりすることもできますよね。
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(myArray, VALUE, ARRAY_SIZE);
上記のように静的イニシャライザ全体を実行できますが、配列サイズが変更されると(配列が大きくなると、適切な追加のイニシャライザを追加しないとガベージが発生します)、それは本当の厄介です。
memsetは、作業を実行するためのランタイムヒットを提供しますが、配列サイズの変更の影響を受けないコードサイズヒットはありません。配列がたとえば数十の要素よりも大きい場合は、ほとんどすべての場合にこのソリューションを使用します。
配列が静的に宣言されていることが本当に重要な場合は、プログラムを作成してビルドプロセスの一部にするプログラムを作成します。
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},
};
見る:
指定されたinits
次に、質問をします:C拡張機能はいつ使用できますか?
上記のコードサンプルは組み込みシステムにあり、別のコンパイラーからの光を見ることはありません。
指定された値で任意のタイプの配列を初期化する高速な方法があります。大規模な配列で非常にうまく機能します。アルゴリズムは次のとおりです。
ための1 000 000
素子int
アレイは規則的なループ初期化(I5、2個のコア、2.3GHz帯、4GiBメモリ、64ビット)よりも高速の4倍です。
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;
}
memfill()
コードの所要時間は約1200 µsです。ただし、後続の反復では、ループに約900〜1000 µsかかりますが、memfill()
コードには1000〜1300 µsかかります。最初の反復は、おそらくキャッシュを埋める時間に影響されます。テストを逆にすると、memfill()
最初は遅い。
初期化された配列の要素にアクセスするためのインデックスの順序については誰も言及していません。私のサンプルコードは、説明的な例を示しています。
#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
<iostream>
有効でないC
としてstd::cout
、std::cin
などがその一部である、std::namespace
そしてC
サポートしていませんnamespaces
。代わりに使用<stdio.h>
してみてくださいprintf(...)
。
すべてのおしゃべりを切り抜けると、簡単に言えば、コンパイル時に最適化をオンにすると、これ以上の効果は得られません。
int i,value=5,array[1000];
for(i=0;i<1000;i++) array[i]=value;
追加ボーナス:コードは実際には読みやすいです:)
ユーザー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];
宣言時に直接初期化されないことですが、次のコードブロックまたは関数呼び出しは、配列の各要素を必要な同じ値に初期化します。他の注意点は、サポートinitializing function
する各for を作成するtype
必要があり、printArray()
これらのタイプをサポートするように関数を変更する必要があることです。
私は元の質問がC ++ではなくCを明示的に言及していることを知っていますが、あなた(私のように)がC ++配列の解決策を探してここに来た場合、ここにきちんとしたトリックがあります:
コンパイラがフォールド式をサポートしている場合は、テンプレートマジックを使用して、必要なstd::index_sequence
値で初期化リストを生成できます。そしてあなたはconstexpr
それを平等にして上司のように感じることができます:
#include <array>
/// [3]
/// This functions's only purpose is to ignore the index given as the second
/// template argument and to always produce the value passed in.
template<class T, size_t /*ignored*/>
constexpr T identity_func(const T& value) {
return value;
}
/// [2]
/// At this point, we have a list of indices that we can unfold
/// into an initializer list using the `identity_func` above.
template<class T, size_t... Indices>
constexpr std::array<T, sizeof...(Indices)>
make_array_of_impl(const T& value, std::index_sequence<Indices...>) {
return {identity_func<T, Indices>(value)...};
}
/// [1]
/// This is the user-facing function.
/// The template arguments are swapped compared to the order used
/// for std::array, this way we can let the compiler infer the type
/// from the given value but still define it explicitly if we want to.
template<size_t Size, class T>
constexpr std::array<T, Size>
make_array_of(const T& value) {
using Indices = std::make_index_sequence<Size>;
return make_array_of_impl(value, Indices{});
}
// std::array<int, 4>{42, 42, 42, 42}
constexpr auto test_array = make_array_of<4/*, int*/>(42);
static_assert(test_array[0] == 42);
static_assert(test_array[1] == 42);
static_assert(test_array[2] == 42);
static_assert(test_array[3] == 42);
// static_assert(test_array[4] == 42); out of bounds
私は質問に要件がないので、解決策は一般的である必要があります:初期メンバー値を持つ、指定されていない可能性のある構造要素から構築された、指定されていない可能性のある多次元配列の初期化:
#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
sizeof(void)
が有効かどうかさえわかりません。
memcpy()
宛先スペースと重複するため、これは未定義の動作を呼び出します。の単純な実装でmemcpy()
は機能しますが、システムで機能させる必要はありません。
昔は(それが良い考えだとは言いませんが)、最初の要素を設定してから、次のようにします。
memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]);
(memcpyの実装に依存する)それが機能するかどうかはわかりませんが、最初の要素を次の要素に繰り返しコピーすることで機能します。構造体の配列でも機能します。
memcpy
、オーバーラップの場合にボトムアップまたはトップダウンのコピー順序のように指定された機能を提供するはずでしたが、そうではありませんでした。
並行して言うと、コンマ演算子を式と組み合わせて使用すると、それが可能になると思います。
a[1]=1, a[2]=2, ..., a[indexSize];
または、単一の構成で意味する場合は、forループで行うことができます。
for(int index = 0, value = 10; index < sizeof(array)/sizeof(array[0]); index++, value--)
array[index] = index;
//引数リストのカンマ演算子は、上記の並列演算子ではないことに注意してください。
配列のデクレレーションを初期化できます。
array[] = {1, 2, 3, 4, 5};
malloc / calloc / sbrk / alloca / etcを呼び出して、ストレージの固定領域をオブジェクトに割り当てることができます。
int *array = malloc(sizeof(int)*numberOfListElements/Indexes);
次の方法でメンバーにアクセスします。
*(array + index)
等。
enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … };
およびstruct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };
。省略記号を削除すると…
、これらのフラグメントはC99またはC11でコンパイルされます。