teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

6

コードの修正

2018/01/30 06:17

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -31,17 +31,6 @@
31
31
  #include <string.h>
32
32
  #include <assert.h> //
33
33
 
34
- //assert.hでは、assertマクロが定義されています。
35
-
36
- //assertマクロは関数形式マクロで、引数に偽(すなわち0)が指定されると、
37
- //ソースファイル名や行番号等の情報を標準エラー出力に出力し、
38
- //プログラムを終了させます。
39
- //プログラマは、assertマクロが出力する情報をもとにデバッグを行います。
40
-
41
- //NDEBUGマクロが定義されていると、assertマクロは、次のように定義され、
42
- //何もしません。
43
- //#define assert(ignore) ((void)0)
44
-
45
34
  #define N 256
46
35
  #define FILENAME "address.csv"
47
36
 
@@ -55,20 +44,13 @@
55
44
  };
56
45
 
57
46
  void data_show(struct address* head);
58
- void data_add(struct address** head);
59
- void data_delete(struct address** head);
60
47
  void data_sort(struct address** head);
61
- void data_write(struct address* head);
62
48
 
63
- void data_amend(struct address* head);
64
- void data_search(struct address* head);
65
-
66
49
  void chop(char *p){
67
50
  for (; *p; p++)
68
51
  ;
69
-
52
+
70
53
  p--;
71
-
72
54
  while (*p == '\r' || *p == '\n')
73
55
  *(p--) = 0;
74
56
 
@@ -81,14 +63,12 @@
81
63
 
82
64
  strcpy(p->name, name);
83
65
 
84
- strcpy(p->address, address);
66
+ strcpy(p->address, address);
67
+
68
+ strcpy(p->tel, tel);
85
69
 
86
- strcpy(p->tel, tel);
87
-
88
-
89
70
  strcpy(p->mail, mail);
90
-
91
-
71
+
92
72
  p->next = *head;
93
73
  if (p->next != 0)
94
74
  p->next->before = p;
@@ -131,145 +111,44 @@
131
111
 
132
112
  r = *p; s = *q;
133
113
  if (&((*p)->next) == q || &((*q)->next) == p) {
134
-
135
-
136
-
137
-
138
-
139
114
 
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
- // &((*p)->next) == q において、**pはaddress構造体型ですから、
155
- //*pはaddress構造体へのポインタです。
156
- //従って、(*p)もaddress構造体へのポインタです。
157
- //であれば、(*p)->nextはaddress構造体のnextメンバですね。
158
- //ならば、&((*p)->next)はそのアドレスですから、nextメンバのアドレスとなります。
159
-
160
- //それと q が等しいという条件ですから、qはadress構造体のnextメンバを
161
- //ポイントしているのだろうと思います。
162
-
163
- //つまり、*pが指すaddress構造体のnextメンバを
164
- //qがポイントしているならば、この条件が成立します。
165
-
166
-
167
-
168
- if (s->next != 0){
115
+ if (s->next != 0){
116
+
169
- s->next->before = r;
117
+ s->next->before = r;
170
118
 
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
- }
119
+ }
199
120
  s->before = r->before;
200
-
201
-
121
+
202
122
  r->before = s;
203
-
204
- *p = s;
205
123
 
206
-
207
- *q = s->next;
124
+ *p = s;
208
125
 
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
- s->next = r;
126
+ *q = s->next;
222
127
 
223
-
128
+ s->next = r;
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
129
+
235
130
  return;
236
- } else { //if ((&((*p)->next)) != q && (&((*q)->next) != p)) の時だと思う
131
+ } else {
237
132
  if (s->next != 0)
238
- // (*q)->nextが0でないとき
133
+
239
-
240
134
  s->next->before = r;
241
- // (s->next)->before=*p
135
+
242
-
243
136
  if (r->next != 0)
244
- // (*p)->nextが0でないとき
137
+
245
-
246
138
  r->next->before = s;
247
- // (r->next)->before=*q
139
+
248
-
249
140
  t = s->before;
250
- // s->before==(*q)->before
141
+
251
- // t=(*q)->before
252
-
253
142
  s->before = r->before;
254
- // s->beforeにr->before==(*p)->before(これはポインタ)を代入する。
143
+
255
-
256
144
  r->before = t;
257
- // r->before==(*p)->before
145
+
258
- // t=s->before
259
- // r->beforeにs->before==(*q)->before(これはポインタ)を代入する。
260
-
261
146
  t = r->next;
262
- // r->next==(*p)->nextが0でないときであるから
263
- // t=(*p)->next
264
147
 
265
148
  r->next = s->next;
266
- // s->next==(*q)->next
149
+
267
- // r->next =(*q)->next
268
-
269
150
  s->next = t;
270
- // t=(*p)->next
151
+
271
- // s->next=(*p)->next
272
-
273
152
  *p = s;
274
153
  *q = r;
275
154
  }
@@ -287,27 +166,7 @@
287
166
  //そうでないと正しくソートされません。
288
167
 
289
168
  if (p == 0)break;
290
- //「リストの先頭が空のとき、返り値が0になるので、ソートが完了したとして、
169
+
291
- //ループを抜けます。」ですね.
292
-
293
- //次のように使うことが出来る。
294
-
295
- // char *p = NULL;
296
-
297
- // if (!p) { … /* if (p==0) と等価 */
298
-
299
- //世の中には様々なマイクロプロセッサーがあり、
300
- //現実にNULLポインターの内部表現が「0番地」では無いものも存在する。
301
-
302
- //しかしこの場合でも、ソースコード中の値は0のままで良い。
303
- //なぜなら、NULLポインターというものは抽象的な概念であり、
304
- //物理的なアドレスを指しているわけではないからである。
305
-
306
- //もし内部表現が0でない計算機の場合、必要に応じてCコンパイラーは
307
- //その値に自動的に変換してくれる。
308
- //従って、NULLポインターと0は完全に等価であり、
309
- //可換であるとして扱うことが出来るのである。
310
-
311
170
  exchange(head, p);
312
171
  //大小を入れ替える
313
172
 
@@ -416,6 +275,7 @@
416
275
  */
417
276
 
418
277
 
278
+
419
279
  /* 実行結果
420
280
  naka@naka ~
421
281
  $ cd kadai/kadai9-8
@@ -446,6 +306,7 @@
446
306
  $
447
307
  */
448
308
 
309
+
449
310
  /* 実行結果
450
311
  naka@naka ~
451
312
  $ cd kadai/kadai9-8
@@ -476,6 +337,36 @@
476
337
  $
477
338
  */
478
339
 
340
+ /* 実行結果
341
+ naka@naka ~
342
+ $ cd kadai/kadai9-8
479
343
 
344
+ naka@naka ~/kadai/kadai9-8
345
+ $ gcc -o kad9-8b kad9-8b.c -Wall
480
346
 
347
+ naka@naka ~/kadai/kadai9-8
348
+ $ kad9-8b
349
+ ファイルから読んだ文字列:yamada,tone,090-1122,mail-9
350
+ ファイルから読んだ文字列:hosi,nagoya,5436,mail-7
351
+ ファイルから読んだ文字列:kato,kanagawa,080-8888,mail-2
352
+ ファイルから読んだ文字列:koko,yosida,090-2314,mail-6
353
+ ファイルから読んだ文字列:naka,kamikosaka,080-4444,mail-1
354
+ ファイルから読んだ文字列:nakada,nogata,090-6376,mail-8
355
+ ファイルから読んだ文字列:saito,yamanashi,080-6666,mail-3
356
+ ファイルから読んだ文字列:suzuki,saitama,090-2222,mail-5
357
+ hosi, nagoya, 5436, mail-7
358
+ kato, kanagawa, 080-8888, mail-2
359
+ koko, yosida, 090-2314, mail-6
360
+ naka, kamikosaka, 080-4444, mail-1
361
+ nakada, nogata, 090-6376, mail-8
362
+ saito, yamanashi, 080-6666, mail-3
363
+ suzuki, saitama, 090-2222, mail-5
364
+ yamada, tone, 090-1122, mail-9
365
+
366
+ naka@naka ~/kadai/kadai9-8
367
+ $
368
+ */
369
+
370
+
371
+
481
372
  ```

5

コード修正

2018/01/30 06:17

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -26,12 +26,6 @@
26
26
  //codepad.org/B83f1FSq
27
27
  //正常動作(リスト構造)
28
28
 
29
- //codepad.org/B83f1FSq
30
- //正常動作(リスト構造)
31
-
32
- //codepad.org/B83f1FSq
33
- //正常動作(リスト構造)
34
-
35
29
  #include <stdio.h>
36
30
  #include <stdlib.h>
37
31
  #include <string.h>
@@ -421,6 +415,7 @@
421
415
  $
422
416
  */
423
417
 
418
+
424
419
  /* 実行結果
425
420
  naka@naka ~
426
421
  $ cd kadai/kadai9-8
@@ -451,6 +446,36 @@
451
446
  $
452
447
  */
453
448
 
449
+ /* 実行結果
450
+ naka@naka ~
451
+ $ cd kadai/kadai9-8
454
452
 
453
+ naka@naka ~/kadai/kadai9-8
454
+ $ gcc -o kad9-8b kad9-8b.c -Wall
455
455
 
456
+ naka@naka ~/kadai/kadai9-8
457
+ $ kad9-8b
458
+ ファイルから読んだ文字列:yamada,tone,090-1122,mail-9
459
+ ファイルから読んだ文字列:hosi,nagoya,5436,mail-7
460
+ ファイルから読んだ文字列:kato,kanagawa,080-8888,mail-2
461
+ ファイルから読んだ文字列:koko,yosida,090-2314,mail-6
462
+ ファイルから読んだ文字列:naka,kamikosaka,080-4444,mail-1
463
+ ファイルから読んだ文字列:nakada,nogata,090-6376,mail-8
464
+ ファイルから読んだ文字列:saito,yamanashi,080-6666,mail-3
465
+ ファイルから読んだ文字列:suzuki,saitama,090-2222,mail-5
466
+ hosi, nagoya, 5436, mail-7
467
+ kato, kanagawa, 080-8888, mail-2
468
+ koko, yosida, 090-2314, mail-6
469
+ naka, kamikosaka, 080-4444, mail-1
470
+ nakada, nogata, 090-6376, mail-8
471
+ saito, yamanashi, 080-6666, mail-3
472
+ suzuki, saitama, 090-2222, mail-5
473
+ yamada, tone, 090-1122, mail-9
474
+
475
+ naka@naka ~/kadai/kadai9-8
476
+ $
477
+ */
478
+
479
+
480
+
456
481
  ```

4

図の追加

2018/01/30 06:09

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -29,6 +29,9 @@
29
29
  //codepad.org/B83f1FSq
30
30
  //正常動作(リスト構造)
31
31
 
32
+ //codepad.org/B83f1FSq
33
+ //正常動作(リスト構造)
34
+
32
35
  #include <stdio.h>
33
36
  #include <stdlib.h>
34
37
  #include <string.h>
@@ -69,34 +72,13 @@
69
72
  void chop(char *p){
70
73
  for (; *p; p++)
71
74
  ;
72
-
73
- //まず、char *p に対して、for(s = p; *p; p++) に現れる、
75
+
74
- //*p の型は(ポインタではなく)char そのものです。
75
- //ですから、*p は、「p がポイントしているところにある char のデータ」です。
76
-
77
- //一方、Cでは、文字列は、「'\0' で終端される」という規定になっています。
78
- //ですから、ちょっとくどく書けば、
79
- //for(s = p; *p != '\0' ; p++)ということで,
80
- //「p がポイントする文字が、終端文字(文字列の終わり)にくるまで」
81
- //という意味です。
76
+ p--;
82
-
83
- //そして、(Cのいろいろな背景から) *p != '\0' という表記は、
84
- //*p とだけ書いた時と同じ動作をします。
85
- //このため、文字列の終端をチェックするために、while(*p) とか、
86
- //if(! *p) こっちは、終端にきたときの判断)とかよく使われる表現です。
87
-
88
- //なお、NULL は、「何もポイントしていないポインタ」の値です。
89
- //そして、ちょっと面倒なのが、規格上は、
90
- //「ヌルポインタ(何もポイントしていないポインタ)の値は、
91
- //定数0と比較したときに等しくなる」と定義されている点です。
92
-
93
- p--; // *pが\0となりfor()を抜けるとここに来る。
94
- //ポインタを1個戻して,\0 の前が'\r'か'\n'どうか調べるため。
95
77
 
96
78
  while (*p == '\r' || *p == '\n')
97
79
  *(p--) = 0;
80
+
98
- //
81
+ }
99
- }//chop()を抜けると\0で区切られた文字列になる。
100
82
 
101
83
  void list_add(struct address **head, char *name, char *address, char *tel, char *mail)
102
84
  {
@@ -104,26 +86,15 @@
104
86
  if ((p = malloc(sizeof(struct address))) != 0) {
105
87
 
106
88
  strcpy(p->name, name);
107
- //文字列のコピー
89
+
108
- //【書式】
109
- //#include <string.h>
110
- //char *strcpy(char *s1, const char *s2);
111
-
112
- //【説明】
113
- //文字型配列 *s1 に文字列 *s2 を '\0' までコピーします。
114
- //'\0' もコピーするので s1 はその分も考えて大きさを宣言して
115
- //おかなければなりません。
116
- //もし、s1 と s2 が重なっている場合には動作は未定義となります。
117
-
118
- strcpy(p->address, address);
90
+ strcpy(p->address, address);
91
+
119
- //文字型配列 p->address に文字列 address を '\0' までコピーします。
92
+ strcpy(p->tel, tel);
120
93
 
121
- strcpy(p->tel, tel);
122
- //文字型配列 p->number に文字列 number を '\0' までコピーします。
123
94
 
124
95
  strcpy(p->mail, mail);
125
- //文字型配列 p->mail に文字列 mail を '\0' までコピーします。
126
96
 
97
+
127
98
  p->next = *head;
128
99
  if (p->next != 0)
129
100
  p->next->before = p;
@@ -140,9 +111,6 @@
140
111
  }
141
112
  }
142
113
 
143
- //関数listmin(head)は、名前からリストの全ての要素をチェックして、
144
- //いちばん小さいnameを持つ要素を返していると思われます。
145
- //そうでないと正しくソートされません。
146
114
  struct address **listmin(struct address **head) {
147
115
  struct address **p;
148
116
 
@@ -150,7 +118,7 @@
150
118
  return 0;
151
119
  if ((*head)->next == 0)
152
120
  return head;
153
- //リストが残り1つの場合、ソートが完了したとして、ループを抜けます。
121
+ //
154
122
 
155
123
  if (strcmp((*head)->name, (*(p = listmin(&((*head)->next))))->name) < 0)
156
124
  return head;
@@ -163,73 +131,112 @@
163
131
  {
164
132
  struct address *r, *s, *t;
165
133
  assert(*p != 0 && *q != 0);
166
- //assertマクロは関数形式マクロで、引数に偽(すなわち0)が指定されると、
134
+
167
- //ソースファイル名や行番号等の情報を標準エラー出力に出力し、プログラムを終了させます。
168
135
  if (p == q)
169
136
  return;
170
137
 
171
138
  r = *p; s = *q;
172
139
  if (&((*p)->next) == q || &((*q)->next) == p) {
173
- // &((*p)->next) == q において、**pはaddress構造体型ですから、
140
+
174
- //*pはaddress構造体へのポインタです。
141
+
175
-
176
- //従って、(*p)もaddress構造体へのポインタです。
142
+
143
+
144
+
177
145
 
146
+
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
156
+
157
+
158
+
159
+
160
+ // &((*p)->next) == q において、**pはaddress構造体型ですから、
161
+ //*pはaddress構造体へのポインタです。
162
+ //従って、(*p)もaddress構造体へのポインタです。
178
- //であれば、(*p)->nextはaddress構造体のnextメンバですね。
163
+ //であれば、(*p)->nextはaddress構造体のnextメンバですね。
179
-
180
- //ならば、&((*p)->next)はそのアドレスですから、nextメンバのアドレスとなります。
164
+ //ならば、&((*p)->next)はそのアドレスですから、nextメンバのアドレスとなります。
181
165
 
182
- //それと q が等しいという条件ですから、qはadress構造体のnextメンバを
166
+ //それと q が等しいという条件ですから、qはadress構造体のnextメンバを
183
- //ポイントしているのだろうと思います。
167
+ //ポイントしているのだろうと思います。
184
168
 
185
- //つまり、*pが指すaddress構造体のnextメンバを
169
+ //つまり、*pが指すaddress構造体のnextメンバを
186
- //qがポイントしているならば、この条件が成立します。
170
+ //qがポイントしているならば、この条件が成立します。
187
-
188
-
189
- //&((*q)->next) == pにおいて、**qはaddress構造体型ですから、
171
+
190
- //*qはaddress構造体へのポインタです。
172
+
191
-
192
- //従って、(*q)もaddress構造体へのポインタです。
193
-
194
- //であれば、(*q)->nextはaddress構造体のnextメンバですね。
195
-
196
- //ならば、&((*q)->next)はそのアドレスですから、
197
- //nextメンバのアドレスとなります。
198
-
199
- //それと p が等しいという条件ですから、pはadress構造体のnextメンバを
200
- //ポイントしているのだろうと思います。
201
-
202
- //つまり、*qが指すaddress構造体のnextメンバを
203
- //pがポイントしているならば、この条件が成立します。
204
173
 
205
- if (s->next != 0){
174
+ if (s->next != 0){
206
- // sと*qはおなじである。s->nextは(*q)->nextであるから
207
- // (*q)->nextが0でないとき
208
-
209
- s->next->before = r;
175
+ s->next->before = r;
210
- //「sの次が存在するなら、そいつの手前をrにする」と読める。
176
+
211
- //つまり" r ← sの次 " ってゆー上り方向のリンクを張り替えたってこと。
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+
203
+
212
- }
204
+ }
205
+ s->before = r->before;
213
206
 
207
+
214
208
  r->before = s;
215
- //「sの次が存在しないなら、r の手前をsにする」と読める。
216
- //つまり" s ← (r->before ) " ってゆー上り方向のリンクを張りかえたってこと。
217
209
 
218
- s->before = r->before;
210
+ *p = s;
219
- //「sの次が存在しないなら(s->next == NULL)、s->before をr->beforeにする」と読める。
211
+
220
- //つまり" r->before ← s->before " ってゆー上り方向のリンクを張り替えたってこと。
221
212
 
222
- *p = s;
213
+ *q = s->next;
223
- //*pにs(これはポインタ*q)を代入する。
214
+
224
- //*pをsすなわち*qをさすようにする。
225
215
 
226
- *q = s->next;
227
- //s->nextはNULLであるから*qにNULLを代入する。
228
- //*qはどこもさしていない
229
216
 
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+
226
+
230
- s->next = r;
227
+ s->next = r;
231
- //rは*pであるから,(s->nextに*p(これはポインタ)を代入する。
228
+
232
- //s->nextは*pを指すようにする
229
+
230
+
231
+
232
+
233
+
234
+
235
+
236
+
237
+
238
+
239
+
233
240
 
234
241
  return;
235
242
  } else { //if ((&((*p)->next)) != q && (&((*q)->next) != p)) の時だと思う
@@ -239,6 +246,12 @@
239
246
  s->next->before = r;
240
247
  // (s->next)->before=*p
241
248
 
249
+ if (r->next != 0)
250
+ // (*p)->nextが0でないとき
251
+
252
+ r->next->before = s;
253
+ // (r->next)->before=*q
254
+
242
255
  t = s->before;
243
256
  // s->before==(*q)->before
244
257
  // t=(*q)->before
@@ -246,12 +259,6 @@
246
259
  s->before = r->before;
247
260
  // s->beforeにr->before==(*p)->before(これはポインタ)を代入する。
248
261
 
249
- if (r->next != 0)
250
- // (*p)->nextが0でないとき
251
-
252
- r->next->before = s;
253
- // (r->next)->before=*q
254
-
255
262
  r->before = t;
256
263
  // r->before==(*p)->before
257
264
  // t=s->before
@@ -274,92 +281,114 @@
274
281
  }
275
282
  }
276
283
 
277
- void data_sort(struct address **head) {
284
+ void data_sort(struct address **head)
285
+ {
278
- struct address **p;
286
+ struct address **p;
287
+
279
- if (*head != 0) {
288
+ if (*head != 0) {
280
- for (;;) {
289
+ for (;;) {
281
- p = listmin(head);
290
+ p = listmin(head);
282
- //関数listmin(head)は、名前からリストの全ての要素をチェックして、
291
+ //関数listmin(head)は、名前からリストの全ての要素をチェックして、
283
- //いちばん小さいnameを持つ要素を返していると思われます。
292
+ //いちばん小さいnameを持つ要素を返していると思われます。
284
- //そうでないと正しくソートされません。
293
+ //そうでないと正しくソートされません。
285
294
 
286
- if (p == 0)break;
295
+ if (p == 0)break;
287
- //リストが1つ場合、ソートが完了したとして、ループを抜けます。
296
+ //リストの先頭空のとき、返値が0になる、ソートが完了したとして、
288
-
297
+ //ループを抜けます。」ですね.
298
+
299
+ //次のように使うことが出来る。
300
+
301
+ // char *p = NULL;
302
+
303
+ // if (!p) { … /* if (p==0) と等価 */
304
+
305
+ //世の中には様々なマイクロプロセッサーがあり、
306
+ //現実にNULLポインターの内部表現が「0番地」では無いものも存在する。
307
+
308
+ //しかしこの場合でも、ソースコード中の値は0のままで良い。
309
+ //なぜなら、NULLポインターというものは抽象的な概念であり、
310
+ //物理的なアドレスを指しているわけではないからである。
311
+
312
+ //もし内部表現が0でない計算機の場合、必要に応じてCコンパイラーは
313
+ //その値に自動的に変換してくれる。
314
+ //従って、NULLポインターと0は完全に等価であり、
315
+ //可換であるとして扱うことが出来るのである。
316
+
289
- exchange(head, p);
317
+ exchange(head, p);
290
- //大小を入れ替える
318
+ //大小を入れ替える
291
319
 
292
- head = &((*head)->next);
320
+ head = &((*head)->next);
293
- //見つけたいちばん小さい要素を関数exchange(head, p)で先頭に移動しています。
321
+ //見つけたいちばん小さい要素を関数exchange(head, p)で先頭に移動しています。
294
- }
322
+ }
295
- }
323
+ }
296
324
  }
297
325
 
298
- void release(struct address **head) {
326
+ void release(struct address **head)
327
+ {
299
- if (*head != 0) {
328
+ if (*head != 0) {
300
- release( &((*head)->next) );
329
+ release( &((*head)->next) );
301
- free(*head);
330
+ free(*head);
302
- *head = 0;
331
+ *head = 0;
303
- }
332
+ }
304
333
  }
305
334
 
306
- int main() {
335
+ int main()
336
+ {
307
- struct address *head;
337
+ struct address *head;
308
- FILE* fp;
338
+ FILE* fp;
309
- static char buff[N], name[N], address[N], tel[N], mail[N];
339
+ static char buff[N], name[N], address[N], tel[N], mail[N];
310
- char *token=",";
340
+ char *token=",";
311
341
 
312
- head = 0;
342
+ head = 0;
313
343
 
314
- if ((fp = fopen(FILENAME,"r")) != 0) {
344
+ if ((fp = fopen(FILENAME,"r")) != 0) {
315
- while(fgets(buff, N, fp) != 0){
345
+ while(fgets(buff, N, fp) != 0){
316
- //本当の大元の文字列を書き換えないようにするために
346
+ //本当の大元の文字列を書き換えないようにするために
317
- //bufを確保してコピーし、それをstrtok()の引数にしている。
347
+ //bufを確保してコピーし、それをstrtok()の引数にしている。
318
- char *p;
348
+ char *p;
319
- chop(buff);
349
+ chop(buff);
320
- printf( "ファイルから読んだ文字列:%s\n", buff );
350
+ printf( "ファイルから読んだ文字列:%s\n", buff );
321
351
 
322
- p = strtok(buff, token);
352
+ p = strtok(buff, token);
323
- if ( p != NULL ) {
353
+ if ( p != NULL ) {
324
- strcpy(name, p);
354
+ strcpy(name, p);
325
- } else {
355
+ } else {
326
- printf( "氏名の切り出しに失敗しました。\n");
356
+ printf( "氏名の切り出しに失敗しました。\n");
327
- break;
357
+ break;
328
- }
358
+ }
359
+ p = strtok(NULL, token);
329
360
 
361
+ if ( p != NULL ) {
362
+ strcpy(address, p);
363
+ } else {
364
+ printf( "住所の切り出しに失敗しました。\n");
365
+ break;
366
+ }
330
- p = strtok(NULL, token);
367
+ p = strtok(NULL, token);
331
- if ( p != NULL ) {
332
- strcpy(address, p);
333
- } else {
334
- printf( "住所の切り出しに失敗しました。\n");
335
- break;
336
- }
337
368
 
369
+ if ( p != NULL ) {
370
+ strcpy(tel, p);
371
+ } else {
372
+ printf( "電話番号の切り出しに失敗しました。\n");
373
+ break;
374
+ }
338
- p = strtok(NULL, token);
375
+ p = strtok(NULL, token);
339
- if ( p != NULL ) {
340
- strcpy(tel, p);
341
- } else {
342
- printf( "電話番号の切り出しに失敗しました。\n");
343
- break;
344
- }
345
376
 
346
- p = strtok(NULL, token);
347
- if ( p != NULL ) {
377
+ if ( p != NULL ) {
348
- strcpy(mail, p);
378
+ strcpy(mail, p);
349
- } else {
379
+ } else {
350
- printf( "メールアドレスの切り出しに失敗しました。\n");
380
+ printf( "メールアドレスの切り出しに失敗しました。\n");
351
- break;
381
+ break;
352
- }
382
+ }
353
- list_add(&head, name, address, tel, mail);
383
+ list_add(&head, name, address, tel, mail);
354
- }
384
+ }
355
- fclose(fp);
385
+ fclose(fp);
356
- }
386
+ }
357
- data_sort(&head);
387
+ data_sort(&head);
358
- data_show(head);
388
+ data_show(head);
359
389
 
360
-
361
- release(&head);
390
+ release(&head);
362
- return 0;
391
+ return 0;
363
392
  }
364
393
 
365
394
  /* 実行結果
@@ -392,6 +421,36 @@
392
421
  $
393
422
  */
394
423
 
424
+ /* 実行結果
425
+ naka@naka ~
426
+ $ cd kadai/kadai9-8
395
427
 
428
+ naka@naka ~/kadai/kadai9-8
429
+ $ gcc -o kad9-8b kad9-8b.c -Wall
396
430
 
431
+ naka@naka ~/kadai/kadai9-8
432
+ $ kad9-8b
433
+ ファイルから読んだ文字列:yamada,tone,090-1122,mail-9
434
+ ファイルから読んだ文字列:hosi,nagoya,5436,mail-7
435
+ ファイルから読んだ文字列:kato,kanagawa,080-8888,mail-2
436
+ ファイルから読んだ文字列:koko,yosida,090-2314,mail-6
437
+ ファイルから読んだ文字列:naka,kamikosaka,080-4444,mail-1
438
+ ファイルから読んだ文字列:nakada,nogata,090-6376,mail-8
439
+ ファイルから読んだ文字列:saito,yamanashi,080-6666,mail-3
440
+ ファイルから読んだ文字列:suzuki,saitama,090-2222,mail-5
441
+ hosi, nagoya, 5436, mail-7
442
+ kato, kanagawa, 080-8888, mail-2
443
+ koko, yosida, 090-2314, mail-6
444
+ naka, kamikosaka, 080-4444, mail-1
445
+ nakada, nogata, 090-6376, mail-8
446
+ saito, yamanashi, 080-6666, mail-3
447
+ suzuki, saitama, 090-2222, mail-5
448
+ yamada, tone, 090-1122, mail-9
449
+
450
+ naka@naka ~/kadai/kadai9-8
451
+ $
452
+ */
453
+
454
+
455
+
397
456
  ```

3

コードの修正

2018/01/30 06:04

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -23,9 +23,28 @@
23
23
  よろしくお願いいたします。
24
24
 
25
25
  ```ここに言語を入力
26
- コード
26
+ //codepad.org/B83f1FSq
27
- // 電話帳プログラムの一部
27
+ //正常動作(リスト構造)
28
28
 
29
+ //codepad.org/B83f1FSq
30
+ //正常動作(リスト構造)
31
+
32
+ #include <stdio.h>
33
+ #include <stdlib.h>
34
+ #include <string.h>
35
+ #include <assert.h> //
36
+
37
+ //assert.hでは、assertマクロが定義されています。
38
+
39
+ //assertマクロは関数形式マクロで、引数に偽(すなわち0)が指定されると、
40
+ //ソースファイル名や行番号等の情報を標準エラー出力に出力し、
41
+ //プログラムを終了させます。
42
+ //プログラマは、assertマクロが出力する情報をもとにデバッグを行います。
43
+
44
+ //NDEBUGマクロが定義されていると、assertマクロは、次のように定義され、
45
+ //何もしません。
46
+ //#define assert(ignore) ((void)0)
47
+
29
48
  #define N 256
30
49
  #define FILENAME "address.csv"
31
50
 
@@ -37,124 +56,342 @@
37
56
  struct address *next;
38
57
  struct address *before;
39
58
  };
59
+
60
+ void data_show(struct address* head);
61
+ void data_add(struct address** head);
62
+ void data_delete(struct address** head);
63
+ void data_sort(struct address** head);
64
+ void data_write(struct address* head);
40
65
 
41
- //(*head)->nameと(*head)->next)のnameとを比べて
42
- //小さいほうのポインタのポインタを返却値にしている。
66
+ void data_amend(struct address* head);
43
- struct address **listmin(struct address **head)
67
+ void data_search(struct address* head);
68
+
69
+ void chop(char *p){
70
+ for (; *p; p++)
71
+ ;
72
+
73
+ //まず、char *p に対して、for(s = p; *p; p++) に現れる、
74
+ //*p の型は(ポインタではなく)char そのものです。
75
+ //ですから、*p は、「p がポイントしているところにある char のデータ」です。
76
+
77
+ //一方、Cでは、文字列は、「'\0' で終端される」という規定になっています。
78
+ //ですから、ちょっとくどく書けば、
79
+ //for(s = p; *p != '\0' ; p++)ということで,
80
+ //「p がポイントする文字が、終端文字(文字列の終わり)にくるまで」
81
+ //という意味です。
82
+
83
+ //そして、(Cのいろいろな背景から) *p != '\0' という表記は、
84
+ //*p とだけ書いた時と同じ動作をします。
85
+ //このため、文字列の終端をチェックするために、while(*p) とか、
86
+ //if(! *p) こっちは、終端にきたときの判断)とかよく使われる表現です。
87
+
88
+ //なお、NULL は、「何もポイントしていないポインタ」の値です。
89
+ //そして、ちょっと面倒なのが、規格上は、
90
+ //「ヌルポインタ(何もポイントしていないポインタ)の値は、
91
+ //定数0と比較したときに等しくなる」と定義されている点です。
92
+
93
+ p--; // *pが\0となりfor()を抜けるとここに来る。
94
+ //ポインタを1個戻して,\0 の前が'\r'か'\n'どうか調べるため。
95
+
96
+ while (*p == '\r' || *p == '\n')
97
+ *(p--) = 0;
98
+ //
99
+ }//chop()を抜けると\0で区切られた文字列になる。
100
+
101
+ void list_add(struct address **head, char *name, char *address, char *tel, char *mail)
44
102
  {
103
+ struct address *p;
104
+ if ((p = malloc(sizeof(struct address))) != 0) {
105
+
106
+ strcpy(p->name, name);
107
+ //文字列のコピー
108
+ //【書式】
109
+ //#include <string.h>
110
+ //char *strcpy(char *s1, const char *s2);
111
+
112
+ //【説明】
113
+ //文字型配列 *s1 に文字列 *s2 を '\0' までコピーします。
114
+ //'\0' もコピーするので s1 はその分も考えて大きさを宣言して
115
+ //おかなければなりません。
116
+ //もし、s1 と s2 が重なっている場合には動作は未定義となります。
117
+
118
+ strcpy(p->address, address);
119
+ //文字型配列 p->address に文字列 address を '\0' までコピーします。
120
+
121
+ strcpy(p->tel, tel);
122
+ //文字型配列 p->number に文字列 number を '\0' までコピーします。
123
+
124
+ strcpy(p->mail, mail);
125
+ //文字型配列 p->mail に文字列 mail を '\0' までコピーします。
126
+
127
+ p->next = *head;
128
+ if (p->next != 0)
129
+ p->next->before = p;
130
+ p->before = 0;
131
+ *head = p;
132
+ }
133
+ }
134
+
135
+
136
+ void data_show(struct address *head) {
137
+ if (head != 0) {
138
+ printf(" %s, %s, %s, %s\n", head->name, head->address, head->tel, head->mail);
139
+ data_show(head->next);
140
+ }
141
+ }
142
+
143
+ //関数listmin(head)は、名前からリストの全ての要素をチェックして、
144
+ //いちばん小さいnameを持つ要素を返していると思われます。
145
+ //そうでないと正しくソートされません。
146
+ struct address **listmin(struct address **head) {
45
147
  struct address **p;
148
+
46
149
  if (*head == 0)
47
150
  return 0;
48
151
  if ((*head)->next == 0)
49
152
  return head;
153
+ //リストが残り1つの場合、ソートが完了したとして、ループを抜けます。
154
+
50
155
  if (strcmp((*head)->name, (*(p = listmin(&((*head)->next))))->name) < 0)
51
- // #include <string.h>
52
- // int strcmp( const char *str1 , const char *str2 );
53
- // str1<str2ならば負の値を返す。
54
156
  return head;
55
157
  else
56
158
  return p;
57
159
  }
58
160
 
161
+ //大小を入れ替える
59
162
  void exchange(struct address **p, struct address **q)
60
163
  {
61
- struct address *r, *s, *t;
164
+ struct address *r, *s, *t;
62
- assert(*p != 0 && *q != 0);
165
+ assert(*p != 0 && *q != 0);
63
-
166
+ //assertマクロは関数形式マクロで、引数に偽(すなわち0)が指定されると、
167
+ //ソースファイル名や行番号等の情報を標準エラー出力に出力し、プログラムを終了させます。
64
- if (p == q)
168
+ if (p == q)
65
- return;
169
+ return;
170
+
171
+ r = *p; s = *q;
172
+ if (&((*p)->next) == q || &((*q)->next) == p) {
173
+ // &((*p)->next) == q において、**pはaddress構造体型ですから、
174
+ //*pはaddress構造体へのポインタです。
175
+
176
+ //従って、(*p)もaddress構造体へのポインタです。
177
+
178
+ //であれば、(*p)->nextはaddress構造体のnextメンバですね。
179
+
180
+ //ならば、&((*p)->next)はそのアドレスですから、nextメンバのアドレスとなります。
181
+
182
+ //それと q が等しいという条件ですから、qはadress構造体のnextメンバを
183
+ //ポイントしているのだろうと思います。
184
+
185
+ //つまり、*pが指すaddress構造体のnextメンバを
186
+ //qがポイントしているならば、この条件が成立します。
187
+
188
+
189
+ //&((*q)->next) == pにおいて、**qはaddress構造体型ですから、
190
+ //*qはaddress構造体へのポインタです。
191
+
192
+ //従って、(*q)もaddress構造体へのポインタです。
193
+
194
+ //であれば、(*q)->nextはaddress構造体のnextメンバですね。
195
+
196
+ //ならば、&((*q)->next)はそのアドレスですから、
197
+ //nextメンバのアドレスとなります。
198
+
199
+ //それと p が等しいという条件ですから、pはadress構造体のnextメンバを
200
+ //ポイントしているのだろうと思います。
201
+
202
+ //つまり、*qが指すaddress構造体のnextメンバを
203
+ //pがポイントしているならば、この条件が成立します。
204
+
205
+ if (s->next != 0){
206
+ // sと*qはおなじである。s->nextは(*q)->nextであるから
207
+ // (*q)->nextが0でないとき
208
+
209
+ s->next->before = r;
210
+ //「sの次が存在するなら、そいつの手前をrにする」と読める。
211
+ //つまり" r ← sの次 " ってゆー上り方向のリンクを張り替えたってこと。
212
+ }
213
+
214
+ r->before = s;
215
+ //「sの次が存在しないなら、r の手前をsにする」と読める。
216
+ //つまり" s ← (r->before ) " ってゆー上り方向のリンクを張りかえたってこと。
66
217
 
67
- r = *p; s = *q;
68
- if (&((*p)->next) == q || &((*q)->next) == p) {
69
- // (*p)はポインタで,(*p)->nextも次のポインタである。
218
+ s->before = r->before;
70
- // q(ポインタポインタ)と(*p)->nextを比較するには&((*p)->next)とする。
219
+ //「s次が存在しないなら(s->next == NULL)、s->before をr->beforeにする」と読める
220
+ //つまり" r->before ← s->before " ってゆー上り方向のリンクを張り替えたってこと。
71
221
 
72
-   if (s->next != 0){
73
-    s->next->before = r;
74
-   //「sの次が存在するなら、そいつの手前をrにする」と読める。
75
-          //つまり" r ← sの次 " ってゆー上り方向のリンクを張り替えたってこと。
76
-       }
77
-   r->before = s;
222
+ *p = s;
78
-   //rは*pであるから,*p->before = sである。s==*qなので
79
-   //*p->before*q(これはポインタ)を代入する。
223
+ //*pにs(これはポインタ*q)を代入する。
224
+ //*pをsすなわち*qをさすようにする。
80
225
 
81
-   s->before = r->before;
226
+ *q = s->next;
82
-   // s->beforeに*q(これはポインタ)を代入する。
227
+ //s->nextはNULLであるから*qにNULLを代入する。
228
+ //*qはどこもさしていない
83
229
 
230
+ s->next = r;
231
+ //rは*pであるから,(s->nextに*p(これはポインタ)を代入する。
232
+ //s->nextは*pを指すようにする
233
+
234
+ return;
235
+ } else { //if ((&((*p)->next)) != q && (&((*q)->next) != p)) の時だと思う
236
+ if (s->next != 0)
237
+ // (*q)->nextが0でないとき
238
+
239
+ s->next->before = r;
240
+ // (s->next)->before=*p
241
+
242
+ t = s->before;
243
+ // s->before==(*q)->before
244
+ // t=(*q)->before
245
+
246
+ s->before = r->before;
247
+ // s->beforeにr->before==(*p)->before(これはポインタ)を代入する。
248
+
249
+ if (r->next != 0)
250
+ // (*p)->nextが0でないとき
251
+
252
+ r->next->before = s;
253
+ // (r->next)->before=*q
254
+
255
+ r->before = t;
256
+ // r->before==(*p)->before
257
+ // t=s->before
258
+ // r->beforeにs->before==(*q)->before(これはポインタ)を代入する。
259
+
260
+ t = r->next;
261
+ // r->next==(*p)->nextが0でないときであるから
262
+ // t=(*p)->next
263
+
264
+ r->next = s->next;
265
+ // s->next==(*q)->next
266
+ // r->next =(*q)->next
267
+
268
+ s->next = t;
269
+ // t=(*p)->next
270
+ // s->next=(*p)->next
271
+
84
-   *p = s;
272
+ *p = s;
85
-   //sは*qだから*pに*q(これはポインタ)を代入する。
273
+ *q = r;
274
+ }
275
+ }
86
276
 
277
+ void data_sort(struct address **head) {
278
+ struct address **p;
279
+ if (*head != 0) {
280
+ for (;;) {
87
-   *q = s->next;
281
+ p = listmin(head);
282
+ //関数listmin(head)は、名前からリストの全ての要素をチェックして、
283
+ //いちばん小さいnameを持つ要素を返していると思われます。
284
+ //そうでないと正しくソートされません。
285
+
286
+ if (p == 0)break;
287
+ //リストが残り1つの場合、ソートが完了したとして、ループを抜けます。
288
+
289
+ exchange(head, p);
290
+ //大小を入れ替える
291
+
292
+ head = &((*head)->next);
88
-   //s->nextは(*q)->nextあるから*q(*q)->next(これはポインタ)を代入
293
+ //見つけたいちばん小さい要素を関数exchange(head, p)で先頭移動しています。
294
+ }
295
+ }
296
+ }
89
297
 
298
+ void release(struct address **head) {
299
+ if (*head != 0) {
300
+ release( &((*head)->next) );
301
+ free(*head);
90
-   s->next = r;
302
+ *head = 0;
91
-   //rは*pであるから,(*q)->nextに*p(これはポインタ)を代入する。
303
+ }
304
+ }
92
305
 
306
+ int main() {
307
+ struct address *head;
308
+ FILE* fp;
309
+ static char buff[N], name[N], address[N], tel[N], mail[N];
310
+ char *token=",";
311
+
93
-   return;
312
+ head = 0;
313
+
314
+ if ((fp = fopen(FILENAME,"r")) != 0) {
315
+ while(fgets(buff, N, fp) != 0){
316
+ //本当の大元の文字列を書き換えないようにするために
317
+ //bufを確保してコピーし、それをstrtok()の引数にしている。
318
+ char *p;
319
+ chop(buff);
320
+ printf( "ファイルから読んだ文字列:%s\n", buff );
321
+
322
+ p = strtok(buff, token);
323
+ if ( p != NULL ) {
324
+ strcpy(name, p);
94
- } else {
325
+ } else {
326
+ printf( "氏名の切り出しに失敗しました。\n");
327
+ break;
328
+ }
329
+
330
+ p = strtok(NULL, token);
95
-    if (s->next != 0){
331
+ if ( p != NULL ) {
332
+ strcpy(address, p);
333
+ } else {
96
-    // (*q)->nextが0でないとき
334
+ printf( "住所の切り出しに失敗しました。\n");
335
+ break;
336
+ }
337
+
338
+ p = strtok(NULL, token);
339
+ if ( p != NULL ) {
340
+ strcpy(tel, p);
341
+ } else {
342
+ printf( "電話番号の切り出しに失敗しました。\n");
343
+ break;
344
+ }
345
+
346
+ p = strtok(NULL, token);
347
+ if ( p != NULL ) {
348
+ strcpy(mail, p);
349
+ } else {
350
+ printf( "メールアドレスの切り出しに失敗しました。\n");
351
+ break;
352
+ }
353
+ list_add(&head, name, address, tel, mail);
354
+ }
355
+ fclose(fp);
356
+ }
357
+ data_sort(&head);
358
+ data_show(head);
359
+
360
+
361
+ release(&head);
362
+ return 0;
363
+ }
97
364
 
98
- s->next->before = r;
365
+ /* 実行結果
99
- // (s->next)->before=*p
366
+ naka@naka ~
100
-   }
101
-    t = s->before;
367
+ $ cd kadai/kadai9-8
102
-    // s->before==(*q)->before
103
-    // t=(*q)->before
104
368
 
369
+ naka@naka ~/kadai/kadai9-8
105
-    s->before = r->before;
370
+ $ gcc -o kad9-8b kad9-8b.c -Wall
106
-    // s->beforeにr->before==(*p)->before(これはポインタ)を代入する。
107
371
 
108
-    if (r->next != 0){
109
-    // (*p)->nextが0でないとき
372
+ naka@naka ~/kadai/kadai9-8
373
+ $ kad9-8b
374
+ ファイルから読んだ文字列:yamada,tone,090-1122,mail-9
375
+ ファイルから読んだ文字列:hosi,nagoya,5436,mail-7
376
+ ファイルから読んだ文字列:kato,kanagawa,080-8888,mail-2
377
+ ファイルから読んだ文字列:koko,yosida,090-2314,mail-6
378
+ ファイルから読んだ文字列:naka,kamikosaka,080-4444,mail-1
379
+ ファイルから読んだ文字列:nakada,nogata,090-6376,mail-8
380
+ ファイルから読んだ文字列:saito,yamanashi,080-6666,mail-3
381
+ ファイルから読んだ文字列:suzuki,saitama,090-2222,mail-5
382
+ hosi, nagoya, 5436, mail-7
383
+ kato, kanagawa, 080-8888, mail-2
384
+ koko, yosida, 090-2314, mail-6
385
+ naka, kamikosaka, 080-4444, mail-1
386
+ nakada, nogata, 090-6376, mail-8
387
+ saito, yamanashi, 080-6666, mail-3
388
+ suzuki, saitama, 090-2222, mail-5
389
+ yamada, tone, 090-1122, mail-9
110
390
 
111
- r->next->before = s;
112
- // (r->next)->before=*q
391
+ naka@naka ~/kadai/kadai9-8
113
-   }
392
+ $
114
-    r->before = t;
393
+ */
115
394
 
116
-    t = r->next;
117
395
 
118
-    r->next = s->next;
119
396
 
120
-    s->next = t;
121
-
122
-    *p = s;
123
-    *q = r;
124
- }
125
- }
126
-
127
- void data_sort(struct address **head)
128
- {
129
- struct address **p;
130
- if (*head != 0) {
131
- for (;;) {
132
- p = listmin(head);
133
- //(*head)->nameと(*head)->next)のnameとを比べて
134
- //小さいほうのポインタのポインタを返却値にしている。
135
- //帰ってきたhead(小さいほうのポインタのポインタ),または
136
- //p(小さいほうのポインタのポインタ)
137
-
138
- if (p == 0)
139
- break;
140
-
141
- exchange(head, p);
142
- //大小を入れ替える
143
-
144
- head = &((*head)->next);
145
- }
146
- }
147
- }
148
-
149
- データ
150
- address.csv
151
- yamada,tone,090-1122,mail-9
152
- hosi,nagoya,5436,mail-7
153
- kato,kanagawa,080-8888,mail-2
154
- koko,yosida,090-2314,mail-6
155
- naka,kamikosaka,080-4444,mail-1
156
- nakada,nogata,090-6376,mail-8
157
- saito,yamanashi,080-6666,mail-3
158
- suzuki,saitama,090-2222,mail-5
159
-
160
397
  ```

2

関数の追加

2018/01/28 07:56

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -38,6 +38,23 @@
38
38
  struct address *before;
39
39
  };
40
40
 
41
+ //(*head)->nameと(*head)->next)のnameとを比べて
42
+ //小さいほうのポインタのポインタを返却値にしている。
43
+ struct address **listmin(struct address **head)
44
+ {
45
+ struct address **p;
46
+ if (*head == 0)
47
+ return 0;
48
+ if ((*head)->next == 0)
49
+ return head;
50
+ if (strcmp((*head)->name, (*(p = listmin(&((*head)->next))))->name) < 0)
51
+ // #include <string.h>
52
+ // int strcmp( const char *str1 , const char *str2 );
53
+ // str1<str2ならば負の値を返す。
54
+ return head;
55
+ else
56
+ return p;
57
+ }
41
58
 
42
59
  void exchange(struct address **p, struct address **q)
43
60
  {

1

再投稿

2018/01/28 04:47

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -1,5 +1,3 @@
1
- ```ここに言語を入力
2
- コード
3
1
  リストの構造体のデータをソートしているコードがあるんですが、その中の
4
2
  exchange()関数のところを図を使って書こうと思ったのですが、うまくいきません。
5
3
  その前に書かれているコードの正確な理解が出来ていないと思います。
@@ -22,11 +20,10 @@
22
20
  if (s->next != 0){}から下のコード(r->before = s;から)を
23
21
 
24
22
  どなたか詳しく、やさしい説明をしてもらえませんか。
25
-
26
-
27
-
28
23
  よろしくお願いいたします。
29
24
 
25
+ ```ここに言語を入力
26
+ コード
30
27
  // 電話帳プログラムの一部
31
28
 
32
29
  #define N 256