🖥️

【C言語超入門】 第15回 構造体

に公開

https://youtu.be/EvCbDU5Ce9E

四国めたん
\textcolor{pink}{四国めたん: }教師役ですわ

ずんだもん
\textcolor{lime}{ずんだもん: }生徒役なのだ

\footnotesize \textcolor{pink}{四国めたん:} 皆さん、こんにちは。四国めたんです

\footnotesize \textcolor{lime}{ずんだもん:} ずんだもんなのだ。こんにちはなのだ

\footnotesize \textcolor{pink}{四国めたん:} 今回もC言語のお勉強をしていきましょう

\footnotesize \textcolor{lime}{ずんだもん:} レッツゴーなのだ

\footnotesize \textcolor{pink}{四国めたん:} 前回は、リンゴの色を表示するプログラムを作成しましたわ

\footnotesize \textcolor{lime}{ずんだもん:} たしかに、そんな感じのサンプルプログラムを作っていたのだ

\footnotesize \textcolor{pink}{四国めたん:} その際、10個分のリンゴの重さと色を保持するために別々の 配列 を使用しましたわ

\footnotesize \textcolor{lime}{ずんだもん:} そのとおりなのだ

\footnotesize \textcolor{pink}{四国めたん:} さて、今回はリンゴの重さと色を1つの 配列 で扱えるように、 構造体 を使っていきますわ

\footnotesize \textcolor{lime}{ずんだもん:} お~、少し複雑になるのだ

構造体でデータをまとめましょう

\footnotesize \textcolor{pink}{四国めたん:} それでは、今回の本題である 構造体 について、お話ししますわ

\footnotesize \textcolor{lime}{ずんだもん:} 待っていたのだ

\footnotesize \textcolor{pink}{四国めたん:} 前回のプログラムの例では、重さを保持する配列"apple_weight"と、色を保持する配列"apple_color"を使いましたわ

\footnotesize \textcolor{lime}{ずんだもん:} 何か問題でもあるのか?

\footnotesize \textcolor{pink}{四国めたん:} いいえ、これはこれで問題ないですわ

\footnotesize \textcolor{pink}{四国めたん:} でも、取り扱う項目が、リンゴの産地や値段等と増えていくとどうなるでしょうか?

\footnotesize \textcolor{lime}{ずんだもん:} 宣言する配列が多くなっていくのだ

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} さらに、リンゴだけではなくオレンジやぶどう等、果物の種類が増えた場合には、収集が付かなくなりますわね

\footnotesize \textcolor{lime}{ずんだもん:} たしかに…

\footnotesize \textcolor{pink}{四国めたん:} それを解消するための仕組みが 構造体 なのですわ

\footnotesize \textcolor{pink}{四国めたん:} 大して難しくはないので、しっかりと理解しましょう

\footnotesize \textcolor{lime}{ずんだもん:} がんばるのだ

構造体は重要です

C++やJavaを含む近年の高級言語では、 クラス が重要なキーワードとなっています

実際、 クラス は、 OOP (Object Oriented Programming)の基礎となる仕組みです

構造体クラス の元になっている仕組みで、非常に重要な概念です

実際、C++言語では、 構造体クラス は、概ね同じ機能を提供します

\footnotesize \textcolor{pink}{四国めたん:} まずは 構造体 を使用して前回のプログラムの例を書き換えて実行してみますわね

#include <conio.h>
#include <stdio.h>

#define SIZE (10)
#define WEIGHT (100)

void main() {
  enum color {
    RED,
    YELLOW,
    GREEN,
  };

  struct fruit {
    int weight;
    enum color fruit_color;
  };

  struct fruit apple[SIZE] = {0};

  for (int i = 0; i < SIZE; i++) {
    apple[i].weight = WEIGHT + i;
    apple[i].fruit_color = i % 3;
  }

  printf("キーボードから数値を入力して下さい。\n");

  int key = _getch();
  while (('0' <= key) && (key <= '9')) {
    int index = key - '0';
    printf("リンゴの重さは%dグラムです\n", apple[index].weight);
    if (apple[index].fruit_color == RED) {
      printf("リンゴの色は赤色です。\n");
    } else if (apple[index].fruit_color == YELLOW) {
      printf("リンゴの色は黄色です。\n");
    } else {
      printf("リンゴの色は緑色です。\n");
    }

    key = _getch();
  }
}

キーボードからの入力表示

\footnotesize \textcolor{lime}{ずんだもん:} 「キーボードから数値を入力して下さい。」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} 変更前と同じですね

\footnotesize \textcolor{pink}{四国めたん:} では、キーボードから\fcolorbox{blue}{lightgray}{0}, \fcolorbox{blue}{lightgray}{1}, \fcolorbox{blue}{lightgray}{2}と入力してみましょう

数字入力後

\footnotesize \textcolor{lime}{ずんだもん:} 入力に合わせて、リンゴの重さと色が表示されているのだ

\footnotesize \textcolor{pink}{四国めたん:} 最後に\fcolorbox{blue}{lightgray}{q}と入力して、プログラムを終了しましょう

構造体の形式を見てみましょう

\footnotesize \textcolor{pink}{四国めたん:} ここが 構造体 を定義している部分ですわ

struct fruit {
  int weight;
  enum color fruit_color;
};

\footnotesize \textcolor{lime}{ずんだもん:} なんか、波括弧"{}"内に変数の宣言みたいなのがあるのだ

\footnotesize \textcolor{pink}{四国めたん:} まぁ、そんな感じですが、実際の 構造体 の定義の形式は、このようになっていますわ

struct 構造体名 {
  型1 メンバー名1;
  型2 メンバー名2;
      :
  型n メンバー名n;
};

\footnotesize \textcolor{lime}{ずんだもん:} structという、新しいキーワードが使われているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、structに続いて 構造体名 を記述しますわ

\footnotesize \textcolor{lime}{ずんだもん:} サンプルコードでは 構造体名 に、小文字で'fruit'となっていたのだ

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} 通常は 構造体名 には小文字を使用し、単語の区切りはアンダースコアを使用しますわね

\footnotesize \textcolor{lime}{ずんだもん:} 変数名の付け方と同じなのだ

\footnotesize \textcolor{pink}{四国めたん:} ちなみに 構造体名 を省略できる場合もあるのですが、今は省略しないようにしてください

\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ

構造体名を省略できる場合

構造体名 を省略できる場合は2つです

1つ目は、 構造体 の定義と同時に変数を宣言する場合です

例えば以下のような形になります

struct {
  int weight;
  enum color fruit_color;
} apple[100] = {0};

なお、同じ 構造体 を使って別の変数の宣言をする場合等は、再度、 構造体 の定義をしなおす必要があるなどのデメリットがあります

2つ目は、typedefキーワードを使って 構造体 にエイリアス名を付ける場合です

typedef struct {
  int weight;
  enum color fruit_color;
} fruit;
fruit apple[100] = {0};

なお、typedefキーワードについては、後の回で説明します

\footnotesize \textcolor{pink}{四国めたん:} 波括弧"{}"の中では変数の宣言と同様に、データの型とメンバー名を羅列しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 区切りはセミコロンを使用しているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、 列挙体 とは異なり、最後の行にもセミコロンは必須なので、忘れないでくださいね

\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ

\footnotesize \textcolor{pink}{四国めたん:} メンバー名は変数名と同様に小文字を使用し、単語の区切りはアンダースコアを使用しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 本当に変数の宣言と同じ感じなのだ

\footnotesize \textcolor{pink}{四国めたん:} そうですね

\footnotesize \textcolor{pink}{四国めたん:} ですので、メンバーの型については変数に指定できるものであれば同じように指定できますわね

\footnotesize \textcolor{lime}{ずんだもん:} サンプルコードではenum colorを指定していたのだ

構造体の変数の宣言と初期化を行います

\footnotesize \textcolor{lime}{ずんだもん:} ところで 構造体 の変数の宣言と初期化は、どのように行うのだ?

\footnotesize \textcolor{pink}{四国めたん:} 通常の型の変数や 列挙体 の変数を宣言、初期化する場合と概ね同じですわ

\footnotesize \textcolor{pink}{四国めたん:} 実際にはstruct 構造体名 変数名 = { 初期値0, 初期値1, ... , 初期値n };という形式になりますわね

\footnotesize \textcolor{lime}{ずんだもん:} 初期値0が最初のメンバーの初期値、初期値1が2番目のメンバーの初期値ということか?

\footnotesize \textcolor{pink}{四国めたん:} はい、その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} 初期値の順番は 構造体 を定義した時のメンバーの指定順と同じになりますわね

\footnotesize \textcolor{pink}{四国めたん:} 例えばstruct fruitの宣言、初期化はstruct fruit grape = { 100, GREEN };のようになりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 変数名に"grape"(ぶどう)を使っているのは、 構造体 のイメージがフルーツだからか?

\footnotesize \textcolor{pink}{四国めたん:} そうですわね

\footnotesize \textcolor{pink}{四国めたん:} なお配列と同様にstruct fruit grape = { 0 };のように初期値に0のみを指定できますわ

\footnotesize \textcolor{lime}{ずんだもん:} 全体が0に初期化されるのか…

構造体の配列の宣言と初期化を行います

\footnotesize \textcolor{lime}{ずんだもん:} ところで、サンプルプログラムでは、 構造体配列 を使っていたのだ

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{lime}{ずんだもん:} 構造体配列 の宣言と初期化は、どのように行うのだ?

\footnotesize \textcolor{pink}{四国めたん:} 形式としては、このようになりますわ

struct 構造体名 配列名[サイズ] = {
  { インデックス0の初期値0, インデックス0の初期値1, ... , インデックス0の初期値n },
  { インデックス1の初期値0, インデックス1の初期値1, ... , インデックス1の初期値n },
      :
      :
  { インデックスmの初期値0, インデックスmの初期値1, ... , インデックスmの初期値n },
};

\footnotesize \textcolor{lime}{ずんだもん:} う~ん、ややこしいのだ

\footnotesize \textcolor{pink}{四国めたん:} 基本的には、配列の各要素毎に初期値を指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} forループを使って初期化できれば、その方が簡単なのだ

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} 全体を0で初期化する場合には、struct fruit apple[SIZE] = { 0 };と0を1つ指定するだけでOKですわ

\footnotesize \textcolor{lime}{ずんだもん:} 構造体 のメンバーについては、気にする必要はないのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、特に気にする必要はありませんわね

構造体のメンバーにアクセスします

\footnotesize \textcolor{lime}{ずんだもん:} ところで 構造体 の各メンバーは、どのように参照するのだ?

\footnotesize \textcolor{pink}{四国めたん:} 構造体 の各メンバーへは、ピリオド . を介してアクセスしますわ

\footnotesize \textcolor{pink}{四国めたん:} 実際には構造体の変数名.メンバー名という形になりますわね

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} サンプルプログラムではforループ内の記述apple[i].weight = WEIGHT + i;apple[i].fruit_color = i % 3;が相当しますわね

\footnotesize \textcolor{pink}{四国めたん:} 参照についてもwhileループ内の最初のprintf("リンゴの重さは%dグラムです\n", apple[index].weight);のように行うことができますわ

まとめ

\footnotesize \textcolor{pink}{四国めたん:} お疲れさまでした

\footnotesize \textcolor{lime}{ずんだもん:} おつかれさまなのだ

\footnotesize \textcolor{pink}{四国めたん:} 以上で 構造体 についての解説を終了しますわ

Discussion