第16回|C言語で構造体の基本を学ぶ:複数の値を1つのまとまりとして扱う

当サイトでは、コンテンツの一部に広告を掲載しています。
第16回|C言語で構造体の基本を学ぶ:複数の値を1つのまとまりとして扱う

はじめてのC言語 | 第16回

目次

はじめに

前回は、関数と配列の受け渡しを学びました。
今回は、C言語の「構造体」を学びます。

構造体を使うと、複数の値を1つのまとまりとして扱えます。
たとえば、学生の名前、年齢、点数を1つのデータとしてまとめることができます。

この回の目的は次の5点です。

  • 構造体が何をするための仕組みかを理解する
  • struct を使った型の作り方を学ぶ
  • メンバへのアクセス方法を覚える
  • 構造体を関数に渡す基本を確認する
  • 構造体の配列を扱う基本を学ぶ

構造体とは何か

構造体は、複数の値を1つにまとめるための仕組みです。
配列は同じ型の値をまとめますが、構造体は異なる型の値をまとめることができます。

たとえば学生の情報を扱う場合、次のような値が必要になることがあります。

  • 名前
  • 年齢
  • 点数

これらを別々の変数で管理すると、データが増えたときに扱いにくくなります。
構造体を使うと、これらを1つのまとまりとして扱えます。

構造体を定義する

構造体は struct を使って定義します。

struct Student {
    char name[20];
    int age;
    int score;
};

この定義では、Student という構造体を作っています。
中には、name age score という3つのメンバがあります。

構造体を使って表示する

ソースコード

struct_basic.c という名前で保存します。

#include <stdio.h>

struct Student {
    char name[20];
    int age;
    int score;
};

int main(void) {
    struct Student s = {"Alice", 20, 85};

    printf("%s\n", s.name);
    printf("%d\n", s.age);
    printf("%d\n", s.score);

    return 0;
}

実行手順

1. 作業ディレクトリに移動する

cd ~/Desktop

2. コンパイルする

clang struct_basic.c -o struct_basic

3. 実行する

./struct_basic

実行結果:

Alice
20
85

コードの読み方

struct Student

struct Student {
    char name[20];
    int age;
    int score;
};

これは構造体の定義です。
struct Student という型を作っています。

struct Student s

struct Student s = {"Alice", 20, 85};

これは、struct Student 型の変数 s を作っています。
"Alice"name20age85score に入ります。

s.name

printf("%s\n", s.name);

構造体の中の値にアクセスするときは、. を使います。
s.name は、構造体変数 sname メンバを表します。

メンバに代入する

構造体のメンバには、あとから値を代入できます。

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

struct Student {
    char name[20];
    int age;
    int score;
};

int main(void) {
    struct Student s;

    strcpy(s.name, "Bob");
    s.age = 19;
    s.score = 92;

    printf("%s %d %d\n", s.name, s.age, s.score);

    return 0;
}

実行結果:

Bob 19 92

文字列の代入に注意する

namechar 配列です。
そのため、あとから文字列を入れるときに次のようには書けません。

s.name = "Bob";

文字列をコピーするには、前回学んだ strcpy を使います。

strcpy(s.name, "Bob");

構造体を関数に渡す

構造体は関数に渡すこともできます。

#include <stdio.h>

struct Student {
    char name[20];
    int age;
    int score;
};

void print_student(struct Student s) {
    printf("%s %d %d\n", s.name, s.age, s.score);
}

int main(void) {
    struct Student s = {"Alice", 20, 85};

    print_student(s);

    return 0;
}

実行結果:

Alice 20 85

関数の引数として渡せる

print_student は、struct Student 型の値を受け取る関数です。

void print_student(struct Student s)

このように書くことで、構造体の中の複数の値をまとめて関数に渡せます。

構造体の配列

構造体は配列にすることもできます。
複数人の学生情報を扱う場合に便利です。

#include <stdio.h>

struct Student {
    char name[20];
    int age;
    int score;
};

int main(void) {
    struct Student students[3] = {
        {"Alice", 20, 85},
        {"Bob", 19, 92},
        {"Carol", 21, 78}
    };
    int i;

    for (i = 0; i < 3; i++) {
        printf("%s %d %d\n", students[i].name, students[i].age, students[i].score);
    }

    return 0;
}

実行結果:

Alice 20 85
Bob 19 92
Carol 21 78

students[i].name

students[i] は、構造体配列の i 番目の要素です。
その中の name メンバにアクセスするため、students[i].name と書きます。

構造体配列を関数に渡す

前回学んだ配列の受け渡しと同じように、構造体配列も関数に渡せます。

#include <stdio.h>

struct Student {
    char name[20];
    int age;
    int score;
};

void print_students(struct Student students[], int size) {
    int i;

    for (i = 0; i < size; i++) {
        printf("%s %d %d\n", students[i].name, students[i].age, students[i].score);
    }
}

int main(void) {
    struct Student students[3] = {
        {"Alice", 20, 85},
        {"Bob", 19, 92},
        {"Carol", 21, 78}
    };

    print_students(students, 3);

    return 0;
}

実行結果:

Alice 20 85
Bob 19 92
Carol 21 78

構造体配列を関数に渡す場合も、要素数を一緒に渡します。
関数側では、配列の要素数を自動では判断できないためです。

初心者がつまずきやすい点

struct Student まで含めて型名である

この段階では、型名は Student だけではなく struct Student です。

struct Student s;

typedef を使うと短く書けますが、この回では基本の struct Student という書き方を使います。

メンバアクセスには .使う

構造体変数のメンバにアクセスするときは . を使います。

s.score = 90;

s->score という書き方もありますが、これは構造体ポインタを扱うときに使います。
この回では、まず . を使う形を理解します。

文字列メンバに直接代入しない

char name[20]; のような配列メンバには、あとから = で文字列を代入できません。
文字列をコピーするときは strcpy を使います。

よくあるエラー

error: must use ‘struct’ tag to refer to type ‘Student’

原因: struct Student と書くべきところを Student だけで書いています。
対処: この回では struct Student と書きます。

正しい例:

struct Student s;

error: array type ‘char[20]’ is not assignable

原因: char 配列のメンバに = で文字列を代入しています。
対処: strcpy を使います。

誤った例:

s.name = "Bob";

正しい例:

strcpy(s.name, "Bob");

実行結果がおかしい

原因: 構造体配列を処理するときに、要素数を間違えている可能性があります。
対処: 配列の要素数とループ条件を確認します。

練習用コード

商品情報を表示する

#include <stdio.h>

struct Product {
    char name[20];
    int price;
};

int main(void) {
    struct Product p = {"Pen", 120};

    printf("%s %d\n", p.name, p.price);

    return 0;
}

構造体配列から合計点を求める

#include <stdio.h>

struct Student {
    char name[20];
    int age;
    int score;
};

int sum_scores(struct Student students[], int size) {
    int i;
    int sum = 0;

    for (i = 0; i < size; i++) {
        sum += students[i].score;
    }

    return sum;
}

int main(void) {
    struct Student students[3] = {
        {"Alice", 20, 85},
        {"Bob", 19, 92},
        {"Carol", 21, 78}
    };

    printf("%d\n", sum_scores(students, 3));

    return 0;
}

実行結果:

255

まとめ

今回のポイントは次のとおりです。

  • 構造体は複数の値を1つのまとまりとして扱う仕組みである
  • 構造体は struct を使って定義する
  • 構造体の中の値をメンバと呼ぶ
  • メンバにアクセスするときは . を使う
  • 構造体は関数に渡せる
  • 構造体は配列として複数まとめて扱える
  • 構造体配列を関数に渡すときも要素数を一緒に渡す

この回では、構造体の基本を学びました。
構造体を使うと、名前、年齢、点数のような複数の値を1つのデータとして扱えます。

次回予告

次は、ファイル入出力の基本を学びます。
データを画面に表示するだけでなく、ファイルに保存したり、ファイルから読み込んだりすることができるようになります。

あわせて読みたい
第17回|C言語でファイル入出力の基本を学ぶ:ファイルに書き込み、ファイルから読み込む はじめてのC言語 | 第17回 はじめに 前回は、構造体の基本を学びました。今回は、C言語でファイルを扱う方法を学びます。 これまでのプログラムでは、結果を画面に表...

さらに学びたいあなたへ

用途ごとに選ぶ Linux のおすすめ本

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

のいのアバター のい UNIX Cafe マスター

Macintosh Color Classicから始まった旅は、長いWindows時代を経て、Windows10のサポート終了をきっかけにUNIXの世界へ戻ってきました。UNIX Cafeでは、UNIX・Linux・そしてMacな世界を、むずかしい言葉を使わず、物語のように書いています。プログラミングは、アイデアをコンピューターに伝えるための言葉です。簡単な単語と文法を覚えれば、誰でもコマンドを使えます。ぜひ一度、やさしいプログラミングの世界をのぞいてみてください。

Created by UNIX Cafe

目次