記述してみました。
コード説明
質問の変更したい内容のとおり、完全に別れた機能として「新規作成」と「追加」、また、番号によるソート機能のコードを記述しました。
新規作成で一時的な構造体へ保存して、追加でメインの構造体へ移動させる、という方式をとり、その都度リストを表示させ中身を確認、一括削除できるようにしました。
点数でのソートに関しては番号でのソートと同じ要領で記述すれば実装できます。また、ソート自体に関しても他にもたくさんアルゴリズムがあるようなので、自分のプログラムにあったものを探してみるといいかとおもいます。
そして、一番大事なことですが、私はVisual Studioではコンパイルできませんでした。
当方、Eclipseですべて記述しました。
そのまま以下のコードをコピペするとエラーを大量に吐きます。
解決方法としては、まず、コンパイル済みヘッダーを読み込まないようにします。
つづいて、sscanfを使用しているのでこれを使用できるようにソースコードに一行記述を加えます(ググればすぐでてきます)。
そして最後に残るエラーですが、マージソートを扱う際に可変長配列を定義している部分になりますが、Visualstudioでは拡張子をcにしてC言語としてコンパイルしても、このような記述はできないようです。ですので工夫が必要かと思われます。
以下にソースコードと、実行結果のスクショを載せました。すこしでも参考になれば幸いです。
実行結果
実行結果1
実行結果2
実行結果3
実行結果4
ソースコード
C
1#include <stdio.h>
2#include <string.h>
3#define MAX 100 /*保存可能な最大人数,名前入力の最長文字数*/
4
5/*学生リストの型を定義*/
6struct student{
7 int id; /*番号*/
8 char name[MAX]; /*名前*/
9 int score; /*得点*/
10};
11
12/*構造体内の配列を関数に渡すために型を宣言*/
13typedef struct student type_list;
14
15/*変数*/
16type_list list_all[MAX]; /*追加された全学生の構造体配列*/
17type_list list_temp[MAX]; /*まだ追加されていない新規の学生の構造体配列*/
18int menu=4; /*メニュー指示番号(1~4)*/
19char line[MAX]; /*キーボードによる入力, 1行分*/
20int i; /*カウンター*/
21int number_temp=0; /*新規追加されたtemp内の件数*/
22int number_all=0; /*追加済みの学生数の数*/
23
24/*関数宣言文*/
25void newStudent(); /*新規作成用*/
26void viewTemp(); /*作成済み構造体リスト中身確認用*/
27void viewAll(); /*追加済み構造体リスト中身確認用*/
28void deleteTemp(); /*作成済み構造体リスト初期化*/
29void add(); /*新規作成分を追加(list_allに保存)*/
30
31void sort(); /*マージソート呼び出し*/
32void merge(); /*マージソート, 結合部分*/
33void mergeSort(); /*マージソート, 分割部分*/
34
35/*メイン関数*/
36int main(void){
37
38 /*終了が指示されるまで何度もメニューを回すためにループ*/
39 while(1){
40 puts(">>メニューを入力して下さい (半角数字1~4)");
41 puts("1.新規作成 2.追加 3.ソート 4.終了 ");
42 fflush(0); /*バッファの吐き出し (Eclipse等のIDEによってはこれをやらないと出力が表示されない場合がある)*/
43
44 fgets(line,sizeof(line),stdin); /*キーボードの入力を読み取る*/
45 sscanf(line,"%d",&menu); /*数値として メニュー指示変数 "menu" へ格納*/
46
47 switch(menu){
48 case 1:
49 newStudent(); /*新規作成*/
50 break;
51 case 2:
52 add(); /*追加*/
53 break;
54 case 3:
55 sort(); /*ソート*/
56 break;
57 case 4:
58 puts(">>終了します。 Bye-Bye");
59 return 0; /*リターンによってプログラムを終了*/
60 default:
61 puts(">>半角数字 1~4 を一文字のみ入力してください。"); /*想定外の入力に対して警告し,メニューの最初から*/
62 break;
63 }
64 }
65 return 0;
66}
67
68void newStudent(){
69
70 /*学生情報の入力をループ*/
71 while(1){
72 puts(">>学生の情報を入力してください。");
73 printf("番号:");
74 fflush(0);
75 fgets(line,sizeof(line),stdin); /*キーボードの入力を読み取る*/
76 sscanf(line,"%d",&list_temp[number_temp].id); /*数値として 新規学生構造体配列へ順番に格納*/
77
78 printf("氏名:");
79 fflush(0);
80 fgets(line,sizeof(line),stdin); /*キーボードの入力を読み取る*/
81 sscanf(line,"%s",&list_temp[number_temp].name); /*数値として 新規学生構造体配列へ順番に格納*/
82
83 printf("点数:");
84 fflush(0);
85 fgets(line,sizeof(line),stdin); /*キーボードの入力を読み取る*/
86 sscanf(line,"%d",&list_temp[number_temp].score); /*数値として 新規学生構造体配列へ順番に格納*/
87
88 ++number_temp; /*作成件数を +1*/
89
90 //printf("%d %s %d",list_temp[number].id,list_temp[number].name,list_temp[number].score);
91
92 puts(">>新規作成されました。指示を入力してください。");
93 puts("1.続けて新規作成 2.作成された一覧を表示 3.メニューへ戻る");
94 fflush(0);
95 fgets(line,sizeof(line),stdin); /*キーボードの入力を読み取る*/
96 sscanf(line,"%d",&menu); /*数値として メニュー指示変数 "menu" へ格納*/
97
98 switch(menu){
99 case 1:
100 break; /*ループを続行*/
101 case 2:
102 viewTemp(); /*作成された一覧を表示*/
103 return;
104 case 3:
105 return;
106 }
107 }
108 return;
109}
110
111void viewTemp(){
112
113 puts("--------------------");
114 for(i=0;i<number_temp;i++){
115 printf(">> 番号: %d, 指名: %s, 点数: %d \n",list_temp[i].id,list_temp[i].name,list_temp[i].score);
116 }
117 puts("--------------------");
118
119 printf(">>新規で %d 件,作成されました。まだ追加はされておりません。\n",number_temp);
120 puts(">>指示を入力してください。さらに追加する場合は一度メニューにもどり、新規作成を選択してください。");
121 puts("1.メニューに戻る 2.これら新規データを消去");
122 fflush(0);
123 fgets(line,sizeof(line),stdin); /*キーボードの入力を読み取る*/
124 sscanf(line,"%d",&menu); /*数値として メニュー指示変数 "menu" へ格納*/
125
126 /*削除が指示された場合*/
127 if(menu==2){
128 deleteTemp();
129 puts("追加せず、削除しました。");
130 }
131 return;
132
133}
134
135void viewAll(){
136 puts("--------------------");
137 for(i=0;i<number_all;i++){
138 printf("番号: %d, 指名: %s, 点数: %d \n",list_all[i].id,list_all[i].name,list_all[i].score);
139 }
140 puts("--------------------");
141
142 printf(">>現在合計で %d 件です。\n",number_all);
143
144 return;
145}
146
147void deleteTemp(){
148
149 for(i=0;i<number_temp;i++){
150 list_temp[i].id=0;
151 list_temp[i].name[0]='\0';
152 list_temp[i].score=0;
153 }
154 number_temp=0;
155
156 return;
157}
158
159void add(){
160
161 /*構造体配列内の対応する各要素ごとに代入*/
162 for(i=0;i<number_temp;i++){
163 list_all[number_all + i].id=list_temp[i].id;
164 strcpy(list_all[number_all + i].name,list_temp[i].name); /*文字列なのでstrcpyを使用*/
165 list_all[number_all + i].score=list_temp[i].score;
166 }
167
168 printf("既存の %d 件に,新規の %d 件が加わり、合計 %d 件になりました。\n",number_all, number_temp,number_all+number_temp);
169
170 number_all+=number_temp; /*追加済み件数を更新*/
171 deleteTemp(); /*新規作成リストtemp内をクリアし、作成件数もリセット*/
172
173 viewAll(); /*追加済みリスト確認*/
174
175 return;
176}
177
178
179/*--------------------------ソート関係の関数---------------------------
180*
181* 採用アルゴリズム: マージソート
182*
183* 変数: 追加済み生徒の構造体リスト, 及びその件数
184*
185* 関数:sort() ソートのメイン関数,帰納の復帰先
186* merge() 二つの分割から一つの構造体へ小さい順に並べ替える
187* mergeSort() 帰納させる関数,構造体を二つの構造体へ分割
188*
189* 動作: 構造体内の比較対象となる配列で比較し、番号、名前、点数すべてを毎回移動させる
190*
191--------------------------------------------------------------------*/
192
193
194/*帰納の復帰先*/
195void sort(){
196 puts(">>追加済み件数を何でソートしますか?(作成されたが未追加のものはソートの対象ではありません。)"); /*構造体list_tempはソートの対象外*/
197 puts("1.番号 2.得点 3.メニューへ戻る");
198 fflush(0);
199 fgets(line,sizeof(line),stdin); /*キーボードの入力を読み取る*/
200 sscanf(line,"%d",&menu); /*数値として メニュー指示変数 "menu" へ格納*/
201
202 if(menu==1){ /*番号でソート*/
203
204 mergeSort(list_all,number_all);
205 viewAll();
206 puts(">>学生番号によるソートが完了しました");
207 puts("");
208
209 }else if(menu==2){ /*得点でソート*/
210 puts("未実装, メニューへもどります。");
211 }else{
212 /*それ以外の入力に対してはメニューへ戻る*/
213 }
214 return;
215}
216
217void merge(type_list *ALL, type_list *L, int L_count, type_list *R, int R_count){
218 int i,j,k; /*カウンター*/
219
220 i=0;
221 j=0;
222 k=0;
223
224 /*分割右側と分割左側を比較しながらALLへ統合させる*/
225 /*どちらか片方の分割が全て統合されたら、あとは評価せず、他方はそのままALLの最後へ*/
226 while(i<L_count && j< R_count){
227
228 /*分割右側と分割左側のそれぞれの最小値を比較*/
229 /*小さい方を選択し,ALLへ移動,同時に名前,点数も移動*/
230 if(L[i].id<R[j].id){
231 ALL[k].id=L[i].id;
232 strcpy(ALL[k].name,L[i].name);
233 ALL[k].score=L[i].score;
234 k++;
235 i++;
236 }else{
237 ALL[k].id=R[j].id;
238 strcpy(ALL[k].name,R[j].name);
239 ALL[k].score=R[j].score;
240 k++;
241 j++;
242 }
243 }
244
245 /*評価せずに終わった方をそのままALLへ結合させるコード*/
246 while(i<L_count){ /*右側配列が先に全てALLへ統合された場合*/
247 ALL[k].id=L[i].id;
248 strcpy(ALL[k].name,L[i].name);
249 ALL[k].score=L[i].score;
250 k++;
251 i++;
252 }
253
254 while(j<R_count){ /*左側配列が先に全てALLへ統合された場合*/
255 ALL[k].id=R[j].id;
256 strcpy(ALL[k].name,R[j].name);
257 ALL[k].score=R[j].score;
258 k++;
259 j++;
260 }
261
262/* デバッグ用 (R と L の中身を確認する)
263 for(i=0;i<L_count;i++){
264 printf("L[%d] - %d %s %d\n",i,L[i].id,L[i].name,L[i].score);
265 }
266 for(i=0;i<R_count;i++){
267 printf("R[%d] - %d %s %d\n",i,R[i].id,R[i].name,R[i].score);
268 }*/
269}
270
271void mergeSort(type_list *ALL, int n){
272 int mid; /*構造体配列の真ん中を定義*/
273 mid = n/2;
274
275 if(n<2) return; /*帰納の復帰*/
276
277 type_list L[mid]; /*分割左側を格納する構造体を定義*/
278 type_list R[n-mid]; /*分割右側を格納する構造体を定義*/
279
280 /*与えられた構造体(最初の一回目の呼び出しでは追加済み学生リスト)の2つに分割する*/
281 /*左側を構造体 L へ, 右側を構造体 R へ*/
282 for(i=0;i<mid;i++) {
283 L[i].id=ALL[i].id;
284 strcpy(L[i].name,ALL[i].name);
285 L[i].score=ALL[i].score;
286 }
287
288 for(i=mid;i<n;i++){
289 R[i-mid].id=ALL[i].id;
290 strcpy(R[i-mid].name,ALL[i].name);
291 R[i-mid].score=ALL[i].score;
292 }
293
294/* デバッグ用 (R と L の中身を確認する)
295 for(i=0;i<mid;i++){
296 printf("L[%d] - %d %s %d\n",i,L[i].id,L[i].name,L[i].score);
297 }
298 for(i=0;i<mid;i++){
299 printf("R[%d] - %d %s %d\n",i,R[i].id,R[i].name,R[i].score);
300 }*/
301
302 /*----------帰納処理----------*/
303 /*分割する関数の中でその関数自体を呼び出し、分割し続ける*/
304 /*比較対象が (n<2) になり、returnするまで分割し続ける。*/
305 mergeSort(L,mid); /*分割された左側をさらに分割*/
306 mergeSort(R,n-mid); /*分割された右側をさらに分割*/
307
308 merge(ALL,L,mid,R,n-mid); /*returnして戻ってきたものをソートして結合*/
309}
310