回答編集履歴

6

add_book() を改善

2021/06/11 08:58

投稿

rubato6809
rubato6809

スコア1382

test CHANGED
@@ -402,46 +402,44 @@
402
402
 
403
403
 
404
404
 
405
- TPBook * add_book(char *name, char *number, TPBook *head)
405
+ TPBook * add_book(char *name, char *number, TPBook *head) // 修正版
406
-
406
+
407
- {
407
+ {
408
+
409
+ // 追加する構造体メモリを獲得
410
+
411
+ TPBook * tp = malloc(sizeof(TPBook));
412
+
413
+
414
+
415
+ // メンバを初期化する
416
+
417
+ tp->next = NULL;
418
+
419
+ strcpy(tp->name, name);
420
+
421
+ strcpy(tp->number, number);
422
+
423
+
424
+
425
+ if (head == NULL) // 一回目は tp 自身が先頭になる
426
+
427
+ return tp;
428
+
429
+
408
430
 
409
431
  TPBook *p = head;
410
432
 
411
433
 
412
434
 
413
- while (p && p->next) {
435
+ while (p->next)
414
436
 
415
437
  p = p->next;
416
438
 
417
- }
439
+
418
440
 
419
441
  // この時点で p はリストの最後を指している
420
442
 
421
-
422
-
423
- // 追加する構造体メモリを獲得
424
-
425
- TPBook *tp = malloc(sizeof(TPBook));
426
-
427
-
428
-
429
- // メンバを初期化する
430
-
431
- tp->next = NULL;
432
-
433
- strcpy(tp->name, name);
434
-
435
- strcpy(tp->number, number);
436
-
437
-
438
-
439
- if (p == NULL) // 一回目は tp 自身が先頭になる
440
-
441
- return tp;
442
-
443
-
444
-
445
443
  // 今作った構造体 tp をリストの最後に追加する。
446
444
 
447
445
  p->next = tp; // 新しい構造体をリストの最後に

5

完全版を追加

2021/06/11 08:58

投稿

rubato6809
rubato6809

スコア1382

test CHANGED
@@ -207,3 +207,281 @@
207
207
  }
208
208
 
209
209
  ```
210
+
211
+ ---
212
+
213
+ サービス。私の手元で動作確認した完全版。
214
+
215
+ ```C
216
+
217
+ #include <stdio.h>
218
+
219
+ #include <string.h>
220
+
221
+ #include <stdlib.h>
222
+
223
+ #include <ctype.h>
224
+
225
+
226
+
227
+ typedef struct TelephoneBook {
228
+
229
+ char name[16];
230
+
231
+ char number[16];
232
+
233
+ struct TelephoneBook *next;
234
+
235
+ } TPBook;
236
+
237
+
238
+
239
+ TPBook * add_book(char *name, char *num, TPBook *head);
240
+
241
+ void print_book(TPBook *p);
242
+
243
+ void free_book(TPBook *p);
244
+
245
+ int check_name(char *name);
246
+
247
+ int check_number(char *number);
248
+
249
+
250
+
251
+ int main(void)
252
+
253
+ {
254
+
255
+ TPBook *head = NULL;
256
+
257
+ char name_number[33];
258
+
259
+ char name[16]; // 入力した名前を格納する
260
+
261
+ char number[16]; // 入力した電話番号を格納する
262
+
263
+ int check_na; // 仕様通りに入力されてなければ1,\qが入力されていれば2が代入される
264
+
265
+ int check_nu; // 仕様通りに入力されてなければ1が代入される
266
+
267
+
268
+
269
+ while (1) {
270
+
271
+ printf("input>");
272
+
273
+ fgets(name_number, sizeof(name_number), stdin);
274
+
275
+ sscanf(name_number, "%s %s", name, number);
276
+
277
+ check_na = check_name(name);
278
+
279
+
280
+
281
+ if (check_na == 2) {
282
+
283
+ print_book(head);
284
+
285
+ free_book(head);
286
+
287
+ return EXIT_SUCCESS;
288
+
289
+ }
290
+
291
+ if (check_na == 1) {
292
+
293
+ printf("error");
294
+
295
+ return EXIT_FAILURE;
296
+
297
+ }
298
+
299
+ check_nu = check_number(number);
300
+
301
+ if (check_nu == 1) {
302
+
303
+ printf("error");
304
+
305
+ return EXIT_FAILURE;
306
+
307
+ }
308
+
309
+ if (check_na == 0 && check_nu == 0) {
310
+
311
+ printf("Ok\n");
312
+
313
+ }
314
+
315
+ head = add_book(name, number, head);
316
+
317
+ print_book(head); // show result
318
+
319
+ }
320
+
321
+ }
322
+
323
+
324
+
325
+ int check_name(char *name)
326
+
327
+ {
328
+
329
+ char *chr1 = "\q";
330
+
331
+ char *chr2 = "\Q";
332
+
333
+
334
+
335
+ if (strcmp(name, chr1) == 0 || strcmp(name, chr2) == 0)
336
+
337
+ return 2;
338
+
339
+
340
+
341
+ int len = strlen(name);
342
+
343
+ if (!isupper(name[0])) // 先頭は英大文字であるべし
344
+
345
+ return 1;
346
+
347
+
348
+
349
+ for (int i = 1; i < len; i++) {
350
+
351
+ if (!islower(name[i])) // 残りは英小文字であるべし
352
+
353
+ return 1;
354
+
355
+ }
356
+
357
+ return 0; // ok
358
+
359
+ }
360
+
361
+
362
+
363
+ int check_number(char *number)
364
+
365
+ {
366
+
367
+ /* format: 090-1234-5678 */
368
+
369
+ for (int i = 0; i <= 2; i++) { // 0, 1, 2 が
370
+
371
+ if (!isdigit(number[i])) // 数字でないなら
372
+
373
+ return 1;
374
+
375
+ }
376
+
377
+ for (int i = 4; i <= 7; i++) { // 4, 5, 6, 7 が
378
+
379
+ if (!isdigit(number[i])) // 数字でないなら
380
+
381
+ return 1;
382
+
383
+ }
384
+
385
+ for (int i = 9; i <= 12; i++) { // 9, 10, 11, 12 が
386
+
387
+ if (!isdigit(number[i])) // 数字でないなら
388
+
389
+ return 1;
390
+
391
+ }
392
+
393
+ if (number[3] != '-' || number[8] != '-') {
394
+
395
+ return 1;
396
+
397
+ }
398
+
399
+ return 0; // ok
400
+
401
+ }
402
+
403
+
404
+
405
+ TPBook * add_book(char *name, char *number, TPBook *head)
406
+
407
+ {
408
+
409
+ TPBook *p = head;
410
+
411
+
412
+
413
+ while (p && p->next) {
414
+
415
+ p = p->next;
416
+
417
+ }
418
+
419
+ // この時点で p はリストの最後を指している
420
+
421
+
422
+
423
+ // 追加する構造体メモリを獲得
424
+
425
+ TPBook *tp = malloc(sizeof(TPBook));
426
+
427
+
428
+
429
+ // メンバを初期化する
430
+
431
+ tp->next = NULL;
432
+
433
+ strcpy(tp->name, name);
434
+
435
+ strcpy(tp->number, number);
436
+
437
+
438
+
439
+ if (p == NULL) // 一回目は tp 自身が先頭になる
440
+
441
+ return tp;
442
+
443
+
444
+
445
+ // 今作った構造体 tp をリストの最後に追加する。
446
+
447
+ p->next = tp; // 新しい構造体をリストの最後に
448
+
449
+ return head; // 二回目以降は head そのまま
450
+
451
+ }
452
+
453
+
454
+
455
+ void print_book(TPBook *p)
456
+
457
+ {
458
+
459
+ while (p) {
460
+
461
+ printf("%s : %s\n", p->name, p->number);
462
+
463
+ p = p->next;
464
+
465
+ }
466
+
467
+ }
468
+
469
+
470
+
471
+ void free_book(TPBook *p)
472
+
473
+ {
474
+
475
+ while (p) { /* 次ポインタがNULLまで処理 */
476
+
477
+ TPBook *p2 = p->next;
478
+
479
+ free(p);
480
+
481
+ p = p2;
482
+
483
+ }
484
+
485
+ }
486
+
487
+ ```

4

for 文のバグを修正

2021/06/10 13:31

投稿

rubato6809
rubato6809

スコア1382

test CHANGED
@@ -118,6 +118,12 @@
118
118
 
119
119
  それに、いちいちローカルな配列にコピーしなくても、そのまま判定できますよ。
120
120
 
121
+ for (int i = 1; i <= len; i++) { これはバグ
122
+
123
+ for (int i = 1; i < len; i++) {  これが正しい
124
+
125
+
126
+
121
127
  ```C
122
128
 
123
129
  #include <ctype.h>
@@ -146,7 +152,7 @@
146
152
 
147
153
 
148
154
 
149
- for (int i = 1; i <= len; i++) {
155
+ for (int i = 1; i < len; i++) { // !!条件を修正した!!
150
156
 
151
157
  if (!islower(name[i])) // 残りは英小文字であるべし
152
158
 

3

main() にも #ifdef ORG を

2021/06/10 12:50

投稿

rubato6809
rubato6809

スコア1382

test CHANGED
@@ -96,9 +96,17 @@
96
96
 
97
97
  {
98
98
 
99
+ #ifdef ORG
100
+
101
+ struct TelephoneBook *head = NULL;
102
+
103
+ #else
104
+
99
- struct TelephoneBook dummy = { "Dummy", "000-0000-0000", NULL };
105
+ struct TelephoneBook dummy = { "Dummy", "000-0000-0000", NULL };
100
-
106
+
101
- struct TelephoneBook *head = &dummy; // ダミーエントリをポイントして開始
107
+ struct TelephoneBook *head = &dummy; // ダミーエントリをポイントして開始
108
+
109
+ #endif
102
110
 
103
111
  ```
104
112
 

2

main() の修正を追加

2021/06/10 12:45

投稿

rubato6809
rubato6809

スコア1382

test CHANGED
@@ -83,6 +83,22 @@
83
83
  return head;
84
84
 
85
85
  }
86
+
87
+ ```
88
+
89
+
90
+
91
+ 質問者のコードは head = NULL; でスタートしており、それだとORGコードが動作するが、私のコードではSegmentation Fault を起こし動作しない。そこで例えば次のようにダミーエントリを作っておく手がある。当座をしのいで動作確認はできるはず。
92
+
93
+ ```C
94
+
95
+ int main(void)
96
+
97
+ {
98
+
99
+ struct TelephoneBook dummy = { "Dummy", "000-0000-0000", NULL };
100
+
101
+ struct TelephoneBook *head = &dummy; // ダミーエントリをポイントして開始
86
102
 
87
103
  ```
88
104
 

1

修正した関数を追加

2021/06/10 12:38

投稿

rubato6809
rubato6809

スコア1382

test CHANGED
@@ -91,3 +91,89 @@
91
91
  P.S.
92
92
 
93
93
  それにしてもヘンな判定をしてますね。リスト操作をしようという段階になって、isdigit(), isupper(), islower() といった標準ライブラリ関数を知らないの?
94
+
95
+ それに、いちいちローカルな配列にコピーしなくても、そのまま判定できますよ。
96
+
97
+ ```C
98
+
99
+ #include <ctype.h>
100
+
101
+ int check_name(char *name)
102
+
103
+ {
104
+
105
+ char *chr1 = "\q";
106
+
107
+ char *chr2 = "\Q";
108
+
109
+
110
+
111
+ if (strcmp(name, chr1) == 0 || strcmp(name, chr2) == 0)
112
+
113
+ return 2;
114
+
115
+
116
+
117
+ int len = strlen(name);
118
+
119
+ if (!isupper(name[0])) // 先頭は英大文字であるべし
120
+
121
+ return 1;
122
+
123
+
124
+
125
+ for (int i = 1; i <= len; i++) {
126
+
127
+ if (!islower(name[i])) // 残りは英小文字であるべし
128
+
129
+ return 1;
130
+
131
+ }
132
+
133
+ return 0; // OK
134
+
135
+ }
136
+
137
+
138
+
139
+ int check_number(char *number)
140
+
141
+ {
142
+
143
+ /* number[] format: 090-1234-5678 */
144
+
145
+ for (int i = 0; i <= 2; i++) { // 0, 1, 2 が
146
+
147
+ if (!isdigit(number[i])) // 数字でないなら
148
+
149
+ return 1;
150
+
151
+ }
152
+
153
+ for (int i = 4; i <= 7; i++) { // 4, 5, 6, 7 が
154
+
155
+ if (!isdigit(number[i])) // 数字でないなら
156
+
157
+ return 1;
158
+
159
+ }
160
+
161
+ for (int i = 9; i <= 12; i++) { // 9, 10, 11, 12 が
162
+
163
+ if (!isdigit(number[i])) // 数字でないなら
164
+
165
+ return 1;
166
+
167
+ }
168
+
169
+ if (number[3] != '-' || number[8] != '-') {
170
+
171
+ return 1;
172
+
173
+ }
174
+
175
+ return 0;
176
+
177
+ }
178
+
179
+ ```