web-dev-qa-db-ja.com

Cでの配列の宣言と初期化

最初に宣言してからCで配列を初期化する方法はありますか?

これまでのところ、私はこのような配列を初期化しています:

int myArray[SIZE] = {1,2,3,4....};

しかし、私はこのような何かをする必要があります

int myArray[SIZE];

myArray = {1,2,3,4....};
51
Dave H

C99では、memcpyと組み合わせて複合リテラルを使用してそれを行うことができます

memcpy(myarray, (int[]) { 1, 2, 3, 4 }, sizeof myarray);

(ソースのサイズとターゲットのサイズが同じであると仮定します)。

C89/90では、追加の「ソース」配列を宣言することでそれをエミュレートできます

const int SOURCE[SIZE] = { 1, 2, 3, 4 }; /* maybe `static`? */
int myArray[SIZE];
...
memcpy(myarray, SOURCE, sizeof myarray);
31
AnT

最初に宣言してからCで配列を初期化する方法はありますか?

がある!ただし、説明した方法は使用しません。

コンマ区切りリストで初期化することはできません。これは宣言でのみ許可されます。ただし、以下で初期化できます...

myArray[0] = 1;
myArray[1] = 2;
...

または

for(int i = 1; i <= SIZE; i++)
{
  myArray[i-1] = i;
}
4
Jacob

これは、配列サイズの不一致に関するNyanのコメントとともに、AndreyTが受け入れた回答の補遺です。 5番目の要素のゼロへの自動設定には同意しません。おそらく5 --1,2,3,4の後の数字です。したがって、異なるサイズの配列をコピーしようとすると、memcpy()のラッパーを使用してcompile-timeエラーを生成することをお勧めします。

#define Memcpy(a,b) do {                    /* copy arrays */       \
    ASSERT(sizeof(a) == sizeof(b) &&        /* a static assert */   \
           sizeof(a) != sizeof((a) + 0));   /* no pointers */       \
    memcpy((a), (b), sizeof (b));           /* & unnecesary */      \
    } while (0)                             /* no return value */

配列の長さが1の場合、このマクロはコンパイル時エラーを生成します。これはおそらく機能です。

マクロを使用しているため、C99複合リテラルには追加の括弧のペアが必要なようです。

Memcpy(myarray, ((int[]) { 1, 2, 3, 4 }));

ここで、ASSERT()は「静的アサート」です。まだ自分のものを持っていない場合は、いくつかのプラットフォームで以下を使用します。

#define CONCAT_TOKENS(a, b) a ## b
#define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b)
#define ASSERT(e) enum {EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)}
#define ASSERTM(e,m) /* version of ASSERT() with message */ \
    enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)}
2
Joseph Quinsey

宣言時に初期化できないのはなぜですか?

どのCコンパイラを使用していますか? C99をサポートしていますか?

C99をサポートしている場合は、必要な場所で変数を宣言し、宣言時に変数を初期化できます。

私がそれをしないことについて考えることができる唯一の言い訳は、それを宣言する必要があるが、それを使用する前に早期終了を行うので、初期化子が無駄になるからです。ただし、そのようなコードは本来のようにきれいに編成されておらず、書くことができるので問題にはならないと思います。

1

初期化後に一度に配列に値を割り当てることはできません。最適な代替方法は、ループを使用することです。

for(i=0;i<N;i++)
{
     array[i] = i;
}

--array[0] = 1などのような値をハードコーディングして割り当てることができます。

Memcpyは、配列にデータが既に保存されている場合にも使用できます。

0
Tush_08

OPは、質問からいくつかの重要な情報を除外し、回答へのコメントのみに入れました。

宣言後に初期化する必要があります。条件によって異なるため、このようなことを意味しますint myArray [SIZE]; if(condition1){myArray {x1、x2、x3、...}} else if(condition2){myArray {y1、y2、y3、...}} 。等々...

これを念頭に置いて、すべての可能な配列を何らかの形でデータに保存する必要があるため、memcpyは必要ない(または必要ない)ため、ポインターと2D配列のみが必要です。

//static global since some compilers build arrays from instruction data
//... notably not const though so they can later be modified if needed
#define SIZE 8
static int myArrays[2][SIZE] = {{0,1,2,3,4,5,6,7},{7,6,5,4,3,2,1,0}};

static inline int *init_myArray(_Bool conditional){
  return myArrays[conditional];
}

// now you can use:
//int *myArray = init_myArray(1 == htons(1)); //any boolean expression

インライン化されていないバージョンでは、x86_64でこのようなアセンブリが生成されます。

init_myArray(bool):
        movzx   eax, dil
        sal     rax, 5
        add     rax, OFFSET FLAT:myArrays
        ret
myArrays:
        .long   0
        .long   1
        .long   2
        .long   3
        .long   4
        .long   5
        .long   6
        .long   7
        .long   7
        .long   6
        .long   5
        .long   4
        .long   3
        .long   2
        .long   1
        .long   0

追加の条件/配列については、myArraysの2を目的の数に変更し、同様のロジックを使用して正しい配列へのポインターを取得します。

0
technosaurus

一度宣言した後に配列を初期化するような特別な方法はありません。

次の3つのオプションのみがあります。

1。)それらを異なる行で初期化します:

int array[SIZE];

array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
//...
//...
//...

しかし、それはあなたが私が推測するものではありません。

2。) forまたはwhileループを使用してそれらを初期化します:

for (i = 0; i < MAX ; i++)  {
    array[i] = i;
}

これは、目標を達成するための最良の方法です。

。)要件が配列自体を1行で初期化することである場合、少なくとも初期化で配列を定義する必要があります。そして、それをコピー先の配列にコピーしますが、そうするメリットはないと思います。その場合、配列を1行で定義して初期化する必要があります。

そして、具体的にあなたがそうしたい理由を尋ねることができますか???

0
Kumar Alok