宣言済みの配列の初期化方法について(C言語)

プログラミング

配列は宣言時に0初期化するのは簡単です。しかし、forループなどで使用した後に使い回す際の初期化は多少手間がかかるのでどうやって書けばいいか考えてみましょう。

配列は初期化しないと不定値

#include <stdio.h>
void main(void)
{
    
    int a[5];
    int x;
    for ( x = 0; x < sizeof(a)/sizeof(int); x++ ){
        printf("%02d:  %d\n", x,a[x] );
    }
}

出力結果は不定な値が入っています。

$main
00:  4195984
01:  0
02:  4195552
03:  0
04:  1180665280

だからwrite前にreadしてしまうと不定値をしようすることになるため、初期化することが大切です。

宣言のときに初期化

#include <stdio.h>

void main(void)
{
    
    <span style="color: #ff0000" class="text-color">int a[5]={0};</span>
    int x;
    for ( x = 0; x < sizeof(a)/sizeof(int); x++ ){
        printf("%02d:  %d\n", x,a[x] );
    }
}

宣言のときに先頭の配列を初期化してやることで、未指定の配列は0に初期化されます。

$main
00:  0
01:  0
02:  0
03:  0
04:  0

応用として、int a[5]={1}; とか記述すると最初の配列のみ1になり、それ以降は0になります。

使用済み配列の初期化1:forループで初期化

一番多く使われるのが配列をforループで配列を1つずつ送って0を代入する方法です。

#include <stdio.h>

void main(void)
{
    
    int *a;
    int x;


    for ( x = 0; x < sizeof(a)/sizeof(int); x++ ){
        printf("%02d:  %d\n", x,a[x] );
    }

<span style="color: #ff0000" class="text-color">    for ( x = 0; x < <span style="background-color: #ffff00" class="background-color">sizeof(a)/sizeof(int)</span>; x++ ){
        a[x] = 0;
    }</span>

    printf("\n ↓ ↓  ↓ ↓\n\n");

    for ( x = 0; x < sizeof(a)/sizeof(int); x++ ){
        printf("%02d:  %d\n", x,a[x] );
    }
    printf("\n");


    return;
}

この方法の面倒なのはループ回数が配列のサイズが固定であればいいのですが、sizeofとかごちゃごちゃした感じのコードになってしまいます。実行結果は一応こうなります。

$main
00:  4195856
01:  0
02:  4195472
03:  0
04:  -101437824

 ↓ ↓  ↓ ↓

00:  0
01:  0
02:  0
03:  0
04:  0

使用済み配列の初期化2:memsetで初期化

memset関数を使用します。ポインタと書き込みたい値(0~0xFF)、サイズを指定するだけです。

#include <stdio.h>
#include <string.h>

void main(void)
{
    
    int *a;
    int x;

    for ( x = 0; x < sizeof(a)/sizeof(int); x++ ){
        printf("%02d:  %d\n", x,a[x] );
    }

    <span style="color: #ff0000" class="text-color">memset( a, 0, sizeof(a) );</span>

    printf("\n ↓ ↓  ↓ ↓\n\n");

    for ( x = 0; x < sizeof(a)/sizeof(int); x++ ){
        printf("%02d:  %d\n", x,a[x] );
    }
    printf("\n");


    return;
}

memsetは1バイト単位での書き込みなります。char型以外でも使用できます。

1行で記述できますし、とても便利なのですが、「皆殺しのmemset」と思うくらい凶悪な一面もあります。

アクセスするメモリのカーネル/アプリ空間や物理/論理とか、アライメントの具合や先頭ポインタが奇数だったりするとどう動くかはハードやコンパイラなど開発環境にとても依存しますので仕事で使用する場合にはプロジェクトの方針を確認の上、単体テストを絶対に実施してください。

まとめ :forループでの初期化が安全でオススメ

  • forループで初期化するのは初心者ぽいけど、ループ回数を間違えなければ安全です。
  • memsetは、本人は正しい使い方だと思っていても、仕様を見ると実は使い方を誤っている場合があります。その場合は、プログラムが落ちる不具合になるかもしれません。
  • 落ちるが怖い、仕様の確認、色々なケースのテストが面倒であれば、安全なforループで初期化しましょう。

当然、forループの回数は間違えたらダメですよ。そこは必ずテストしてください。

とはいえ、今回の例文くらいの内容であればmemsetを使っても全然問題ないです。でも危険性は理解して使ってくださいね。

コメント

タイトルとURLをコピーしました