趣味の開発ノート

ITの学習やプログラミング・ノーコードアプリ開発のことなど。

【C言語】構造体の宣言・定義・初期化とメンバへのアクセス(printf, scanf)についてまとめ

C言語を学習中。
ポインタを学習後、今度は構造体について学習している。

scanf()関数でユーザー入力を受け付けて構造体のメンバーに代入するという処理をやりたいのだけど、複雑になってきてよくわからなくなってきたので、一通り整理する。

ポイント整理

(1)構造体の宣言

何はともあれ、最初に宣言しておかなければ構造体を使えない。
グローバル領域で宣言しておく。

// 構造体の宣言
struct STATUS{
    char name[21];
    int hp;
    int ap;
};

(2)構造体を定義・初期化してprintf()で出力する

構造体変数の定義と初期化を行い、各メンバーへアクセスしてprintf()出力するやり方。
構造体変数を使用したい関数内で記述する。

// 構造体の定義・初期化
struct STATUS yuusha = {"ゆうしゃ", 8, 2};

// 構造体yuushaのメンバーをprintfで出力
// 出力結果 -> ゆうしゃ:最大HP = 8, 攻撃力 = 2
printf("%s:最大HP = %d, 攻撃力 = %d\n", yuusha.name, yuusha.hp, yuusha.ap);

(3)定義・初期化した構造体の値を書き換える

構造体変数の定義と初期化を行い、各メンバーのにアクセスして値を再代入するやり方。
int型はそのまま代入が可能。
string型はstrcpy()を使うためstring.hのインクルードが必要。#include <string.h>の一文をグローバル領域の先頭に記述する。

// 構造体の定義・初期化
struct STATUS monster = {"モンスター", 10, 1};

// 構造体(初期化済み)の各メンバーへ個別に再代入
strcpy(monster.name, "スライム");  // string.hのインクルードが必要
monster.hp = 3;
monster.ap = 1;

// 構造体monsterのメンバーをprintfで出力
// 出力結果 -> スライム:最大HP = 3, 攻撃力 = 1
printf("%s:最大HP = %d, 攻撃力 = %d\n", monster.name, monster.hp, monster.ap);

(4)構造体(定義のみ)の各メンバーに代入する

定義のみで初期化していない場合でも、やり方は先程の再代入と変わらない。
こちらもstring型はstrcpy()を使うためstring.hのインクルードが必要。

// 構造体の定義
struct STATUS enemy;

// 構造体(定義のみ)enemyの各メンバーへ個別に代入
strcpy(enemy.name, "カンダタ");  // string.hのインクルードが必要
enemy.hp = 18;
enemy.ap = 1;

// 構造体enemyのメンバーをprintfで出力
// 出力結果 -> カンダタ:最大HP = 18, 攻撃力 = 1
printf("%s:最大HP = %d, 攻撃力 = %d\n", enemy.name, enemy.hp, enemy.ap);

(5)構造体の各メンバーにscanf()関数で入力を受け付けて代入する

今回目標としてた処理。
前提として、scanf()はユーザー入力を受け付けて指定した変数に格納する、というような事が行われる。
その時にscanf()関数には変数のアドレスを渡してやる必要がある。

// 構造体の定義
struct STATUS member;

// 構造体の各メンバーへscanfで代入
printf("名前を入力 > ");
scanf("%s", member.name);   // 第2引数はアドレスを指定。str型配列は変数名そのものがアドレスを示す
printf("最大HPを入力 > ");
scanf("%d", &member.hp);   // 第2引数はアドレスを指定。int型は変数名にアドレス演算子&をつける
printf("攻撃力を入力 > ");
scanf("%d", &member.ap);

// 構造体memberのメンバーをprintfで出力
// 出力結果 -> (ユーザー入力値)
printf("%s:最大HP = %d, 攻撃力 = %d\n", member.name, member.hp, member.ap);

サンプルコード

/*
    構造体の宣言、定義・初期化
    構造体のメンバーへアクセスしてprintfで表示
    構造体のメンバー(int, char)にscanfで代入
*/

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

// 構造体の宣言
struct STATUS{
    char name[21];
    int hp;
    int ap;
};

int main()
{
    // 構造体の定義・初期化
    struct STATUS yuusha = {"ゆうしゃ", 8, 2};
    struct STATUS monster = {"モンスター", 10, 1};
    struct STATUS enemy;
    struct STATUS member;

    // 構造体yuushaのメンバーをprintfで出力
    // 出力結果 -> ゆうしゃ:最大HP = 8, 攻撃力 = 2
    printf("%s:最大HP = %d, 攻撃力 = %d\n", yuusha.name, yuusha.hp, yuusha.ap);

    // 構造体(初期化済み)の各メンバーへ個別に再代入
    strcpy(monster.name, "スライム");  // string.hのインクルードが必要
    monster.hp = 3;
    monster.ap = 1;

    // 構造体monsterのメンバーをprintfで出力
    // 出力結果 -> スライム:最大HP = 3, 攻撃力 = 1
    printf("%s:最大HP = %d, 攻撃力 = %d\n", monster.name, monster.hp, monster.ap);

    // 構造体(定義のみ)enemyの各メンバーへ個別に代入
    strcpy(enemy.name, "カンダタ");  // string.hのインクルードが必要
    enemy.hp = 18;
    enemy.ap = 1;

    // 構造体enemyのメンバーをprintfで出力
    // 出力結果 -> カンダタ:最大HP = 18, 攻撃力 = 1
    printf("%s:最大HP = %d, 攻撃力 = %d\n", enemy.name, enemy.hp, enemy.ap);

    // 構造体の各メンバーへscanfで代入
    printf("名前を入力 > ");
    scanf("%s", member.name); // 文字列配列は変数名そのものがアドレスを示す
    printf("最大HPを入力 > ");
    scanf("%d", &member.hp);
    printf("攻撃力を入力 > ");
    scanf("%d", &member.ap);

    // 構造体senshiのメンバーをprintfで出力
    // 出力結果 -> (ユーザー入力値)
    printf("%s:最大HP = %d, 攻撃力 = %d\n", member.name, member.hp, member.ap);

    return 0;
}