回答編集履歴

3

Sophian

Sophian score 34

2018/06/12 22:39  投稿

記述してみました。  
 
コード説明
---
質問の変更したい内容のとおり、完全に別れた機能として「新規作成」と「追加」、また、番号によるソート機能のコードを記述しました。
新規作成で一時的な構造体へ保存して、追加でメインの構造体へ移動させる、という方式をとり、その都度リストを表示させ中身を確認、一括削除できるようにしました。
点数でのソートに関しては番号でのソートと同じ要領で記述すれば実装できます。また、ソート自体に関しても他にもたくさんアルゴリズムがあるようなので、自分のプログラムにあったものを探してみるといいかとおもいます。
そして、一番大事なことですが、私は**Visual Studioではコンパイルできませんでした。**
当方、Eclipseですべて記述しました。
つづいて、sscanfを使用しているのでこれを使用できるようにソースコードに一行記述を加えます(ググればすぐでてきます)。
そして最後に残るエラーですが、マージソートを扱う際に可変長配列を定義している部分になりますが、Visualstudioでは拡張子をcにしてC言語としてコンパイルしても、このような記述はできないようです。ですので工夫が必要かと思われます。
以下にソースコードと、実行結果のスクショを載せました。すこしでも参考になれば幸いです。
実行結果
---
[実行結果1](https://gyazo.com/b4e2bcab8db11190007e4561a41a3899)
[実行結果2](https://gyazo.com/102c66b14139925051b6a85cd2037e1c)
[実行結果3](https://gyazo.com/b79309c7718d53c24f8a165783b29f6d)
[実行結果4](https://gyazo.com/a584ce07130b39ddbbe283764f975613)
ソースコード
---
```C
#include <stdio.h>
#include <string.h>
#define MAX 100   /*保存可能な最大人数,名前入力の最長文字数*/
/*学生リストの型を定義*/
struct student{
   int id;       /*番号*/
   char name[MAX];   /*名前*/
   int score;   /*得点*/
};
/*構造体内の配列を関数に渡すために型を宣言*/
typedef struct student type_list;
/*変数*/
type_list list_all[MAX];   /*追加された全学生の構造体配列*/
type_list list_temp[MAX];   /*まだ追加されていない新規の学生の構造体配列*/
int menu=4;   /*メニュー指示番号(1~4)*/
char line[MAX];   /*キーボードによる入力, 1行分*/
int i;   /*カウンター*/
int number_temp=0;   /*新規追加されたtemp内の件数*/
int number_all=0;   /*追加済みの学生数の数*/
/*関数宣言文*/
void newStudent();   /*新規作成用*/
void viewTemp();   /*作成済み構造体リスト中身確認用*/
void viewAll();       /*追加済み構造体リスト中身確認用*/
void deleteTemp();   /*作成済み構造体リスト初期化*/
void add();           /*新規作成分を追加(list_allに保存)*/
void sort();       /*マージソート呼び出し*/
void merge();       /*マージソート, 結合部分*/
void mergeSort();   /*マージソート, 分割部分*/
/*メイン関数*/
int main(void){
   /*終了が指示されるまで何度もメニューを回すためにループ*/
   while(1){
       puts(">>メニューを入力して下さい (半角数字1~4)");
       puts("1.新規作成 2.追加 3.ソート 4.終了 ");
       fflush(0);   /*バッファの吐き出し (Eclipse等のIDEによってはこれをやらないと出力が表示されない場合がある)*/
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
       switch(menu){
       case 1:
           newStudent();   /*新規作成*/
           break;
       case 2:
           add();           /*追加*/
           break;
       case 3:
           sort();           /*ソート*/
           break;
       case 4:
           puts(">>終了します。 Bye-Bye");
           return 0;   /*リターンによってプログラムを終了*/
       default:
           puts(">>半角数字 1~4 を一文字のみ入力してください。");   /*想定外の入力に対して警告し,メニューの最初から*/
           break;
       }
   }
   return 0;
}
void newStudent(){
   /*学生情報の入力をループ*/
   while(1){
       puts(">>学生の情報を入力してください。");
       printf("番号:");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&list_temp[number_temp].id);   /*数値として 新規学生構造体配列へ順番に格納*/
       printf("氏名:");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%s",&list_temp[number_temp].name);   /*数値として 新規学生構造体配列へ順番に格納*/
       printf("点数:");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&list_temp[number_temp].score);   /*数値として 新規学生構造体配列へ順番に格納*/
       ++number_temp;   /*作成件数を +1*/
       //printf("%d %s %d",list_temp[number].id,list_temp[number].name,list_temp[number].score);
       puts(">>新規作成されました。指示を入力してください。");
       puts("1.続けて新規作成 2.作成された一覧を表示 3.メニューへ戻る");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
       switch(menu){
       case 1:
           break;   /*ループを続行*/
       case 2:
           viewTemp();   /*作成された一覧を表示*/
           return;
       case 3:
           return;
       }
   }
   return;
}
void viewTemp(){
   puts("--------------------");
   for(i=0;i<number_temp;i++){
       printf(">> 番号: %d, 指名: %s, 点数: %d \n",list_temp[i].id,list_temp[i].name,list_temp[i].score);
   }
   puts("--------------------");
   printf(">>新規で %d 件,作成されました。まだ追加はされておりません。\n",number_temp);
   puts(">>指示を入力してください。さらに追加する場合は一度メニューにもどり、新規作成を選択してください。");
   puts("1.メニューに戻る 2.これら新規データを消去");
   fflush(0);
   fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
   sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
   /*削除が指示された場合*/
   if(menu==2){
       deleteTemp();
       puts("追加せず、削除しました。");
   }
   return;
}
void viewAll(){
   puts("--------------------");
   for(i=0;i<number_all;i++){
       printf("番号: %d, 指名: %s, 点数: %d \n",list_all[i].id,list_all[i].name,list_all[i].score);
   }
   puts("--------------------");
   printf(">>現在合計で %d 件です。\n",number_all);
   return;
}
void deleteTemp(){
   for(i=0;i<number_temp;i++){
       list_temp[i].id=0;
       list_temp[i].name[0]='\0';
       list_temp[i].score=0;
   }
   number_temp=0;
   return;
}
void add(){
   /*構造体配列内の対応する各要素ごとに代入*/
   for(i=0;i<number_temp;i++){
       list_all[number_all + i].id=list_temp[i].id;
       strcpy(list_all[number_all + i].name,list_temp[i].name);   /*文字列なのでstrcpyを使用*/
       list_all[number_all + i].score=list_temp[i].score;
   }
   printf("既存の %d 件に,新規の %d 件が加わり、合計 %d 件になりました。\n",number_all, number_temp,number_all+number_temp);
   number_all+=number_temp;   /*追加済み件数を更新*/
   deleteTemp();   /*新規作成リストtemp内をクリアし、作成件数もリセット*/
   viewAll();   /*追加済みリスト確認*/
   return;
}
/*--------------------------ソート関係の関数---------------------------
*
*   採用アルゴリズム: マージソート
*
*   変数: 追加済み生徒の構造体リスト, 及びその件数
*
*   関数:sort()           ソートのメイン関数,帰納の復帰先
*        merge()       二つの分割から一つの構造体へ小さい順に並べ替える
*        mergeSort()   帰納させる関数,構造体を二つの構造体へ分割
*
*   動作: 構造体内の比較対象となる配列で比較し、番号、名前、点数すべてを毎回移動させる
*
--------------------------------------------------------------------*/
/*帰納の復帰先*/
void sort(){
   puts(">>追加済み件数を何でソートしますか?(作成されたが未追加のものはソートの対象ではありません。)");   /*構造体list_tempはソートの対象外*/
   puts("1.番号 2.得点 3.メニューへ戻る");
   fflush(0);
   fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
   sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
   if(menu==1){   /*番号でソート*/
       mergeSort(list_all,number_all);
       viewAll();
       puts(">>学生番号によるソートが完了しました");
       puts("");
   }else if(menu==2){   /*得点でソート*/
       puts("未実装, メニューへもどります。");
   }else{
       /*それ以外の入力に対してはメニューへ戻る*/
   }
   return;
}
void merge(type_list *ALL, type_list *L, int L_count, type_list *R, int R_count){
   int i,j,k;   /*カウンター*/
   i=0;
   j=0;
   k=0;
   /*分割右側と分割左側を比較しながらALLへ統合させる*/
   /*どちらか片方の分割が全て統合されたら、あとは評価せず、他方はそのままALLの最後へ*/
   while(i<L_count && j< R_count){
       /*分割右側と分割左側のそれぞれの最小値を比較*/
       /*小さい方を選択し,ALLへ移動,同時に名前,点数も移動*/
       if(L[i].id<R[j].id){
           ALL[k].id=L[i].id;
           strcpy(ALL[k].name,L[i].name);
           ALL[k].score=L[i].score;
           k++;
           i++;
       }else{
           ALL[k].id=R[j].id;
           strcpy(ALL[k].name,R[j].name);
           ALL[k].score=R[j].score;
           k++;
           j++;
       }
   }
   /*評価せずに終わった方をそのままALLへ結合させるコード*/
   while(i<L_count){   /*右側配列が先に全てALLへ統合された場合*/
       ALL[k].id=L[i].id;
       strcpy(ALL[k].name,L[i].name);
       ALL[k].score=L[i].score;
       k++;
       i++;
   }
   while(j<R_count){   /*左側配列が先に全てALLへ統合された場合*/
       ALL[k].id=R[j].id;
       strcpy(ALL[k].name,R[j].name);
       ALL[k].score=R[j].score;
       k++;
       j++;
   }
/*   デバッグ用 (R と L の中身を確認する)
   for(i=0;i<L_count;i++){
       printf("L[%d] - %d %s %d\n",i,L[i].id,L[i].name,L[i].score);
   }
   for(i=0;i<R_count;i++){
       printf("R[%d] - %d %s %d\n",i,R[i].id,R[i].name,R[i].score);
   }*/
}
void mergeSort(type_list *ALL, int n){
   int mid;   /*構造体配列の真ん中を定義*/
   mid = n/2;
   if(n<2) return;   /*帰納の復帰*/
   type_list L[mid];   /*分割左側を格納する構造体を定義*/
   type_list R[n-mid];   /*分割右側を格納する構造体を定義*/
   /*与えられた構造体(最初の一回目の呼び出しでは追加済み学生リスト)の2つに分割する*/
   /*左側を構造体 L へ, 右側を構造体 R へ*/
   for(i=0;i<mid;i++) {
       L[i].id=ALL[i].id;
       strcpy(L[i].name,ALL[i].name);
       L[i].score=ALL[i].score;
   }
   for(i=mid;i<n;i++){
       R[i-mid].id=ALL[i].id;
       strcpy(R[i-mid].name,ALL[i].name);
       R[i-mid].score=ALL[i].score;
   }
/*   デバッグ用 (R と L の中身を確認する)
   for(i=0;i<mid;i++){
       printf("L[%d] - %d %s %d\n",i,L[i].id,L[i].name,L[i].score);
   }
   for(i=0;i<mid;i++){
       printf("R[%d] - %d %s %d\n",i,R[i].id,R[i].name,R[i].score);
   }*/
   /*----------帰納処理----------*/
   /*分割する関数の中でその関数自体を呼び出し、分割し続ける*/
   /*比較対象が (n<2) になり、returnするまで分割し続ける。*/
   mergeSort(L,mid);   /*分割された左側をさらに分割*/
   mergeSort(R,n-mid);   /*分割された右側をさらに分割*/
   merge(ALL,L,mid,R,n-mid);   /*returnして戻ってきたものをソートして結合*/
}
```
2

Sophian

Sophian score 34

2018/06/12 22:37  投稿

こんばんは。  
こういった場での初解答失礼します。  
C言語を習い始めたばかりなので、自身の学習のため、たまたま見つけたこの質問のソースコードを記述してみました。  
 
しかし、私にはまだコードの解読は大変なので、記載のコードはあまり見ていないです…。ので全く別のプログラムになるかと思います。  
また、コメントで可能な限り説明を盛り込みましたが、それでもかなり分かりづらいかとおもいます。  
 
構造体というのを使うのも初めてで、線形?リストというのもなんだかわかっていません。一般によく書かれる省略した書き方?もよくわかっていないので、表現がくどくなっているコードもあるかと思います。  
またソートにはマージアルゴリズムというのを参考に記述したのですが、これも初で調べながら試行錯誤したため、デバッグのコードが残っていたり、コメントが独り言のようになっていたりします…。  
なので、申し訳ありませんが、コードが非常にみづらいかと思います…。  
 
初めて遭遇する知識が多く、大変勉強させていただきました。  
 
コード説明
---
質問の変更したい内容のとおり、完全に別れた機能として「新規作成」と「追加」、また、番号によるソート機能のコードを記述しました。
新規作成で一時的な構造体へ保存して、追加でメインの構造体へ移動させる、という方式をとり、その都度リストを表示させ中身を確認、一括削除できるようにしました。
点数でのソートに関しては番号でのソートと同じ要領で記述すれば実装できます。また、ソート自体に関しても他にもたくさんアルゴリズムがあるようなので、自分のプログラムにあったものを探してみるといいかとおもいます。
そして、一番大事なことですが、私は**Visual Studioではコンパイルできませんでした。**
当方、Eclipseですべて記述しました。
まず、そのまま以下のコードをコピペするとエラーを大量に吐きます。
調べた結果、コンパイル済みヘッダーを読み込まないようにします。
つづいて、sscanfを使用しているのでこれを使用できるようにソースコードに一行記述を加えます(ググればすぐでてきます)。
そして最後に残るエラーですが、マージソートを扱う際に可変長配列を定義している部分になりますが、Visualstudioでは拡張子をcにしてC言語としてコンパイルしても、このような記述はできないようです。ですので工夫が必要かと思われます。
以下にソースコードと、実行結果のスクショを載せました。すこしでも参考になれば幸いです。
実行結果
---
[実行結果1](https://gyazo.com/b4e2bcab8db11190007e4561a41a3899)
[実行結果2](https://gyazo.com/102c66b14139925051b6a85cd2037e1c)
[実行結果3](https://gyazo.com/b79309c7718d53c24f8a165783b29f6d)
[実行結果4](https://gyazo.com/a584ce07130b39ddbbe283764f975613)
ソースコード
---
```C
#include <stdio.h>
#include <string.h>
#define MAX 100   /*保存可能な最大人数,名前入力の最長文字数*/
/*学生リストの型を定義*/
struct student{
   int id;       /*番号*/
   char name[MAX];   /*名前*/
   int score;   /*得点*/
};
/*構造体内の配列を関数に渡すために型を宣言*/
typedef struct student type_list;
/*変数*/
type_list list_all[MAX];   /*追加された全学生の構造体配列*/
type_list list_temp[MAX];   /*まだ追加されていない新規の学生の構造体配列*/
int menu=4;   /*メニュー指示番号(1~4)*/
char line[MAX];   /*キーボードによる入力, 1行分*/
int i;   /*カウンター*/
int number_temp=0;   /*新規追加されたtemp内の件数*/
int number_all=0;   /*追加済みの学生数の数*/
/*関数宣言文*/
void newStudent();   /*新規作成用*/
void viewTemp();   /*作成済み構造体リスト中身確認用*/
void viewAll();       /*追加済み構造体リスト中身確認用*/
void deleteTemp();   /*作成済み構造体リスト初期化*/
void add();           /*新規作成分を追加(list_allに保存)*/
void sort();       /*マージソート呼び出し*/
void merge();       /*マージソート, 結合部分*/
void mergeSort();   /*マージソート, 分割部分*/
/*メイン関数*/
int main(void){
   /*終了が指示されるまで何度もメニューを回すためにループ*/
   while(1){
       puts(">>メニューを入力して下さい (半角数字1~4)");
       puts("1.新規作成 2.追加 3.ソート 4.終了 ");
       fflush(0);   /*バッファの吐き出し (Eclipse等のIDEによってはこれをやらないと出力が表示されない場合がある)*/
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
       switch(menu){
       case 1:
           newStudent();   /*新規作成*/
           break;
       case 2:
           add();           /*追加*/
           break;
       case 3:
           sort();           /*ソート*/
           break;
       case 4:
           puts(">>終了します。 Bye-Bye");
           return 0;   /*リターンによってプログラムを終了*/
       default:
           puts(">>半角数字 1~4 を一文字のみ入力してください。");   /*想定外の入力に対して警告し,メニューの最初から*/
           break;
       }
   }
   return 0;
}
void newStudent(){
   /*学生情報の入力をループ*/
   while(1){
       puts(">>学生の情報を入力してください。");
       printf("番号:");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&list_temp[number_temp].id);   /*数値として 新規学生構造体配列へ順番に格納*/
       printf("氏名:");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%s",&list_temp[number_temp].name);   /*数値として 新規学生構造体配列へ順番に格納*/
       printf("点数:");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&list_temp[number_temp].score);   /*数値として 新規学生構造体配列へ順番に格納*/
       ++number_temp;   /*作成件数を +1*/
       //printf("%d %s %d",list_temp[number].id,list_temp[number].name,list_temp[number].score);
       puts(">>新規作成されました。指示を入力してください。");
       puts("1.続けて新規作成 2.作成された一覧を表示 3.メニューへ戻る");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
       switch(menu){
       case 1:
           break;   /*ループを続行*/
       case 2:
           viewTemp();   /*作成された一覧を表示*/
           return;
       case 3:
           return;
       }
   }
   return;
}
void viewTemp(){
   puts("--------------------");
   for(i=0;i<number_temp;i++){
       printf(">> 番号: %d, 指名: %s, 点数: %d \n",list_temp[i].id,list_temp[i].name,list_temp[i].score);
   }
   puts("--------------------");
   printf(">>新規で %d 件,作成されました。まだ追加はされておりません。\n",number_temp);
   puts(">>指示を入力してください。さらに追加する場合は一度メニューにもどり、新規作成を選択してください。");
   puts("1.メニューに戻る 2.これら新規データを消去");
   fflush(0);
   fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
   sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
   /*削除が指示された場合*/
   if(menu==2){
       deleteTemp();
       puts("追加せず、削除しました。");
   }
   return;
}
void viewAll(){
   puts("--------------------");
   for(i=0;i<number_all;i++){
       printf("番号: %d, 指名: %s, 点数: %d \n",list_all[i].id,list_all[i].name,list_all[i].score);
   }
   puts("--------------------");
   printf(">>現在合計で %d 件です。\n",number_all);
   return;
}
void deleteTemp(){
   for(i=0;i<number_temp;i++){
       list_temp[i].id=0;
       list_temp[i].name[0]='\0';
       list_temp[i].score=0;
   }
   number_temp=0;
   return;
}
void add(){
   /*構造体配列内の対応する各要素ごとに代入*/
   for(i=0;i<number_temp;i++){
       list_all[number_all + i].id=list_temp[i].id;
       strcpy(list_all[number_all + i].name,list_temp[i].name);   /*文字列なのでstrcpyを使用*/
       list_all[number_all + i].score=list_temp[i].score;
   }
   printf("既存の %d 件に,新規の %d 件が加わり、合計 %d 件になりました。\n",number_all, number_temp,number_all+number_temp);
   number_all+=number_temp;   /*追加済み件数を更新*/
   deleteTemp();   /*新規作成リストtemp内をクリアし、作成件数もリセット*/
   viewAll();   /*追加済みリスト確認*/
   return;
}
/*--------------------------ソート関係の関数---------------------------
*
*   採用アルゴリズム: マージソート
*
*   変数: 追加済み生徒の構造体リスト, 及びその件数
*
*   関数:sort()           ソートのメイン関数,帰納の復帰先
*        merge()       二つの分割から一つの構造体へ小さい順に並べ替える
*        mergeSort()   帰納させる関数,構造体を二つの構造体へ分割
*
*   動作: 構造体内の比較対象となる配列で比較し、番号、名前、点数すべてを毎回移動させる
*
--------------------------------------------------------------------*/
/*帰納の復帰先*/
void sort(){
   puts(">>追加済み件数を何でソートしますか?(作成されたが未追加のものはソートの対象ではありません。)");   /*構造体list_tempはソートの対象外*/
   puts("1.番号 2.得点 3.メニューへ戻る");
   fflush(0);
   fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
   sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
   if(menu==1){   /*番号でソート*/
       mergeSort(list_all,number_all);
       viewAll();
       puts(">>学生番号によるソートが完了しました");
       puts("");
   }else if(menu==2){   /*得点でソート*/
       puts("未実装, メニューへもどります。");
   }else{
       /*それ以外の入力に対してはメニューへ戻る*/
   }
   return;
}
void merge(type_list *ALL, type_list *L, int L_count, type_list *R, int R_count){
   int i,j,k;   /*カウンター*/
   i=0;
   j=0;
   k=0;
   /*分割右側と分割左側を比較しながらALLへ統合させる*/
   /*どちらか片方の分割が全て統合されたら、あとは評価せず、他方はそのままALLの最後へ*/
   while(i<L_count && j< R_count){
       /*分割右側と分割左側のそれぞれの最小値を比較*/
       /*小さい方を選択し,ALLへ移動,同時に名前,点数も移動*/
       if(L[i].id<R[j].id){
           ALL[k].id=L[i].id;
           strcpy(ALL[k].name,L[i].name);
           ALL[k].score=L[i].score;
           k++;
           i++;
       }else{
           ALL[k].id=R[j].id;
           strcpy(ALL[k].name,R[j].name);
           ALL[k].score=R[j].score;
           k++;
           j++;
       }
   }
   /*評価せずに終わった方をそのままALLへ結合させるコード*/
   while(i<L_count){   /*右側配列が先に全てALLへ統合された場合*/
       ALL[k].id=L[i].id;
       strcpy(ALL[k].name,L[i].name);
       ALL[k].score=L[i].score;
       k++;
       i++;
   }
   while(j<R_count){   /*左側配列が先に全てALLへ統合された場合*/
       ALL[k].id=R[j].id;
       strcpy(ALL[k].name,R[j].name);
       ALL[k].score=R[j].score;
       k++;
       j++;
   }
/*   デバッグ用 (R と L の中身を確認する)
   for(i=0;i<L_count;i++){
       printf("L[%d] - %d %s %d\n",i,L[i].id,L[i].name,L[i].score);
   }
   for(i=0;i<R_count;i++){
       printf("R[%d] - %d %s %d\n",i,R[i].id,R[i].name,R[i].score);
   }*/
}
void mergeSort(type_list *ALL, int n){
   int mid;   /*構造体配列の真ん中を定義*/
   mid = n/2;
   if(n<2) return;   /*帰納の復帰*/
   type_list L[mid];   /*分割左側を格納する構造体を定義*/
   type_list R[n-mid];   /*分割右側を格納する構造体を定義*/
   /*与えられた構造体(最初の一回目の呼び出しでは追加済み学生リスト)の2つに分割する*/
   /*左側を構造体 L へ, 右側を構造体 R へ*/
   for(i=0;i<mid;i++) {
       L[i].id=ALL[i].id;
       strcpy(L[i].name,ALL[i].name);
       L[i].score=ALL[i].score;
   }
   for(i=mid;i<n;i++){
       R[i-mid].id=ALL[i].id;
       strcpy(R[i-mid].name,ALL[i].name);
       R[i-mid].score=ALL[i].score;
   }
/*   デバッグ用 (R と L の中身を確認する)
   for(i=0;i<mid;i++){
       printf("L[%d] - %d %s %d\n",i,L[i].id,L[i].name,L[i].score);
   }
   for(i=0;i<mid;i++){
       printf("R[%d] - %d %s %d\n",i,R[i].id,R[i].name,R[i].score);
   }*/
   /*----------帰納処理----------*/
   /*分割する関数の中でその関数自体を呼び出し、分割し続ける*/
   /*比較対象が (n<2) になり、returnするまで分割し続ける。*/
   mergeSort(L,mid);   /*分割された左側をさらに分割*/
   mergeSort(R,n-mid);   /*分割された右側をさらに分割*/
   merge(ALL,L,mid,R,n-mid);   /*returnして戻ってきたものをソートして結合*/
}
```
1 修正

Sophian

Sophian score 34

2016/03/30 00:45  投稿

こんばんは。
こういった場での初解答失礼します。
C言語を習い始めたばかりなので、自身の学習のため、たまたま見つけたこの質問のソースコードを記述してみました。
しかし、私にはまだコードの解読は大変なので、記載のコードはあまり見ていないです…。ので全く別のプログラムになるかと思います。
また、コメントで可能な限り説明を盛り込みましたが、それでもかなり分かりづらいかとおもいます。
構造体というのを使うのも初めてで、線形?リストというのもなんだかわかっていません。一般によく書かれる省略した書き方?もよくわかっていないので、表現がくどくなっているコードもあるかと思います。
またソートにはマージアルゴリズムというのを参考に記述したのですが、これも初で調べながら試行錯誤したため、デバッグのコードが残っていたり、コメントが独り言のようになっていたりします…。
なので、申し訳ありませんが、コードが非常にみづらいかと思います…。  
 
初めて遭遇する知識が多く、大変勉強させていただきました。
コード説明
---
質問の変更したい内容のとおり、完全に別れた機能として「新規作成」と「追加」、また、番号によるソート機能のコードを記述しました。
新規作成で一時的な構造体へ保存して、追加でメインの構造体へ移動させる、という方式をとり、その都度リストを表示させ中身を確認、一括削除できるようにしました。
点数でのソートに関しては番号でのソートと同じ要領で記述すれば実装できます。また、ソート自体に関しても他にもたくさんアルゴリズムがあるようなので、自分のプログラムにあったものを探してみるといいかとおもいます。
そして、一番大事なことですが、私は**Visual Studioではコンパイルできませんでした。**
当方、Eclipseですべて記述しました。  
まず、そのまま以下のコードをコピペするとエラーを大量に吐きます。
調べた結果、コンパイル済みヘッダーを読み込まないようにします。
つづいて、sscanfを使用しているのでこれを使用できるようにソースコードに一行記述を加えます(ググればすぐでてきます)。
そして最後に残るエラーですが、マージソートを扱う際に可変長配列を定義している部分になりますが、Visualstudioでは拡張子をcにしてC言語としてコンパイルしても、このような記述はできないようです。ですので工夫が必要かと思われます。
以下にソースコードと、実行結果のスクショを載せました。すこしでも参考になれば幸いです。
実行結果
---
[実行結果1](https://gyazo.com/b4e2bcab8db11190007e4561a41a3899)
[実行結果2](https://gyazo.com/102c66b14139925051b6a85cd2037e1c)
[実行結果3](https://gyazo.com/b79309c7718d53c24f8a165783b29f6d)
[実行結果4](https://gyazo.com/a584ce07130b39ddbbe283764f975613)
ソースコード
---
```C
#include <stdio.h>
#include <string.h>
#define MAX 100   /*保存可能な最大人数,名前入力の最長文字数*/
/*学生リストの型を定義*/
struct student{
   int id;       /*番号*/
   char name[MAX];   /*名前*/
   int score;   /*得点*/
};
/*構造体内の配列を関数に渡すために型を宣言*/
typedef struct student type_list;
/*変数*/
type_list list_all[MAX];   /*追加された全学生の構造体配列*/
type_list list_temp[MAX];   /*まだ追加されていない新規の学生の構造体配列*/
int menu=4;   /*メニュー指示番号(1~4)*/
char line[MAX];   /*キーボードによる入力, 1行分*/
int i;   /*カウンター*/
int number_temp=0;   /*新規追加されたtemp内の件数*/
int number_all=0;   /*追加済みの学生数の数*/
/*関数宣言文*/
void newStudent();   /*新規作成用*/
void viewTemp();   /*作成済み構造体リスト中身確認用*/
void viewAll();       /*追加済み構造体リスト中身確認用*/
void deleteTemp();   /*作成済み構造体リスト初期化*/
void add();           /*新規作成分を追加(list_allに保存)*/
void sort();       /*マージソート呼び出し*/
void merge();       /*マージソート, 結合部分*/
void mergeSort();   /*マージソート, 分割部分*/
/*メイン関数*/
int main(void){
   /*終了が指示されるまで何度もメニューを回すためにループ*/
   while(1){
       puts(">>メニューを入力して下さい (半角数字1~4)");
       puts("1.新規作成 2.追加 3.ソート 4.終了 ");
       fflush(0);   /*バッファの吐き出し (Eclipse等のIDEによってはこれをやらないと出力が表示されない場合がある)*/
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
       switch(menu){
       case 1:
           newStudent();   /*新規作成*/
           break;
       case 2:
           add();           /*追加*/
           break;
       case 3:
           sort();           /*ソート*/
           break;
       case 4:
           puts(">>終了します。 Bye-Bye");
           return 0;   /*リターンによってプログラムを終了*/
       default:
           puts(">>半角数字 1~4 を一文字のみ入力してください。");   /*想定外の入力に対して警告し,メニューの最初から*/
           break;
       }
   }
   return 0;
}
void newStudent(){
   /*学生情報の入力をループ*/
   while(1){
       puts(">>学生の情報を入力してください。");
       printf("番号:");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&list_temp[number_temp].id);   /*数値として 新規学生構造体配列へ順番に格納*/
       printf("氏名:");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%s",&list_temp[number_temp].name);   /*数値として 新規学生構造体配列へ順番に格納*/
       printf("点数:");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&list_temp[number_temp].score);   /*数値として 新規学生構造体配列へ順番に格納*/
       ++number_temp;   /*作成件数を +1*/
       //printf("%d %s %d",list_temp[number].id,list_temp[number].name,list_temp[number].score);
       puts(">>新規作成されました。指示を入力してください。");
       puts("1.続けて新規作成 2.作成された一覧を表示 3.メニューへ戻る");
       fflush(0);
       fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
       sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
       switch(menu){
       case 1:
           break;   /*ループを続行*/
       case 2:
           viewTemp();   /*作成された一覧を表示*/
           return;
       case 3:
           return;
       }
   }
   return;
}
void viewTemp(){
   puts("--------------------");
   for(i=0;i<number_temp;i++){
       printf(">> 番号: %d, 指名: %s, 点数: %d \n",list_temp[i].id,list_temp[i].name,list_temp[i].score);
   }
   puts("--------------------");
   printf(">>新規で %d 件,作成されました。まだ追加はされておりません。\n",number_temp);
   puts(">>指示を入力してください。さらに追加する場合は一度メニューにもどり、新規作成を選択してください。");
   puts("1.メニューに戻る 2.これら新規データを消去");
   fflush(0);
   fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
   sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
   /*削除が指示された場合*/
   if(menu==2){
       deleteTemp();
       puts("追加せず、削除しました。");
   }
   return;
}
void viewAll(){
   puts("--------------------");
   for(i=0;i<number_all;i++){
       printf("番号: %d, 指名: %s, 点数: %d \n",list_all[i].id,list_all[i].name,list_all[i].score);
   }
   puts("--------------------");
   printf(">>現在合計で %d 件です。\n",number_all);
   return;
}
void deleteTemp(){
   for(i=0;i<number_temp;i++){
       list_temp[i].id=0;
       list_temp[i].name[0]='\0';
       list_temp[i].score=0;
   }
   number_temp=0;
   return;
}
void add(){
   /*構造体配列内の対応する各要素ごとに代入*/
   for(i=0;i<number_temp;i++){
       list_all[number_all + i].id=list_temp[i].id;
       strcpy(list_all[number_all + i].name,list_temp[i].name);   /*文字列なのでstrcpyを使用*/
       list_all[number_all + i].score=list_temp[i].score;
   }
   printf("既存の %d 件に,新規の %d 件が加わり、合計 %d 件になりました。\n",number_all, number_temp,number_all+number_temp);
   number_all+=number_temp;   /*追加済み件数を更新*/
   deleteTemp();   /*新規作成リストtemp内をクリアし、作成件数もリセット*/
   viewAll();   /*追加済みリスト確認*/
   return;
}
/*--------------------------ソート関係の関数---------------------------
*
*   採用アルゴリズム: マージソート
*
*   変数: 追加済み生徒の構造体リスト, 及びその件数
*
*   関数:sort()           ソートのメイン関数,帰納の復帰先
*        merge()       二つの分割から一つの構造体へ小さい順に並べ替える
*        mergeSort()   帰納させる関数,構造体を二つの構造体へ分割
*
*   動作: 構造体内の比較対象となる配列で比較し、番号、名前、点数すべてを毎回移動させる
*
--------------------------------------------------------------------*/
/*帰納の復帰先*/
void sort(){
   puts(">>追加済み件数を何でソートしますか?(作成されたが未追加のものはソートの対象ではありません。)");   /*構造体list_tempはソートの対象外*/
   puts("1.番号 2.得点 3.メニューへ戻る");
   fflush(0);
   fgets(line,sizeof(line),stdin);   /*キーボードの入力を読み取る*/
   sscanf(line,"%d",&menu);   /*数値として メニュー指示変数 "menu" へ格納*/
   if(menu==1){   /*番号でソート*/
       mergeSort(list_all,number_all);
       viewAll();
       puts(">>学生番号によるソートが完了しました");
       puts("");
   }else if(menu==2){   /*得点でソート*/
       puts("未実装, メニューへもどります。");
   }else{
       /*それ以外の入力に対してはメニューへ戻る*/
   }
   return;
}
void merge(type_list *ALL, type_list *L, int L_count, type_list *R, int R_count){
   int i,j,k;   /*カウンター*/
   i=0;
   j=0;
   k=0;
   /*分割右側と分割左側を比較しながらALLへ統合させる*/
   /*どちらか片方の分割が全て統合されたら、あとは評価せず、他方はそのままALLの最後へ*/
   while(i<L_count && j< R_count){
       /*分割右側と分割左側のそれぞれの最小値を比較*/
       /*小さい方を選択し,ALLへ移動,同時に名前,点数も移動*/
       if(L[i].id<R[j].id){
           ALL[k].id=L[i].id;
           strcpy(ALL[k].name,L[i].name);
           ALL[k].score=L[i].score;
           k++;
           i++;
       }else{
           ALL[k].id=R[j].id;
           strcpy(ALL[k].name,R[j].name);
           ALL[k].score=R[j].score;
           k++;
           j++;
       }
   }
   /*評価せずに終わった方をそのままALLへ結合させるコード*/
   while(i<L_count){   /*右側配列が先に全てALLへ統合された場合*/
       ALL[k].id=L[i].id;
       strcpy(ALL[k].name,L[i].name);
       ALL[k].score=L[i].score;
       k++;
       i++;
   }
   while(j<R_count){   /*左側配列が先に全てALLへ統合された場合*/
       ALL[k].id=R[j].id;
       strcpy(ALL[k].name,R[j].name);
       ALL[k].score=R[j].score;
       k++;
       j++;
   }
/*   デバッグ用 (R と L の中身を確認する)
   for(i=0;i<L_count;i++){
       printf("L[%d] - %d %s %d\n",i,L[i].id,L[i].name,L[i].score);
   }
   for(i=0;i<R_count;i++){
       printf("R[%d] - %d %s %d\n",i,R[i].id,R[i].name,R[i].score);
   }*/
}
void mergeSort(type_list *ALL, int n){
   int mid;   /*構造体配列の真ん中を定義*/
   mid = n/2;
   if(n<2) return;   /*帰納の復帰*/
   type_list L[mid];   /*分割左側を格納する構造体を定義*/
   type_list R[n-mid];   /*分割右側を格納する構造体を定義*/
   /*与えられた構造体(最初の一回目の呼び出しでは追加済み学生リスト)の2つに分割する*/
   /*左側を構造体 L へ, 右側を構造体 R へ*/
   for(i=0;i<mid;i++) {
       L[i].id=ALL[i].id;
       strcpy(L[i].name,ALL[i].name);
       L[i].score=ALL[i].score;
   }
   for(i=mid;i<n;i++){
       R[i-mid].id=ALL[i].id;
       strcpy(R[i-mid].name,ALL[i].name);
       R[i-mid].score=ALL[i].score;
   }
/*   デバッグ用 (R と L の中身を確認する)
   for(i=0;i<mid;i++){
       printf("L[%d] - %d %s %d\n",i,L[i].id,L[i].name,L[i].score);
   }
   for(i=0;i<mid;i++){
       printf("R[%d] - %d %s %d\n",i,R[i].id,R[i].name,R[i].score);
   }*/
   /*----------帰納処理----------*/
   /*分割する関数の中でその関数自体を呼び出し、分割し続ける*/
   /*比較対象が (n<2) になり、returnするまで分割し続ける。*/
   mergeSort(L,mid);   /*分割された左側をさらに分割*/
   mergeSort(R,n-mid);   /*分割された右側をさらに分割*/
   merge(ALL,L,mid,R,n-mid);   /*returnして戻ってきたものをソートして結合*/
}
```

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る