使用済みの構造体の初期化(C言語)

プログラミング

構造体は宣言での初期化は簡単ですが、使用済みの構造体を初期化するにはどうするといいでしょうか?考えてみます。

構造体宣言での初期化

#include <stdio.h>

typedef struct {
    char name[50];
    int year;
    int month;
    int day;
} birthday_t;

void main(void)
{
    birthday_t test;

    birthday_t test2 ={{0}};

    birthday_t fujita = {
    {"fujita"},
    2021,5,5
    };
    
    printf("test1[%s]  ",test1.name);
    printf("%d/%d/%d\n",test1.year,test1.month,test1.day);

    printf("test2[%s]  ",test2.name);
    printf("%d/%d/%d\n",test2.year,test2.month,test2.day);

    printf("fujita[%s] ",fujita.name);
    printf("%d/%d/%d\n",fujita.year,fujita.month,fujita.day);

    return;
}

test1は未初期化、test2はzero(0)初期化、fujitaは適切な値を入れた初期化した場合の出力結果はこちら。

test1[]  32766/0/0
test2[]  0/0/0
fujita[fujita] 2021/5/5

test1は不定値が出力されました。それ以外は正常に値が格納されていました。

使用済みの構造体の初期化方法(初期化済みローカル変数を使う)

いろいろな方法があるのですが、初期化済み構造体をコピーする方法を紹介します。

#include <stdio.h>

typedef struct {
    char name[50];
    int year;
    int month;
    int day;
} birthday_t;

void main(void)
{
    birthday_t test1;

    birthday_t fujita = {
    {"fujita"},
    2021,5,5
    };
    
    printf("fujita[%s] ",fujita.name);
    printf("%d/%d/%d\n",fujita.year,fujita.month,fujita.day);

    {
        birthday_t birthday_zero ={{0}};
        fujita = birthday_zero;
    }

    printf("fujita[%s] ",fujita.name);
    printf("%d/%d/%d\n",fujita.year,fujita.month,fujita.day);

    return;
}

ハイライトのところで新たに初期化済みローカル変数を宣言してそれを使用済み構造体にコピーしています。

実行結果は下記の通り。ちゃんと初期化されています。

$main
fujita[fujita] 2021/5/5
fujita[] 0/0/0

これのメリットは構造体のメンバーが追加されてもメンテナンスが不要であることです。

デメリットは、もともとの構造体が配列になっているとforループが必要になったり、初期化用の構造体も配列にしてしまうと更にたくさんのスタックメモリーが大量に必要になりますので、注意が必要です。

使用済みの構造体の初期化方法(memsetを使う)

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

typedef struct {
    char name[50];
    int year;
    int month;
    int day;
} birthday_t;

void main(void)
{
    birthday_t test1;

    birthday_t fujita = {
    {"fujita"},
    2021,5,5
    };
    
    printf("fujita[%s] ",fujita.name);
    printf("%d/%d/%d\n",fujita.year,fujita.month,fujita.day);

    memset(&fujita, 0, sizeof(birthday_t) );
 
    printf("fujita[%s] ",fujita.name);
    printf("%d/%d/%d\n",fujita.year,fujita.month,fujita.day);

    return;
}

ハイライトのところでmemsetを使用しています。

大体これで大丈夫です。これだと構造体配列もサイズを変更すれば対応出来ますので安心です。構造体が追加されたときにメンテが不要になるようにsizeofでサイズ指定するようにしてください。

注意は配列の場合は掛け算する配列数を間違えると最悪ダンプして落ちてしまいますので丁寧にテストしておきましょう。

まとめ

  • 小型の構造体であれば、初期化用構造体を宣言してコピーするのが安全でおすすめ。
  • 大型の構造体の場合は、memsetでクリアーするのが簡単です。→クリアサイズを間違えると不具合になります。

コメント

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