第10章 演習問題 解答例

10.1 構造体の基本

a10-1-1.c

テストの成績を構造体で管理します。実行結果例を参考に構造体を初期化し値を表示してください。ただし、点数のメンバは要素数5の配列で宣言してください。

【実行結果例】

番号 = 1
氏名 = 安部寛之
国語の点数 = 76
数学の点数 = 82
理科の点数 = 87
社会の点数 = 93
英語の点数 = 88
/* a10-1-1.c */
#include <stdio.h>
#define K 5     /* 科目数 */

struct Test_record {/* 成績構造体 */
    int no;           /* 学生番号   */
    char name[20];    /* 氏名       */
    int ten[K];       /* 点数(国語・数学・理科・社会・英語)*/
};

int main(void)
{
    struct Test_record student = {1, "安部寛之", 76, 82, 87, 93, 88};

    printf("番号 = %d\n", student.no);
    printf("氏名 = %s\n", student.name);
    printf("国語の点数 = %d\n", student.ten[0]);
    printf("数学の点数 = %d\n", student.ten[1]);
    printf("理科の点数 = %d\n", student.ten[2]);
    printf("社会の点数 = %d\n", student.ten[3]);
    printf("英語の点数 = %d\n", student.ten[4]);

    return 0;
}

[Back]

a10-1-2.c

P.336の演習1(a10-1-1.c)で作成した構造体を、次のような5人分の要素で初期化し、学生ごとの合計点を求めてください。

番号氏名点数
国語数学理科社会英語
1安部寛之7682879388
2内山理香5466716476
3小田裕一9345639796
4後藤美希8188728478
5柴崎ユウ5861775688
/* a10-1-2.c */
#include <stdio.h>
#define N 5     /* 人数   */
#define K 5     /* 科目数 */

struct Test_record {/* 成績構造体 */
    int no;           /* 学生番号   */
    char name[20];    /* 氏名       */
    int ten[K];       /* 点数(国語・数学・理科・社会・英語)*/
};

int main(void)
{
    struct Test_record student[N] = 
    {{1, "安部寛之", 76, 82, 87, 93, 88},
     {2, "内山理香", 54, 66, 71, 64, 76},
     {3, "小田裕一", 93, 45, 63, 97, 96},
     {4, "後藤美希", 81, 88, 72, 84, 78},
     {5, "柴崎ユウ", 58, 61, 77, 56, 88}};
    int i, j, total[N] = {0};

    for (i = 0; i < N; i++) {
        for (j = 0; j < K; j++) {
            total[i] += student[i].ten[j];
        }
        printf("%sの合計点は%d\n", student[i].name, total[i]);
    }

    return 0;
}

[Back]

10.2 構造体の活用

a10-2-1.c

次の表を構造体として宣言し初期化してください。初期化した値は表示して確認してください。なお、給与は基本給と各手当を構造体として宣言し、それをネストしてください。

社員情報構造体
社員番号氏名役職勤続年数給与構造体
基本給住宅手当家族手当資格手当
127"滝沢康明""課長"21366780100001500012000
204"加藤ゆい""主任"152836401000006000
272"矢田佐希子"""10228760006000
304"堂本猛"""521770001000012000
/* a10-2-1.c */
#include <stdio.h>
#define N 4     /* 人数 */

typedef struct {     /* 給与       */
    int basic;         /* 基本給   */
    int house;         /* 住宅手当 */
    int family;        /* 家族手当 */
    int qualification; /* 資格手当 */
} Pay;
typedef struct  {    /* 社員情報 */
    int no;            /* 社員番号 */
    char name[20];     /* 氏名     */
    char post[20];     /* 役職     */
    int years;         /* 勤続年数 */
    Pay pay;           /* 給与     */
} Syain_dt;

int main(void)
{
    Syain_dt g[N] = {
        {127, "滝沢康明",   "課長", 21, 366780, 10000, 15000, 12000},
        {204, "加藤ゆい",   "主任", 15, 283640, 10000, 0,     6000},
        {272, "矢田佐希子", "",     10, 228760, 0,     0,     6000},
        {304, "堂本猛",     "",     5,  217700, 0,     10000, 12000}
    };
    int i;

    printf("番号 氏名     役職  勤続 基本給 住宅 家族 資格\n");
    for (i = 0; i < N; i++) {
        printf("%4d %-12s %-6s %4d %6d %5d %5d %5d\n", g[i].no, g[i].name, 
                g[i].post, g[i].years, g[i].pay.basic, 
                g[i].pay.house, g[i].pay.family, g[i].pay.qualification);
    }

    return 0;
}

[Back]

a10-2-2.c

P.344の演習1(a10-2-1.c)で作成した構造体に、次のデータを社員番号で昇順になる位置に挿入してください。

社員情報構造体
社員番号氏名役職勤続年数給与構造体
基本給住宅手当家族手当資格手当
255"小池一平"""12264200000
/* a10-2-2.c */
#include <stdio.h>
#define N 4     /* 人数 */

typedef struct {     /* 給与       */
    int basic;         /* 基本給   */
    int house;         /* 住宅手当 */
    int family;        /* 家族手当 */
    int qualification; /* 資格手当 */
} Pay;
typedef struct  {    /* 社員情報 */
    int no;            /* 社員番号 */
    char name[20];     /* 氏名     */
    char post[20];     /* 役職     */
    int years;         /* 勤続年数 */
    Pay pay;           /* 給与     */
} Syain_dt;

int main(void)
{
    Syain_dt g[N+1] = {
        {127, "滝沢康明",   "課長", 21, 366780, 10000, 15000, 12000},
        {204, "加藤ゆい",   "主任", 15, 283640, 10000, 0,     6000},
        {272, "矢田佐希子", "",     10, 228760, 0,     0,     6000},
        {304, "堂本猛",     "",     5,  217700, 0,     10000, 12000},
    };
    Syain_dt add = {255, "小池一平",   "",     12, 264200, 0,     0,     0};
    int i;

    for (i = N - 1; i >= 0; i--) {
        if (g[i].no > add.no) {
            g[i + 1] = g[i];
            if (i == 0) {
                g[i] = add;
            }
        }
        else {
            g[i + 1] = add;
            break;
        }
    }

    printf("番号 氏名     役職  勤続 基本給 住宅 家族 資格\n");
    for (i = 0; i < N + 1; i++) {
        printf("%4d %-12s %-6s %4d %6d %5d %5d %5d\n", g[i].no, g[i].name, 
                g[i].post, g[i].years, g[i].pay.basic, 
                g[i].pay.house, g[i].pay.family, g[i].pay.qualification);
    }

    return 0;
}

配列に要素を挿入するためには、挿入場所より下の要素をずらす必要があります。そのため、配列の最後から要素の比較と移動を繰り返しながら挿入場所を探します。

[Back]

a10-2-3.c

P.346のs10-2-2.cで宣言した構造体の変数と配列に、キーボードから値を入力し、表示して確認するプログラムを作成してください。

/* a10-2-3.c */
#include <stdio.h>

typedef struct {   /* 円の情報 */
    int x;           /* x座標 */
    int y;           /* y座標 */
    int r;           /* 半径  */
    char color[10];  /* 色    */
} Circle;

int main(void)
{
    Circle c1, c2[1];

    printf("円1のメンバに値を入力してください。座標(x, y) 半径 色\n");
    scanf("%d %d %d %s", &c1.x, &c1.y, &c1.r, c1.color);

    printf("円2のメンバに値を入力してください。座標(x, y) 半径 色\n");
    scanf("%d %d %d %s", &c2[0].x, &c2[0].y, &c2[0].r, c2[0].color);

    printf("円1:(%d, %d) 半径 = %d 色 = %s\n", c1.x, c1.y, c1.r, c1.color);
    printf("円2:(%d, %d) 半径 = %d 色 = %s\n", c2[0].x, c2[0].y, c2[0].r, c2[0].color);

    return 0;
}

[Back]

10.3 構造体へのポインタ

a10-3-1.c

次のデータから該当する社員番号の社員を探し、情報を表示するプログラムを作成してください。

社員情報構造体
社員番号氏名役職勤続年数給与構造体
基本給住宅手当家族手当資格手当
127"滝沢康明""課長"21366780100001500012000
204"加藤ゆい""主任"152836401000006000
255"小池一平"""12264200000
272"矢田佐希子"""10228760006000
304"堂本猛"""521770001000012000
/* a10-3-1.c */
#include <stdio.h>
#define N 5     /* 人数 */

typedef struct {     /* 給与       */
    int basic;         /* 基本給   */
    int house;         /* 住宅手当 */
    int family;        /* 家族手当 */
    int qualification; /* 資格手当 */
} Pay;
typedef struct  {    /* 社員情報 */
    int no;            /* 社員番号 */
    char name[20];     /* 氏名     */
    char post[20];     /* 役職     */
    int years;         /* 勤続年数 */
    Pay pay;           /* 給与     */
} Syain_dt;

int main(void)
{
    Syain_dt g[N] = {
        {127, "滝沢康明",   "課長", 21, 366780, 10000, 15000, 12000},
        {204, "加藤ゆい",   "主任", 15, 283640, 10000, 0,     6000},
        {255, "小池一平",   "",     12, 264200, 0,     0,     0},
        {272, "矢田佐希子", "",     10, 228760, 0,     0,     6000},
        {304, "堂本猛",     "",     5,  217700, 0,     10000, 12000},
    };
    Syain_dt *p = g;
    int i, sno;

    printf("探索する社員番号を入力してください。> ");
    scanf("%d", &sno);

    for (i = 0; i < N; i++) {
        if (sno == p->no) {
            printf("番号 氏名     役職  勤続 基本給 住宅 家族 資格\n");
            printf("%4d %-12s %-6s %4d %6d %5d %5d %5d\n", p->no, p->name, 
                p->post, p->years, p->pay.basic, 
                p->pay.house, p->pay.family, p->pay.qualification);
            break;
        }
        p++;
    }
    if (i == N) {
            printf("該当する番号はありません。\n");
    }

    return 0;
}

このプログラムは、先頭から順番に該当する要素を調べていく線形探索法と呼ばれるアルゴリズムを使っています。線形探索法は単純ですが要素数が多くなると大変に時間がかかります。

[Back]

a10-3-2.c

社員番号が必ず昇順に並んでいるものとしてa10-3-2-1.cの探索を効率的に行うように修正してください。

/* a10-3-2.c */
#include <stdio.h>
#define N 5     /* 人数 */

typedef struct {     /* 給与       */
    int basic;         /* 基本給   */
    int house;         /* 住宅手当 */
    int family;        /* 家族手当 */
    int qualification; /* 資格手当 */
} Pay;
typedef struct  {    /* 社員情報 */
    int no;            /* 社員番号 */
    char name[20];     /* 氏名     */
    char post[20];     /* 役職     */
    int years;         /* 勤続年数 */
    Pay pay;           /* 給与     */
} Syain_dt;

int main(void)
{
    Syain_dt g[N] = {
        {127, "滝沢康明",   "課長", 21, 366780, 10000, 15000, 12000},
        {204, "加藤ゆい",   "主任", 15, 283640, 10000, 0,     6000},
        {255, "小池一平",   "",     12, 264200, 0,     0,     0},
        {272, "矢田佐希子", "",     10, 228760, 0,     0,     6000},
        {304, "堂本猛",     "",     5,  217700, 0,     10000, 12000},
    };
    Syain_dt *p = g;
    int i, sno;

    printf("探索する社員番号を入力してください。> ");
    scanf("%d", &sno);

    for (i = 0; i < N; i++) {
        if (sno == p->no) {
            printf("番号 氏名     役職  勤続 基本給 住宅 家族 資格\n");
            printf("%4d %-12s %-6s %4d %6d %5d %5d %5d\n", p->no, p->name, 
                p->post, p->years, p->pay.basic, 
                p->pay.house, p->pay.family, p->pay.qualification);
            break;
        }
        else if (sno < p->no) {
            printf("該当する番号はありません。\n");
            break;
        }
        p++;
    }
    if (i == N) {
            printf("該当する番号はありません。\n");
    }
    return 0;
}

社員番号が昇順に並んでいるので、探索する番号のほうが配列の番号よりも小さくなった場合には該当する番号がなかったとみなします。

【別解:二分探索法を用いたプログラム】
/* a10-3-2b.c */
#include <stdio.h>
#define N 5     /* 人数 */

typedef struct {     /* 給与       */
    int basic;         /* 基本給   */
    int house;         /* 住宅手当 */
    int family;        /* 家族手当 */
    int qualification; /* 資格手当 */
} Pay;
typedef struct  {    /* 社員情報 */
    int no;            /* 社員番号 */
    char name[20];     /* 氏名     */
    char post[20];     /* 役職     */
    int years;         /* 勤続年数 */
    Pay pay;           /* 給与     */
} Syain_dt;

int main(void)
{
    Syain_dt g[N] = {
        {127, "滝沢康明",   "課長", 21, 366780, 10000, 15000, 12000},
        {204, "加藤ゆい",   "主任", 15, 283640, 10000, 0,     6000},
        {255, "小池一平",   "",     12, 264200, 0,     0,     0},
        {272, "矢田佐希子", "",     10, 228760, 0,     0,     6000},
        {304, "堂本猛",     "",     5,  217700, 0,     10000, 12000},
    };
    Syain_dt *p = g;
    int sno, l, r, m;

    printf("探索する社員番号を入力してください。> ");
    scanf("%d", &sno);

    l = 0;
    r = N - 1;
    while (l <= r) {
        m = (l + r) / 2;
        if (sno == (p + m)->no) {
            printf("番号 氏名     役職  勤続 基本給 住宅 家族 資格\n");
            printf("%4d %-12s %-6s %4d %6d %5d %5d %5d\n", (p + m)->no, (p + m)->name, 
                (p + m)->post, (p + m)->years, (p + m)->pay.basic, 
                (p + m)->pay.house, (p + m)->pay.family, (p + m)->pay.qualification);
            break;
        }
        else if (sno > (p + m)->no) {
            l = m + 1;
        }
        else {
            r = m - 1;
        }
    }
    if (l > r) {
            printf("該当する番号はありません。\n");
    }
    return 0;
}

データが昇順、または降順に並んでいる場合には二分探索法という効率のよいアルゴリズムを用いることができます。
二分探索法は、下図のように探索の範囲を次々に二等分しながら狭めていく方法です。

解説図

[Back]

10.4 構造体と関数

a10-4-1.c

P.339の演習1(a10-1-2.c)の点数の合計部分を、次の仕様を参考に関数化してください。

 関数名 total_test
 仮引数 Test_record s:成績情報構造体
 返却値 int型:合計点数
/* a10-4-1.c */
#include <stdio.h>
#define N 5     /* 人数   */
#define K 5     /* 科目数 */

typedef struct {    /* 成績構造体 */
    int no;           /* 学生番号   */
    char name[20];    /* 氏名       */
    int ten[K];       /* 点数(国語・数学・理科・社会・英語)*/
} Test_record;

int total_test(Test_record s);

int main(void)
{
    Test_record student[N] = 
    {{1, "安部寛之", 76, 82, 87, 93, 88},
     {2, "内山理香", 54, 66, 71, 64, 76},
     {3, "小田裕一", 93, 45, 63, 97, 96},
     {4, "後藤美希", 81, 88, 72, 84, 78},
     {5, "柴崎ユウ", 58, 61, 77, 56, 88}};
    int i, total[N];

    for (i = 0; i < N; i++) {
        total[i] = total_test(student[i]);
        printf("%sの合計点は%d\n", student[i].name, total[i]);
    }

    return 0;
}

/*** 合計点数を返却する ***/
/* (引数)s:成績構造体 (返却値)合計点数 */
int total_test(Test_record s)
{
    int i, total = 0;

    for (i = 0; i < K; i++) {
        total += s.ten[i];
    }

    return total;
}

[Back]

a10-4-2.c

P.339の演習1(a10-1-2.c)で使用した構造体から、引数で指定した科目の最高点数を求める関数を、次の仕様を参考にして作成してください。

 関数名 max_test
 仮引数 Test_record *s:成績構造体へのポインタ
     int subject:科目(0:国語、1:数学、2:理科、3:社会、4:英語)
     int n:人数
 返却値 int型:最高点数
/* a10-4-2.c */
#include <stdio.h>
#define N 5
#define K 5

typedef struct {    /* 成績構造体 */
    int no;           /* 学生番号   */
    char name[20];    /* 氏名       */
    int ten[K];       /* 点数(国語・数学・理科・社会・英語)*/
} Test_record;

int max_test(const Test_record *s, int subject, int n);

int main(void)
{
    Test_record student[N] = 
    {{1, "安部寛之", 76, 82, 87, 93, 88},
     {2, "内山理香", 54, 66, 71, 64, 76},
     {3, "小田裕一", 93, 45, 63, 97, 96},
     {4, "後藤美希", 81, 88, 72, 84, 78},
     {5, "柴崎ユウ", 58, 61, 77, 56, 88}};

    printf("数学の最高点数は%d点です。\n", max_test(student, 1, N));

    return 0;
}

/*** 合計点数を返却する ***/
/* (引数)s:成績構造体へのポインタ subject:科目 n:人数
  (返却値)最高点数 */
int max_test(const Test_record *s, int subject, int n)
{
    int i, max;

    max = s->ten[subject];

    for (i = 1; i < n; i++) {
        if (max < (s+i)->ten[subject]) {
            max = (s+i)->ten[subject];
        }
    }

    return max;
}

[Back]

a10-4-3.c

P.353の演習1(a10-3-1.c)のデータの検索部分を、次の仕様を参考に関数化してください。

 関数名 search_syain
 仮引数 Syain_dt *p:探索する構造体へのポインタ
     int sno:探索する社員番号
     int n:構造体の件数
 返却値 Syain_dt型:探索した社員情報(データのない場合には社員番号に0を設定)
/* a10-4-3.c */
#include <stdio.h>
#define N 5

typedef struct {     /* 給与       */
    int basic;         /* 基本給   */
    int house;         /* 住宅手当 */
    int family;        /* 家族手当 */
    int qualification; /* 資格手当 */
} Pay;
typedef struct  {    /* 社員情報 */
    int no;            /* 社員番号 */
    char name[20];     /* 氏名     */
    char post[20];     /* 役職     */
    int years;         /* 勤続年数 */
    Pay pay;           /* 給与     */
} Syain_dt;

Syain_dt search_syain(const Syain_dt *p, int sno, int n);

int main(void)
{
    Syain_dt g[N] = {
        {127, "滝沢康明",   "課長", 21, 366780, 10000, 15000, 12000},
        {204, "加藤ゆい",   "主任", 15, 283640, 10000, 0,     6000},
        {255, "小池一平",   "",     12, 264200, 0,     0,     0},
        {272, "矢田佐希子", "",     10, 228760, 0,     0,     6000},
        {304, "堂本猛",     "",     5,  217700, 0,     10000, 12000},
    };
    Syain_dt search;
    int sno;

    printf("探索する社員番号を入力してください。> ");
    scanf("%d", &sno);

    search = search_syain(g, sno, N);

    if (search.no != 0) {
        printf("番号 氏名     役職  勤続 基本給 住宅 家族 資格\n");
        printf("%4d %-12s %-6s %4d %6d %5d %5d %5d\n", search.no, search.name, 
                search.post, search.years, search.pay.basic, 
                search.pay.house, search.pay.family, search.pay.qualification);
    }
    else {
            printf("該当する番号はありません。\n");
    }

    return 0;
}

/*** 社員情報を探索する ***/
/* (引数)s:探索する構造体へのポインタ sno:探索社員番号 n:構造体の件数
  (返却値)探索した社員情報(データのない場合には社員番号に0を設定) */
Syain_dt search_syain(const Syain_dt *p, int sno, int n)
{
    Syain_dt s;
    int i;

    for (i = 0; i < n; i++) {
        if (sno == p->no) {
            s = *p;
            break;
        }
        p++;
    }
    if (i == n) {
            s.no = 0;
    }

    return s;
}

[Back]

a10-4-4.c

P.346の演習1(a10-2-2.c)のデータの挿入部分を、次の仕様を参考に関数化してください。

 関数名 insert_syain
 引数  Syain_dt *s:挿入元の構造体へのポインタ
     Syain_dt t:挿入する構造体
     int n:挿入元の構造体の件数
 返却値 なし
/* a10-4-4.c */
#include <stdio.h>
#define N 4     /* 人数 */

typedef struct {     /* 給与       */
    int basic;         /* 基本給   */
    int house;         /* 住宅手当 */
    int family;        /* 家族手当 */
    int qualification; /* 資格手当 */
} Pay;
typedef struct  {    /* 社員情報 */
    int no;            /* 社員番号 */
    char name[20];     /* 氏名     */
    char post[20];     /* 役職     */
    int years;         /* 勤続年数 */
    Pay pay;           /* 給与     */
} Syain_dt;

void insert_syain(Syain_dt *s, Syain_dt t, int n);

int main(void)
{
    Syain_dt g[N+1] = {
        {127, "滝沢康明",   "課長", 21, 366780, 10000, 15000, 12000},
        {204, "加藤ゆい",   "主任", 15, 283640, 10000, 0,     6000},
        {272, "矢田佐希子", "",     10, 228760, 0,     0,     6000},
        {304, "堂本猛",     "",     5,  217700, 0,     10000, 12000},
    };
    Syain_dt tuika = {255, "小池一平",   "",     12, 264200, 0,     0,     0};
    int i;

    insert_syain(g, tuika, N);

    printf("番号 氏名     役職  勤続 基本給 住宅 家族 資格\n");
    for (i = 0; i <= N; i++) {
        printf("%4d %-12s %-6s %4d %6d %5d %5d %5d\n", g[i].no, g[i].name, 
                g[i].post, g[i].years, g[i].pay.basic, 
                g[i].pay.house, g[i].pay.family, g[i].pay.qualification);
    }

    return 0;
}

/*** 社員情報を挿入する ***/
/* (引数)s:挿入元の構造体へのポインタ t:挿入する構造体 n:挿入元の構造体の件数
  (返却値)なし */
void insert_syain(Syain_dt *s, Syain_dt t, int n)
{
    int i;

    for (i = n - 1; i >= 0; i--) {
        if ((s+i)->no > t.no) {
            *(s+i+1) = *(s+i);
            if (i == 0) {
                *(s+i) = t;
            }
        }
        else {
            *(s+i+1) = t;
            break;
        }
    }
}

[Back]


Copyright© 2006,2012 Tomoko Sugawara. All Rights Reserved.