このページの解説は C99 をベースとしています。
以下は目次です。
定義済みの構造体のすべてのメンバに、0 を入れたいとします。
#include <stdio.h>
struct Data_tag {
int a;
double b;
char c[4];
struct Data_tag* d;
};
void print_data(const struct Data_tag* data)
{
(".a == %d\n", data->a);
printf(".b == %lf\n", data->b);
printf(".c == %s\n", data->c);
printf(".d == %p\n", data->d);
printf}
int main(void)
{
struct Data_tag s;
// s のすべてのメンバに 0 を入れる
(&s);
print_data}
実行した結果、次のように出力されることを望むものとします(浮動小数点数の表示桁数や、ヌルポインタの表現は処理系によって異なる可能性があります)。
実行結果:
.a == 0
.b == 0.000000
.c ==
.d == 0000000000000000
なお、構造体変数を定義した時点で、すべてのメンバに 0 を入れておきたいのであれば、次のように書けばよいですし、そうすべきです。
struct Data_tag s = {0};
初期値の個数が不足している場合、残りのメンバは自動的に 0、0.0、ヌルポインタといった値で初期化されることが保証されています(第26章)。
各要素に1つ1つ代入していきます。単純ですが、確実に正しい結果が得られる方法です。
#include <stdio.h>
struct Data_tag {
int a;
double b;
char c[4];
struct Data_tag* d;
};
void print_data(const struct Data_tag* data)
{
(".a == %d\n", data->a);
printf(".b == %lf\n", data->b);
printf(".c == %s\n", data->c);
printf(".d == %p\n", data->d);
printf}
int main(void)
{
struct Data_tag s;
.a = 0;
s.b = 0.0;
s.c[0] = '\0';
s.d = NULL;
s
(&s);
print_data}
実行結果:
.a == 0
.b == 0.000000
.c ==
.d == 0000000000000000
s.d への代入は NULL の代わりに 0 を使っても構いません。
s.c に関して、有効な文字列として扱う分には、s[0] に ‘\0’ が入っていれば問題ありません。s[0]~s[3] のそれぞれに ‘\0’ を入れたいのなら、memset関数 を使うか、for文で1つずつ入れます(逆引き「配列の全要素を 0 で埋める」を参照)。
構造体変数をクリアする処理として関数化しておくのも良いでしょう。
void clear_data(struct Data_tag* data)
{
->a = 0;
data->b = 0.0;
data->c[0] = '\0';
data->d = NULL;
data}
あとから構造体のメンバの個数を増やしたとき、そのメンバに対して 0 を代入するコードを忘れずに追加しなければならないことに注意が必要です。
【上級】この方法では、構造体メンバの間や、最後のメンバの後ろにあるかもしれないパディング(第26章)の部分に 0 は入りません(代入していないのだから当たり前ですが)。
複合リテラル(第26章)を使うと、すべてのメンバにまとめて 0 を代入できます。
方法① よりもこちらの方が簡単ですし、構造体のメンバが追加されても自動対応できる点でも優れていますが、C99規格で追加された機能であるため、古いコンパイラでは対応していません。
#include <stdio.h>
struct Data_tag {
int a;
double b;
char c[4];
struct Data_tag* d;
};
void print_data(const struct Data_tag* data)
{
(".a == %d\n", data->a);
printf(".b == %lf\n", data->b);
printf(".c == %s\n", data->c);
printf(".d == %p\n", data->d);
printf}
int main(void)
{
struct Data_tag s;
= (struct Data_tag){0};
s
(&s);
print_data}
実行結果:
.a == 0
.b == 0.000000
.c ==
.d == 0000000000000000
初期値は先頭の1つだけ明示すれば、残りはデフォルトの値が使われます。デフォルトの値は、0、0.0、ヌルポインタといったものですから、目的に合っています。
【上級】この方法では、構造体メンバの間や、最後のメンバの後ろにあるかもしれないパディング(第26章)の部分に 0 は入りません。
memset関数を使うと、メモリの範囲を同じ値で埋めることができるため、これを使って、すべてのメンバを 0 で埋める方法が紹介されることがあります。
#include <stdio.h>
#include <string.h>
struct Data_tag {
int a;
double b;
char c[4];
struct Data_tag* d;
};
void print_data(const struct Data_tag* data)
{
(".a == %d\n", data->a);
printf(".b == %lf\n", data->b);
printf(".c == %s\n", data->c);
printf(".d == %p\n", data->d);
printf}
int main(void)
{
struct Data_tag s;
(&s, 0, sizeof(s));
memset
(&s);
print_data}
実行結果:
.a == 0
.b == 0.000000
.c ==
.d == 0000000000000000
memset関数を使うには、<string.h> のインクルードが必要です。
この方法は、多くの処理系では正しい結果が得られますが、うまくいかない場合もあり得ます。メンバの型が、ポインタ型や、浮動小数点型の配列の場合、「0」で埋めることが必ずしもヌルポインタや 0.0 のことを意味しないためです(第34章)。
このサンプルプログラムでいえば、s.a と s.c については結果が保証できますが、s.b と s.d の結果は保証されません。
【上級】この方法では、構造体メンバの間や、最後のメンバの後ろにあるかもしれないパディング(第26章)の部分も 0 で埋められます。
{
の直後と、}
の直前に空白を入れない)return 0;
を削除(C言語編全体でのコードの統一)新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |