C言語:構造体と列挙型を用いたプログラム例

課題1:書籍販売データの処理

以下のプログラムは、書籍の販売データを管理し、販売数でランキングを表示し、総売上額を計算します。

#include <stdio.h>

#define MAX_BOOKS 10

// 書籍情報を格納する構造体
typedef struct {
    char ISBN[20];       // ISBNコード
    char title[80];      // 書籍タイトル
    char author[80];     // 著者名
    double price;        // 単価
    int quantity;        // 販売数
} Book;

// 関数のプロトタイプ宣言
void display_books(Book books[], int count);
void sort_by_sales(Book books[], int count);
double calculate_total_sales(Book books[], int count);

int main() {
    Book catalog[MAX_BOOKS] = {
        {"978-4-06-523406-9", "海辺のカフカ", "村上春樹", 2100, 125},
        {"978-4-16-390610-4", "1Q84 BOOK1", "村上春樹", 1800, 98},
        {"978-4-16-711325-7", "ノルウェイの森", "村上春樹", 1500, 145},
        {"978-4-06-293425-2", "かがみの孤城", "辻村深月", 1400, 87},
        {"978-4-06-521866-1", "きのう見た夢", "伊坂幸太郎", 1600, 76},
        {"978-4-06-518804-7", "羊をめぐる冒険", "村上春樹", 1700, 65},
        {"978-4-06-522644-9", "国境", "辻村深月", 1300, 54},
        {"978-4-06-522645-6", "ミステリと言う剧薬", "辻村深月", 1500, 43},
        {"978-4-06-522646-3", "夜のピクニック", "乙一", 1400, 38}
    };

    printf("書籍販売ランキング(販売数順):
");
    sort_by_sales(catalog, MAX_BOOKS);
    display_books(catalog, MAX_BOOKS);

    printf("
総売上額: %.2f円
", calculate_total_sales(catalog, MAX_BOOKS));

    return 0;
}

// 書籍リストを表示する関数
void display_books(Book books[], int count) {
    printf("%-20s %-30s %-20s %-10s %-10s
", "ISBN", "タイトル", "著者", "単価", "販売数");
    for (int i = 0; i < count; ++i) {
        printf("%-20s %-30s %-20s %-10.0f %-10d
", 
               books[i].ISBN, books[i].title, books[i].author, books[i].price, books[i].quantity);
    }
}

// 販売数で書籍を降順にソートする関数(バブルソート)
void sort_by_sales(Book books[], int count) {
    Book temp;
    for (int i = 0; i < count - 1; ++i) {
        for (int j = 0; j < count - i - 1; ++j) {
            if (books[j].quantity < books[j + 1].quantity) {
                temp = books[j];
                books[j] = books[j + 1];
                books[j + 1] = temp;
            }
        }
    }
}

// 総売上額を計算する関数
double calculate_total_sales(Book books[], int count) {
    double total = 0.0;
    for (int i = 0; i < count; ++i) {
        total += books[i].price * books[i].quantity;
    }
    return total;
}

課題2:日付の操作と比較

以下のプログラムは、日付を入力し、その日が年の何日目かを計算し、また2つの日付を比較します。

#include <stdio.h>

// 日付情報を格納する構造体
typedef struct {
    int year;   // 年
    int month;  // 月
    int day;    // 日
} Date;

// 関数のプロトタイプ宣言
void input_date(Date *date_ptr);                 // 日付を入力する
int get_day_of_year(Date date);                  // 年間通算日を返す
int compare_two_dates(Date date1, Date date2);    // 2つの日付を比較する

int main() {
    Date test_date;
    int result;

    printf("テスト1: 日付を入力し、年間通算日を表示します。
");
    for (int i = 0; i < 3; ++i) {
        input_date(&test_date);
        printf("%d年%d月%d日は、その年の第%d日目です。

", 
               test_date.year, test_date.month, test_date.day, get_day_of_year(test_date));
    }

    printf("
テスト2: 2人の誕生日を比較します。
");
    Date person1_birth, person2_birth;
    for (int i = 0; i < 3; ++i) {
        printf("1人目の誕生日を入力してください(例: 1990-05-15):
");
        input_date(&person1_birth);
        printf("2人目の誕生日を入力してください(例: 1990-05-15):
");
        input_date(&person2_birth);

        result = compare_two_dates(person1_birth, person2_birth);
        if (result == 0) {
            printf("2人は同じ日に生まれました。

");
        } else if (result < 0) {
            printf("1人目の方が年上です。

");
        } else {
            printf("1人目の方が年下です。

");
        }
    }

    return 0;
}

// ユーザーから日付を入力する関数
void input_date(Date *date_ptr) {
    printf("日付を入力してください(例: 2023-12-25): ");
    scanf("%d-%d-%d", &date_ptr->year, &date_ptr->month, &date_ptr->day);
}

// うるう年かどうかを判定するヘルパー関数
int is_leap_year(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

// 年間通算日を計算する関数
int get_day_of_year(Date date) {
    int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int total_days = date.day;

    if (is_leap_year(date.year)) {
        days_in_month[1] = 29; // 2月の日数を29日に変更
    }

    for (int i = 0; i < date.month - 1; ++i) {
        total_days += days_in_month[i];
    }
    return total_days;
}

// 2つの日付を比較する関数(別のロジック:通算日数に変換して比較)
int compare_two_dates(Date date1, Date date2) {
    // 2つの日付を基準日からの通算日数に変換
    int total_days1 = date1.year * 365 + date1.day;
    int total_days2 = date2.year * 365 + date2.day;

    // うるう年を考慮
    for (int y = 1; y < date1.year; ++y) {
        if (is_leap_year(y)) total_days1++;
    }
    for (int y = 1; y < date2.year; ++y) {
        if (is_leap_year(y)) total_days2++;
    }

    // 月の通算日を加算
    int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (is_leap_year(date1.year)) days_in_month[1] = 29;
    for (int m = 0; m < date1.month - 1; ++m) total_days1 += days_in_month[m];

    if (is_leap_year(date2.year)) days_in_month[1] = 29;
    for (int m = 0; m < date2.month - 1; ++m) total_days2 += days_in_month[m];

    if (total_days1 < total_days2) return -1;
    if (total_days1 > total_days2) return 1;
    return 0;
}

課題3:ユーザーアカウントの管理

以下のプログラムは、ユーザーアカウントの情報を管理し、パスワードをマスクして表示します。

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

// ユーザー種別を定義する列挙型
enum UserType { admin, student, teacher };

// アカウント情報を格納する構造体
typedef struct {
    char username[20];  // ユーザー名
    char password[20];  // パスワード
    enum UserType type; // アカウント種別
} Account;

// 関数のプロトタイプ宣言
void display_accounts(Account accounts[], int count); // アカウント情報を表示する

int main() {
    Account user_db[] = {
        {"user001", "pass123", student},
        {"user002", "secure456", student},
        {"user003", "qwerty789", student},
        {"admin01", "admin2023", admin},
        {"teacherA", "edu@2023", teacher},
        {"user004", "letmein", student}
    };
    int num_accounts = sizeof(user_db) / sizeof(Account);

    display_accounts(user_db, num_accounts);

    return 0;
}

// アカウント情報を表示する関数(パスワードはマスクされる)
void display_accounts(Account accounts[], int count) {
    printf("%-12s %-15s %-10s
", "ユーザー名", "パスワード", "種別");
    for (int i = 0; i < count; ++i) {
        printf("%-12s ", accounts[i].username);
        
        // パスワードをアスタリスクでマスク
        int pwd_len = strlen(accounts[i].password);
        for (int j = 0; j < pwd_len; ++j) {
            printf("*");
        }
        
        // 種別を表示
        switch (accounts[i].type) {
            case admin:
                printf(" admin");
                break;
            case student:
                printf(" student");
                break;
            case teacher:
                printf(" teacher");
                break;
            default:
                printf(" 不明");
                break;
        }
        printf("
");
    }
}

課題4:連絡先リストの管理

以下のプログラムは、連絡先リストを管理し、特定の連絡先を緊急連絡先としてマークし、氏名のアルファベット順(緊急連絡先を優先)で表示します。

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

// 連絡先情報を格納する構造体
typedef struct {
    char name[20];   // 氏名
    char phone[12];  // 電話番号
    int is_vip;      // 緊急連絡先フラグ(1: はい, 0: いいえ)
} Contact;

// 関数のプロトタイプ宣言
void mark_as_vip(Contact contacts[], int count, char name[]); // 緊急連絡先を設定
void display_contacts(Contact contacts[], int count);         // 連絡先を表示
void display_sorted(Contact contacts[], int count);          // ソートして表示

#define MAX_CONTACTS 10
int main() {
    Contact address_book[MAX_CONTACTS] = {
        {"田中太郎", "090-1234-5678", 0},
        {"佐藤花子", "080-8765-4321", 0},
        {"鈴木一郎", "03-5555-1111", 0},
        {"高橋美咲", "070-9999-8888", 0},
        {"伊藤健太", "090-2222-3333", 0},
        {"中村悠", "050-4444-5555", 0},
        {"山本さくら", "060-6666-7777", 0},
        {"渡辺翔", "090-7777-8888", 0},
        {"小林陽菜", "080-9999-0000", 0},
        {"加藤健", "03-1111-2222", 0}
    };
    int vip_count;
    char vip_name[20];

    printf("元の連絡先リスト:
");
    display_contacts(address_book, MAX_CONTACTS);

    printf("
設定する緊急連絡先の人数を入力してください: ");
    scanf("%d", &vip_count);

    printf("%d人の緊急連絡先の氏名を入力してください:
", vip_count);
    for (int i = 0; i < vip_count; ++i) {
        scanf("%s", vip_name);
        mark_as_vip(address_book, MAX_CONTACTS, vip_name);
    }

    printf("
連絡先リスト(氏名順、緊急連絡先を優先):
");
    display_sorted(address_book, MAX_CONTACTS);

    return 0;
}

// 指定された氏名の連絡先を緊急連絡先に設定する関数
void mark_as_vip(Contact contacts[], int count, char name[]) {
    for (int i = 0; i < count; ++i) {
        if (strcmp(contacts[i].name, name) == 0) {
            contacts[i].is_vip = 1;
            break; // 一致したらループを抜ける
        }
    }
}

// 連絡先を表示する関数
void display_contacts(Contact contacts[], int count) {
    for (int i = 0; i < count; ++i) {
        printf("%-10s %-15s", contacts[i].name, contacts[i].phone);
        if (contacts[i].is_vip) {
            printf(" *");
        }
        printf("
");
    }
}

// 連絡先をソートして表示する関数(選択ソートを使用)
void display_sorted(Contact contacts[], int count) {
    Contact sorted_list[MAX_CONTACTS];
    // 元の配列をコピー
    for (int i = 0; i < count; ++i) {
        sorted_list[i] = contacts[i];
    }

    // 選択ソートでソート
    for (int i = 0; i < count - 1; ++i) {
        int max_idx = i;
        for (int j = i + 1; j < count; ++j) {
            // 緊急連絡先を優先
            if (sorted_list[j].is_vip > sorted_list[max_idx].is_vip) {
                max_idx = j;
            }
            // 緊急フラグが同じ場合は氏名で比較
            else if (sorted_list[j].is_vip == sorted_list[max_idx].is_vip) {
                if (strcmp(sorted_list[j].name, sorted_list[max_idx].name) < 0) {
                    max_idx = j;
                }
            }
        }
        // 最大要素を先頭に持ってくる
        if (max_idx != i) {
            Contact temp = sorted_list[i];
            sorted_list[i] = sorted_list[max_idx];
            sorted_list[max_idx] = temp;
        }
    }
    display_contacts(sorted_list, count);
}

タグ: C言語 構造体 列挙型 ソート 日付処理

8月13日 12:49 投稿