2
@ab-boy_ringo

C言語 学生名簿管理プログラムの作成

この記事は最終更新日から1年以上が経過しています。

1. 仕様

次の機能を持つ.
1. 学籍番号と氏名を入力(登録)する.データの重複は考慮しない.
2. 登録済みの学籍番号と氏名を表示する.
3. 学籍番号で昇順ソートする.
4. 学籍番号で降順ソートする.
5. 学籍番号を入力し,完全一致したデータを削除する.
6. 学籍番号と氏名のデータを持つテキストファイルを読み込む.今まで登録していたデータは上書きされる.
7. 登録されているデータをテキストファイルに書き込む.
8. 学籍番号を入力し,完全一致するデータを検索する.

2. ソースコード

nameList.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct student{
    char number[10];    //学籍番号
    char name[50];      //氏名
};

void data_in(struct student *std);                          //入力
void data_out(struct student *std);                         //出力
void data_asc(struct student *std,int ninzu);               //昇順
void data_desc(struct student *std,int ninzu);              //降順
int data_delete(struct student *std,int ninzu,int search);  //削除
int file_read(struct student *std,int ninzu);               //読み込み
void file_write(struct student *std,int ninzu);             //書き込み
int check(struct student *std,int ninzu);                   //検索

int main(void)
{
    struct student std[20];         //生徒人数
    int ninzu=0,i,search;           //n:人数(データ数), i:繰り返し用, search:検索配列値格納用
    int menu,end=0;                 //menu:処理選択用, end:終了用

    while(1)
    {
        printf("メニュー\n");
        printf("1:データ入力\n");
        printf("2:データ出力\n");
        printf("3:小さい順に整列\n");
        printf("4:大きい順に整列\n");
        printf("5:データ削除\n");
        printf("6:ファイルからデータ読み込み\n");
        printf("7:ファイルへのデータ書き込み\n");
        printf("8:データ検索\n");
        printf("9:終了\n");
        printf("実行する処理の番号-->");
        scanf("%d%*c", &menu);  //%*c:改行を読み飛ばす

        switch(menu)
        {
          case 1:           //入力
            if(ninzu>=20){  //既に20名のデータが存在する時
                printf("データ数が上限に達しています\n\n");
                break;
            }
            data_in(&std[ninzu]);
            ninzu++;                //人数を1人分増やす
            printf("データを入力しました\n\n");
            break;
          case 2:                   //表示
            for(i=0;i<ninzu;i++)    //入力した人数分
                data_out(&std[i]);
            if(ninzu==0)            //データが存在しない時
                printf("表示するデータがありません\n");
            printf("\n");
            break;
          case 3:           //昇順ソート
            if(ninzu==0){   //データが存在しない時
                printf("整列させるデータが存在しません\n\n");
                break;
            }
            data_asc(&std[0],ninzu);
            break;
          case 4:           //降順ソート
            if(ninzu==0){   //データが存在しない時
                printf("整列させるデータが存在しません\n\n");
                break;
            }
            data_desc(&std[0],ninzu);
            break;
          case 5:                           //削除
            search=check(&std[0],ninzu);    //検索した値の配列の中身を格納
            if(search>=0){                  //検索したデータと同じデータが見つかった場合
                data_out(&std[search]);
                ninzu=data_delete(&std[0],ninzu,search);
                printf("上記のデータを削除しました\n\n");
            }
            else{
                printf("データが存在しません\n\n");
            }
            break;
          case 6:                           //ファイル読み込み
            ninzu=file_read(&std[0],ninzu); //読み込んだ時のデータ数を格納
            break;
          case 7:           //ファイル書き込み
            if(ninzu==0){   //データが存在しない時
                printf("書き込むデータが存在しません\n\n");
                break;
            }
            file_write(&std[0],ninzu);
            break;
          case 8:                           //検索
            search=check(&std[0],ninzu);    //検索した値の配列の中身を格納
            if(search>=0){                  //検索したデータと同じデータが見つかった場合
                printf("検索結果\n");
                data_out(&std[search]);
                printf("\n");
            }
            else{
                printf("データが存在しません\n\n");
            }
            break;
          case 9:   //終了
            end=1;  //終了条件の値を代入
            break;
          default:  //エラー
            printf("入力番号がありません\n\n");
        }
        if(end==1)  //終了条件の値が入っている時
            break;
    }
    return 0;
}
void data_in(struct student *std)   //入力
{
    printf("学籍番号---->");
    scanf("%s",std->number);                //学籍番号のデータ読み込み
    printf("名前---->");
    scanf("%s",std->name);              //氏名のデータ読み込み
}
void data_out(struct student *std)              //出力
{
    printf("%s\t%s\n", std->number, std->name); //既存のデータ表示
}
void data_asc(struct student *std,int ninzu)                //昇順
{
    int i,j;
    struct student temp;

    //学籍番号を昇順にソート
    for(i=0;i<ninzu;i++){                                   //i番目のカウント
        for(j=i;j<ninzu;j++){                               //j番目のカウント
            if(strcmp((std+i)->number,(std+j)->number)>0){  //i番目の方が大きい時
                temp=*(std+i);                              //i番目のデータを退避
                *(std+i)=*(std+j);                          //j番目のデータを格納
                *(std+j)=temp;                              //i番目のデータを格納
            }
        }
    }

    printf("小さい順に並べかえました\n\n");
}
void data_desc(struct student *std,int ninzu)               //降順
{
    int i,j;
    struct student temp;

    //学籍番号を降順にソート
    for(i=0;i<ninzu;i++){                                   //i番目のカウント
        for(j=i;j<ninzu;j++){                               //j番目のカウント
            if(strcmp((std+i)->number, (std+j)->number)<0){ //i番目の方が小さい時
                temp=*(std+i);                              //i番目のデータを退避
                *(std+i)=*(std+j);                          //j番目のデータを格納
                *(std+j)=temp;                              //i番目のデータを格納
            }
        }
    }

    printf("大きい順に並べかえました\n\n");
}
int data_delete(struct student *std,int ninzu,int search)   //削除
{
    int i;

    for(i=search;i<ninzu;i++){  //検索した位置から人数を最後尾まで
        std[i]=std[i+1];        //削除してできた空き要素を詰める
    }
    ninzu--;                    //削除した分の人数を減ずる

    return ninzu;               //人数をmain関数に返す
}
int file_read(struct student *std,int ninzu)                                    //読み込み
{
    FILE *fin;
    char in_filename[20];
    int i=0;

    printf("入力ファイル名---->");
    gets(in_filename);                                                          //ファイル名の読み込み

    if((fin = fopen(in_filename,"r")) == NULL){                                 //ファイルが開けない時
        printf("ファイルが開けません\n\n");
        return ninzu;                                                           //人数をmain関数に返す
    }
    while(fscanf(fin,"%s\t%s",(std+i)->number,(std+i)->name) != EOF){           //ファイルのデータを読み込む
        i++;                                                                    //ファイルのデータ数をカウント
    }

    if(i==0)
        printf("ファイルにデータが存在しません\n\n");
    else
        printf("ファイルを読み込みました\n\n");

    fclose(fin);                                                                //ファイルを閉じる

    return i;
}
void file_write(struct student *std,int ninzu)                  //書き込み
{
    FILE *fout;
    char out_filename[20];
    int i;

    printf("出力ファイル名---->");
    gets(out_filename);                                         //ファイル名の読み込み

    if((fout = fopen(out_filename, "w")) == NULL){              //書き込み用ファイルを開けなかった時
        printf("ファイルが開けません\n");
        fclose(fout);                                           //ファイルを閉じる
    }

    for(i=0;i<ninzu;i++){                                       //人数分
        fprintf(fout,"%s\t%s\n",(std+i)->number,(std+i)->name); //ファイルへ書き込む
    }

    printf("ファイルへ書き込みました\n\n");

    fclose(fout);                                               //ファイルを閉じる
}

int check(struct student *std,int ninzu)            //検索
{
    char number[10];
    int i;

    if(ninzu>0){                                    //データが存在する時
        printf("学籍番号を入力---->");
        gets(number);
        for(i=0;i<ninzu;i++){                       //人数分のデータを順番に
            if(strcmp(number,(std+i)->number) == 0) //一致する文字列(学籍番号)があった時
                return i;                           //データの位置をmain関数に返す
        }
    }

    return -1;                                      //見つけられなかったときに返す
}

3. 注意事項

学籍番号のソートはchar型配列である.
数値型(int型等)ではなく,学籍番号を数字のみにしても,数値の大小比較にならないことに注意すること.
そのため,以下のような実行結果になっても間違いではない.

昇順ソートした後出力した時の例は下記の通り.なお,途中経過は省略する.
学籍番号が1の次に10となり,2,3,・・・と続く.
1,2,・・・,10のような数値の昇順にはならない.

昇順ソート実行結果例
(省略)

実行する処理の番号-->3
小さい順に並べかえました

メニュー
1:データ入力
2:データ出力
3:小さい順に整列
4:大きい順に整列
5:データ削除
6:ファイルからデータ読み込み
7:ファイルへのデータ書き込み
8:データ検索
9:終了
実行する処理の番号-->2

1       aaa
10      jjj
2       bbb
3       ccc
4       ddd
5       eee
6       fff
7       ggg
8       hhh
9       iii

(省略)

これについては,
01,10,・・・
または
001,010,・・・
のように,上位桁を0詰めして桁合わせしたり,数値型にすることで,期待値通りになる.

2
ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
ab-boy_ringo

コメント

(編集済み)

1つの関数が長いと見通しが悪くなってしまうので、機能単位に関数を分けてはいかがでしょう?
1関数は25行以内(標準端末一画面内)が見通しの効く範囲だと思います。

変数名や関数名がコメント代わりになるように、省略形にしない方がいいと思います。
処理するデータに応じて、関数を分類することもできます。オブジェクト指向的な構成になります。

私なりに手を入れてみました。
何か参考になることがあれば幸いです。

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

typedef const char *String;
typedef void (*Function)();

typedef enum input_status {
    INPUT_EOF = EOF,
    INPUT_OK = 0,
    INPUT_ERROR = 1,
} InputStatus;

InputStatus input_int(int *value) {
    int n = scanf("%d%*c", value); // *c で改行文字を破棄
    if (n == EOF)
        return INPUT_EOF;
    if (n != 1)
        scanf("%*[^\n]%*c");  // 数値以外の入力を破棄
    return n == 1 ? INPUT_OK : INPUT_ERROR;
}

InputStatus input_string(char *value, int size) {
    if (size < 1 + 1 || size > 255 + 1)  // 最低1文字,最大255文字 + '\0'
        return INPUT_ERROR;
    char format[sizeof("%255[^\n]%*c")];
    sprintf(format, "%%%d[^\n]%%*c", size - 1);
    int n = scanf(format, value);
    if (n == EOF)
        return INPUT_EOF;
    return n == 1 ? INPUT_OK : INPUT_ERROR;
}

///////////////////////////////////////////////////////////////////////////////
// Student
///////////////////////////////////////////////////////////////////////////////

#define Student_NAME_SIZE (50)
#define Student_NAME_FORMAT "%49[^\n]%*c"

typedef int StudentNumber;

typedef struct student {
    StudentNumber number;
    char name[Student_NAME_SIZE];
} Student;

InputStatus Student_entry(Student *student) {
    printf("学籍番号---->");
    InputStatus status = input_int(&student->number);
    if (status != INPUT_OK)
        return status;

    printf("名前---->");
    return input_string(student->name, Student_NAME_SIZE);
}

void Student_show(Student *student) {
    printf("%d\t%s\n", student->number, student->name);
}

int Student_read(Student *student, FILE *file) {
    return fscanf(file, "%d\t" Student_NAME_FORMAT, &student->number, student->name);
}

void Student_write(Student *student, FILE *file) {
    fprintf(file, "%d\t%s\n", student->number, student->name);
}

int Student_ascend_number(const void *student1, const void *student2) {
    return ((Student *)student1)->number - ((Student *)student2)->number;
}

int Student_descend_number(const void *student1, const void *student2) {
    return ((Student *)student2)->number - ((Student *)student1)->number;
}

///////////////////////////////////////////////////////////////////////////////
// StudentBook
///////////////////////////////////////////////////////////////////////////////

#define StudentBook_SIZE_MAX (20)

typedef struct student_book {
    int size;
    Student students[StudentBook_SIZE_MAX];
} StudentBook;

void StudentBook_destroy(StudentBook *book) {
    book->size = -1;
}

bool StudentBook_is_available(StudentBook *book) {
    return book->size >= 0;
}

void StudentBook_entry(StudentBook *book) {
    if (book->size >= StudentBook_SIZE_MAX) {
        printf("データ数が上限に達しています\n");
        return;
    }
    if (Student_entry(&book->students[book->size]) == INPUT_OK) {
        book->size++;
        printf("データを入力しました\n");
    }
}

void StudentBook_show(StudentBook *book) {
    if (book->size == 0) {
        printf("表示するデータがありません\n");
        return;
    }
    for (int i = 0; i < book->size; i++)
        Student_show(&book->students[i]);
}

void StudentBook_sort_ascending(StudentBook *book) {
    if (book->size == 0) {
        printf("整列させるデータが存在しません\n");
        return;
    }
    qsort(book->students, book->size, sizeof(Student), Student_ascend_number);
    printf("小さい順に並べかえました\n");
}

void StudentBook_sort_descending(StudentBook *book)
{
    if (book->size == 0) {
        printf("整列させるデータが存在しません\n");
        return;
    }
    qsort(book->students, book->size, sizeof(Student), Student_descend_number);
    printf("大きい順に並べかえました\n");
}

int StudentBook_select_student(StudentBook *book) {
    if (book->size == 0) {
        return -1;
    }
    printf("学籍番号を入力---->");
    StudentNumber number;
    if (input_int(&number) != INPUT_OK)
        return -1;
    for (int index = 0; index < book->size; index++) {
        if (book->students[index].number == number)
            return index;
    }
    return -1;
}

void StudentBook_remove(StudentBook *book)
{
    int index = StudentBook_select_student(book);
    if (index < 0) {
        printf("データが存在しません\n");
        return;
    }
    Student_show(&book->students[index]);
    for (index += 1; index < book->size; index++) {
        book->students[index - 1] = book->students[index];
    }
    book->size--;
    printf("上記のデータを削除しました\n");
}

void StudentBook_search(StudentBook *book) {
    int index = StudentBook_select_student(book);
    if (index < 0) {
        printf("データが存在しません\n");
        return;
    }
    printf("検索結果\n");
    Student_show(&book->students[index]);
}

void StudentBook_load(StudentBook *book)
{
    char filename[80];
    FILE *file;

    printf("入力ファイル名---->");
    if (input_string(filename, sizeof(filename)) != INPUT_OK)
        return;
    if ((file = fopen(filename, "r")) == NULL) {
        printf("ファイルが開けません\n");
        return;
    }
    for (book->size = 0; book->size < StudentBook_SIZE_MAX; book->size++) {
        if (Student_read(&book->students[book->size], file) == EOF)
            break;
    }
    fclose(file);
    if (book->size == 0)
        printf("ファイルにデータが存在しません\n");
    else
        printf("ファイルを読み込みました\n");
}

void StudentBook_save(StudentBook *book)
{
    char filename[80];
    FILE *file;

    if (book->size == 0) {
        printf("書き込むデータが存在しません\n");
        return;
    }
    printf("出力ファイル名---->");
    if (input_string(filename, sizeof(filename)) != INPUT_OK) {
        return;
    }
    if ((file = fopen(filename, "w")) == NULL) {
        printf("ファイルが開けません\n");
        return;
    }
    printf("filename: %s\n", filename);
    printf("size: %d\n", book->size);
    for (int i = 0; i < book->size; i++) {
        Student_write(&book->students[i], file);
    }
    fclose(file);
    printf("ファイルへ書き込みました\n");
}

///////////////////////////////////////////////////////////////////////////////
// Menu
///////////////////////////////////////////////////////////////////////////////

#define Menu_START_NUMBER (1)

typedef struct {
    Function function;
    String explain;
} Menu;

Menu Menu_SELECTIONS[] = {
    {StudentBook_entry          , "データ入力"                },
    {StudentBook_show           , "データ表示"                },
    {StudentBook_sort_ascending , "小さい順に整列"            },
    {StudentBook_sort_descending, "大きい順に整列"            },
    {StudentBook_remove         , "データ削除"                },
    {StudentBook_load           , "ファイルからデータ読み込み"},
    {StudentBook_save           , "ファイルへのデータ書き込み"},
    {StudentBook_search         , "データ検索"                },
    {StudentBook_destroy        , "終了"                      },
};
#define Menu_SIZE (sizeof(Menu_SELECTIONS) / sizeof(Menu_SELECTIONS[0]))

void Menu_operate_none() {
}

void Menu_show() {
    printf("\nメニュー\n");
    for (int i = 0; i < Menu_SIZE; i++) {
        printf("%d: %s\n", Menu_START_NUMBER + i, Menu_SELECTIONS[i].explain);
    }
}

Function Menu_select() {
    printf("実行する処理の番号-->");
    int selection;
    if (input_int(&selection) != INPUT_OK) {
        printf("番号を入力してください\n");
        return Menu_operate_none;
    }

    selection -= Menu_START_NUMBER;
    if (selection < 0 || selection >= Menu_SIZE) {
        printf("メニューにない番号です\n");
        return Menu_operate_none;
    }

    return Menu_SELECTIONS[selection].function;
}

///////////////////////////////////////////////////////////////////////////////
// Application
///////////////////////////////////////////////////////////////////////////////

int main(void) {
    StudentBook book = {.size = 0};

    while (StudentBook_is_available(&book)) {
        Menu_show();
        Function operate = Menu_select();
        operate(&book);
    }
}
0
あなたもコメントしてみませんか :)
ユーザー登録
すでにアカウントを持っている方はログイン
記事投稿イベント開催中
Java開発者のためのAzure入門
~
新人プログラマ応援 - みんなで新人を育てよう!
~