質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

2回答

3269閲覧

C言語 線形リスト

Inabahitsuji

総合スコア8

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2016/03/19 18:15

編集2022/01/12 10:55

初歩的な質問で非情に申し訳ないのですがどなたかお力添えをして頂けないでしょうか。
下記のコードの機能を新規作成、追加、ソートに変更したいのですが一向にうまくいかず、詰まっている状態です。

「機能説明」
・新規作成…番号、氏名、得点を入力
・追加…新規作成によって入力されたものをリストに格納
・ソート…番号順や得点順を昇順降順に切り替えれるもの

・追記・
質問内容の指摘ありがとうございます、こういった場で尋ねるのは初めてでどうお聞きすればいいのかさえ分からず本当に申し訳ありません…。

新しく作る「新規作成機能」は下記の「追加機能」を利用したいのですが、そのままでは上記の機能説明で言うところの「新規作成」と「追加」を同時に行ってしまうため、新規作成で入力・追加で格納するといった形にしたいのです。

構築環境
win10
visualStudio2015

「実行結果のイメージ」
メニューを入力して下さい
1.新規作成2.追加3.ソート4.終了
1
番号:xx
氏名:yy
得点:zz

新規作成が完了しました
このデータを追加する場合はメニューにて追加を選択して下さい

メニューを入力して下さい
1.新規作成2.追加3.ソート4.終了

まだ追加されていないデータがありますがよろしいですか?
1.はい2.いいえ
2

メニューを入力して下さい
1.新規作成2.追加3.ソート4.終了
2

追加が完了しました

メニューを入力して下さい
1.新規作成2.追加3.ソート4.終了
3

追加されたデータのソートを行います
1.番号順2.得点順
1

番号1 氏名xx 得点yy

C言語

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5#define BUFSIZE 20 6#define DATASIZE 100 7 8 9 typedef struct address { 10 int szNum; //番号 11 char szName[10]; //氏名 12 int szPoint; //得点 13} Numress; 14 15 int search(Numress *ap, int cnt); 16 int add(Numress *ap, int cnt); 17 int amend(Numress *ap, int cnt); 18 int del(Numress *ap, int cnt); 19 int printall(Numress *ap, int cnt); 20 21 /* 関数のジャンプテーブル */ 22 int(*func[])(Numress *, int) = { search, add, amend, del, printall }; 23 24 /* 構造体の配列 -- 大きくてスタックを消費する可能性があるので静的に定義した */ 25 Numress ad[DATASIZE]; 26 27 //処理の選択 28 int main(void) 29 { 30 char dummy[BUFSIZE]; 31 int i, cnt = 0; 32 33 while (1) { 34 puts("●メニューを入力して下さい"); 35 puts("1.検索\n2.追加\n3.修正\n4.削除\n5.全体表示\n6.終了"); 36 scanf("%d", &i); gets(dummy); 37 if (1 <= i && i <= 5) cnt = func[i - 1](ad, cnt); 38 else if (i == 6) break; 39 } 40 41 return 0; 42 } 43 int search(Numress *ap, int cnt) 44 { 45 char buf[BUFSIZE], dummy[BUFSIZE]; 46 char *target[] = { "番号", "氏名", "得点" }; 47 int i, j = 0, count = 0; 48 Numress *t = ap; 49 50 while (1) { 51 puts("何で探しますか?\n1.番号 2.氏名 3.得点"); 52 scanf("%d", &i); gets(dummy); 53 if (1 <= i && i <= 3) break; 54 } 55 printf("%sを入力して下さい:", target[--i]); 56 gets(buf); 57 58 while (j++ < cnt) { 59 switch (i) { 60 case 0: /* 番号 */ 61 if (!strcmp(t->szNum, buf)) goto print; 62 break; 63 case 1: /* 氏名 */ 64 if (!strcmp(t->szName, buf)) goto print; 65 break; 66 case 2: /* 得点 */ 67 if (!strcmp(t->szPoint, buf)) goto print; 68 break; 69 default: /* no condition、ここには来ない */ 70 break; 71 } 72 t++; 73 continue; 74 print:; 75 printf("%d: 番号:%s 氏名:%s 得点:%s\n", j, t->szNum, t->szName, t->szPoint); 76 t++; 77 count++; 78 } 79 printf("%d件Hit\n", count); 80 81 return cnt; 82 } 83 84 int add(Numress *ap, int cnt) 85 { 86 Numress *t = ap + cnt; 87 88 if (cnt == DATASIZE) { 89 puts("これ以上追加できません"); 90 return cnt; 91 } 92 printf("番号:"); 93 gets(t->szNum); 94 printf("氏名:"); 95 gets(t->szName); 96 printf("得点:"); 97 gets(t->szPoint); 98 99 return cnt + 1; 100 } 101 102 int amend(Numress *ap, int cnt) 103 { 104 Numress *t; 105 char buf[BUFSIZE]; 106 int i; 107 108 puts("何番を修正しますか?"); 109 scanf("%d", &i); gets(buf); 110 111 if (i > 0 && i <= cnt) { 112 t = ap + i - 1; /* 配列のアドレスの計算 */ 113 puts("変更しない場合は単に[return]を押して下さい"); 114 printf("番号: %s -> ", t->szNum); 115 gets(buf); 116 if (strlen(buf)) strcpy(t->szNum, buf); 117 printf("氏名: %s -> ", t->szName); 118 gets(buf); 119 if (strlen(buf)) strcpy(t->szName, buf); 120 printf("得点: %s -> ", t->szPoint); 121 gets(buf); 122 if (strlen(buf)) strcpy(t->szPoint, buf); 123 } 124 else 125 puts("番号が不適切です"); 126 return cnt; 127 } 128 int del(Numress *ap, int cnt) 129 { 130 char buf[BUFSIZE]; 131 int i, j; 132 133 puts("何番を削除しますか?"); 134 scanf("%d", &i); gets(buf); 135 136 if (i > 0 && i <= cnt) { 137 for (j = i - 1; j < cnt - 1; j++) 138 ap[j] = ap[j + 1]; 139 return cnt - 1; 140 } 141 142 puts("番号が不適切です"); 143 return cnt; 144 } 145 146 147 int printall(Numress *ap, int cnt) 148 { 149 int i = 0; 150 151 while (i < cnt) { 152 printf("%d: 番号:%s 氏名:%s 得点:%s\n", ++i, ap->szNum, ap->szName, ap->szPoint); 153 ap++; 154 } 155 156 return cnt; 157 } 158

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2016/03/19 21:40 編集

>一向にうまくいかず・・・ 何がうまくいかないのでしょう? 環境(OS,コンパイラなど)を教えてください。また、gets()は推奨されません。fgets()を使いましょう。
guest

回答2

0

c

1typedef struct address { 2 int szNum; //番号 3 char szName[10]; //氏名 4 int szPoint; //得点 5} Numress;

上記構造では線形リストは構成できません。(ポインタを他に持つなら別ですが…)
また、Numress *t = ap + cnt;など配列に対するアクセス方法になっているのは何故でしょう?
線形リストの実装方法など検索して調べてみてください。
「追記」
Cでのリスト操作については、下記サイトが比較的わかりやすいと思います。
連結リスト

投稿2016/03/20 04:14

編集2016/03/20 14:10
cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Inabahitsuji

2016/03/20 04:37

ご指摘ありがとうございます、ネットの解説を見ても今一つ飲み込めず理解に至らなかった結果この様な結果になってしまったのです…。 もう一度改めて一から調べ直しますね、お手数お掛けしました。 もし行き詰ったときにまたアドバイスを頂けると凄く嬉しいです、本当にありがとうございました。
cateye

2016/03/27 01:28

ソートの処理については、表示だけであれば、各データのポインタを他に持ってポインタのみソートする方法が簡単だと思います。実データの入れ替えならばポインタはそのままに中身だけ入れ替える関数(リストは壊さずに中身だけ変える…)を定義して行えばいいと思います。当然、比較関数は必要ですが。
guest

0

記述してみました。

コード説明

質問の変更したい内容のとおり、完全に別れた機能として「新規作成」と「追加」、また、番号によるソート機能のコードを記述しました。
新規作成で一時的な構造体へ保存して、追加でメインの構造体へ移動させる、という方式をとり、その都度リストを表示させ中身を確認、一括削除できるようにしました。

点数でのソートに関しては番号でのソートと同じ要領で記述すれば実装できます。また、ソート自体に関しても他にもたくさんアルゴリズムがあるようなので、自分のプログラムにあったものを探してみるといいかとおもいます。

そして、一番大事なことですが、私は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

投稿2016/03/29 15:42

編集2018/06/12 13:39
Sophian

総合スコア36

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pepperleaf

2018/06/12 14:09

こちらのVisual Stdio 2017環境では、コンパイルできました。(コマンドライン) ただし、Warningの山で、まともに動くとは思えませんでしたが、、。 文字列と数値の区別がついていないように思われます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問