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

回答編集履歴

6

add_book() を改善

2021/06/11 08:58

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -200,26 +200,25 @@
200
200
  return 0; // ok
201
201
  }
202
202
 
203
- TPBook * add_book(char *name, char *number, TPBook *head)
203
+ TPBook * add_book(char *name, char *number, TPBook *head) // 修正版
204
204
  {
205
- TPBook *p = head;
206
-
207
- while (p && p->next) {
208
- p = p->next;
209
- }
210
- // この時点で p はリストの最後を指している
211
-
212
205
  // 追加する構造体メモリを獲得
213
- TPBook *tp = malloc(sizeof(TPBook));
206
+ TPBook * tp = malloc(sizeof(TPBook));
214
207
 
215
208
  // メンバを初期化する
216
209
  tp->next = NULL;
217
210
  strcpy(tp->name, name);
218
211
  strcpy(tp->number, number);
219
212
 
220
- if (p == NULL) // 一回目は tp 自身が先頭になる
213
+ if (head == NULL) // 一回目は tp 自身が先頭になる
221
214
  return tp;
222
215
 
216
+ TPBook *p = head;
217
+
218
+ while (p->next)
219
+ p = p->next;
220
+
221
+ // この時点で p はリストの最後を指している
223
222
  // 今作った構造体 tp をリストの最後に追加する。
224
223
  p->next = tp; // 新しい構造体をリストの最後に
225
224
  return head; // 二回目以降は head そのまま

5

完全版を追加

2021/06/11 08:58

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -102,4 +102,143 @@
102
102
  }
103
103
  return 0;
104
104
  }
105
+ ```
106
+ ---
107
+ サービス。私の手元で動作確認した完全版。
108
+ ```C
109
+ #include <stdio.h>
110
+ #include <string.h>
111
+ #include <stdlib.h>
112
+ #include <ctype.h>
113
+
114
+ typedef struct TelephoneBook {
115
+ char name[16];
116
+ char number[16];
117
+ struct TelephoneBook *next;
118
+ } TPBook;
119
+
120
+ TPBook * add_book(char *name, char *num, TPBook *head);
121
+ void print_book(TPBook *p);
122
+ void free_book(TPBook *p);
123
+ int check_name(char *name);
124
+ int check_number(char *number);
125
+
126
+ int main(void)
127
+ {
128
+ TPBook *head = NULL;
129
+ char name_number[33];
130
+ char name[16]; // 入力した名前を格納する
131
+ char number[16]; // 入力した電話番号を格納する
132
+ int check_na; // 仕様通りに入力されてなければ1,\qが入力されていれば2が代入される
133
+ int check_nu; // 仕様通りに入力されてなければ1が代入される
134
+
135
+ while (1) {
136
+ printf("input>");
137
+ fgets(name_number, sizeof(name_number), stdin);
138
+ sscanf(name_number, "%s %s", name, number);
139
+ check_na = check_name(name);
140
+
141
+ if (check_na == 2) {
142
+ print_book(head);
143
+ free_book(head);
144
+ return EXIT_SUCCESS;
145
+ }
146
+ if (check_na == 1) {
147
+ printf("error");
148
+ return EXIT_FAILURE;
149
+ }
150
+ check_nu = check_number(number);
151
+ if (check_nu == 1) {
152
+ printf("error");
153
+ return EXIT_FAILURE;
154
+ }
155
+ if (check_na == 0 && check_nu == 0) {
156
+ printf("Ok\n");
157
+ }
158
+ head = add_book(name, number, head);
159
+ print_book(head); // show result
160
+ }
161
+ }
162
+
163
+ int check_name(char *name)
164
+ {
165
+ char *chr1 = "\q";
166
+ char *chr2 = "\Q";
167
+
168
+ if (strcmp(name, chr1) == 0 || strcmp(name, chr2) == 0)
169
+ return 2;
170
+
171
+ int len = strlen(name);
172
+ if (!isupper(name[0])) // 先頭は英大文字であるべし
173
+ return 1;
174
+
175
+ for (int i = 1; i < len; i++) {
176
+ if (!islower(name[i])) // 残りは英小文字であるべし
177
+ return 1;
178
+ }
179
+ return 0; // ok
180
+ }
181
+
182
+ int check_number(char *number)
183
+ {
184
+ /* format: 090-1234-5678 */
185
+ for (int i = 0; i <= 2; i++) { // 0, 1, 2 が
186
+ if (!isdigit(number[i])) // 数字でないなら
187
+ return 1;
188
+ }
189
+ for (int i = 4; i <= 7; i++) { // 4, 5, 6, 7 が
190
+ if (!isdigit(number[i])) // 数字でないなら
191
+ return 1;
192
+ }
193
+ for (int i = 9; i <= 12; i++) { // 9, 10, 11, 12 が
194
+ if (!isdigit(number[i])) // 数字でないなら
195
+ return 1;
196
+ }
197
+ if (number[3] != '-' || number[8] != '-') {
198
+ return 1;
199
+ }
200
+ return 0; // ok
201
+ }
202
+
203
+ TPBook * add_book(char *name, char *number, TPBook *head)
204
+ {
205
+ TPBook *p = head;
206
+
207
+ while (p && p->next) {
208
+ p = p->next;
209
+ }
210
+ // この時点で p はリストの最後を指している
211
+
212
+ // 追加する構造体メモリを獲得
213
+ TPBook *tp = malloc(sizeof(TPBook));
214
+
215
+ // メンバを初期化する
216
+ tp->next = NULL;
217
+ strcpy(tp->name, name);
218
+ strcpy(tp->number, number);
219
+
220
+ if (p == NULL) // 一回目は tp 自身が先頭になる
221
+ return tp;
222
+
223
+ // 今作った構造体 tp をリストの最後に追加する。
224
+ p->next = tp; // 新しい構造体をリストの最後に
225
+ return head; // 二回目以降は head そのまま
226
+ }
227
+
228
+ void print_book(TPBook *p)
229
+ {
230
+ while (p) {
231
+ printf("%s : %s\n", p->name, p->number);
232
+ p = p->next;
233
+ }
234
+ }
235
+
236
+ void free_book(TPBook *p)
237
+ {
238
+ while (p) { /* 次ポインタがNULLまで処理 */
239
+ TPBook *p2 = p->next;
240
+ free(p);
241
+ p = p2;
242
+ }
243
+ }
105
244
  ```

4

for 文のバグを修正

2021/06/10 13:31

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -58,6 +58,9 @@
58
58
  P.S.
59
59
  それにしてもヘンな判定をしてますね。リスト操作をしようという段階になって、isdigit(), isupper(), islower() といった標準ライブラリ関数を知らないの?
60
60
  それに、いちいちローカルな配列にコピーしなくても、そのまま判定できますよ。
61
+ for (int i = 1; i <= len; i++) { これはバグ
62
+ for (int i = 1; i < len; i++) {  これが正しい
63
+
61
64
  ```C
62
65
  #include <ctype.h>
63
66
  int check_name(char *name)
@@ -72,7 +75,7 @@
72
75
  if (!isupper(name[0])) // 先頭は英大文字であるべし
73
76
  return 1;
74
77
 
75
- for (int i = 1; i <= len; i++) {
78
+ for (int i = 1; i < len; i++) { // !!条件を修正した!!
76
79
  if (!islower(name[i])) // 残りは英小文字であるべし
77
80
  return 1;
78
81
  }

3

main() にも #ifdef ORG を

2021/06/10 12:50

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -47,8 +47,12 @@
47
47
  ```C
48
48
  int main(void)
49
49
  {
50
+ #ifdef ORG
51
+ struct TelephoneBook *head = NULL;
52
+ #else
50
- struct TelephoneBook dummy = { "Dummy", "000-0000-0000", NULL };
53
+ struct TelephoneBook dummy = { "Dummy", "000-0000-0000", NULL };
51
- struct TelephoneBook *head = &dummy; // ダミーエントリをポイントして開始
54
+ struct TelephoneBook *head = &dummy; // ダミーエントリをポイントして開始
55
+ #endif
52
56
  ```
53
57
 
54
58
  P.S.

2

main() の修正を追加

2021/06/10 12:45

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -43,6 +43,14 @@
43
43
  }
44
44
  ```
45
45
 
46
+ 質問者のコードは head = NULL; でスタートしており、それだとORGコードが動作するが、私のコードではSegmentation Fault を起こし動作しない。そこで例えば次のようにダミーエントリを作っておく手がある。当座をしのいで動作確認はできるはず。
47
+ ```C
48
+ int main(void)
49
+ {
50
+ struct TelephoneBook dummy = { "Dummy", "000-0000-0000", NULL };
51
+ struct TelephoneBook *head = &dummy; // ダミーエントリをポイントして開始
52
+ ```
53
+
46
54
  P.S.
47
55
  それにしてもヘンな判定をしてますね。リスト操作をしようという段階になって、isdigit(), isupper(), islower() といった標準ライブラリ関数を知らないの?
48
56
  それに、いちいちローカルな配列にコピーしなくても、そのまま判定できますよ。

1

修正した関数を追加

2021/06/10 12:38

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -44,4 +44,47 @@
44
44
  ```
45
45
 
46
46
  P.S.
47
- それにしてもヘンな判定をしてますね。リスト操作をしようという段階になって、isdigit(), isupper(), islower() といった標準ライブラリ関数を知らないの?
47
+ それにしてもヘンな判定をしてますね。リスト操作をしようという段階になって、isdigit(), isupper(), islower() といった標準ライブラリ関数を知らないの?
48
+ それに、いちいちローカルな配列にコピーしなくても、そのまま判定できますよ。
49
+ ```C
50
+ #include <ctype.h>
51
+ int check_name(char *name)
52
+ {
53
+ char *chr1 = "\q";
54
+ char *chr2 = "\Q";
55
+
56
+ if (strcmp(name, chr1) == 0 || strcmp(name, chr2) == 0)
57
+ return 2;
58
+
59
+ int len = strlen(name);
60
+ if (!isupper(name[0])) // 先頭は英大文字であるべし
61
+ return 1;
62
+
63
+ for (int i = 1; i <= len; i++) {
64
+ if (!islower(name[i])) // 残りは英小文字であるべし
65
+ return 1;
66
+ }
67
+ return 0; // OK
68
+ }
69
+
70
+ int check_number(char *number)
71
+ {
72
+ /* number[] format: 090-1234-5678 */
73
+ for (int i = 0; i <= 2; i++) { // 0, 1, 2 が
74
+ if (!isdigit(number[i])) // 数字でないなら
75
+ return 1;
76
+ }
77
+ for (int i = 4; i <= 7; i++) { // 4, 5, 6, 7 が
78
+ if (!isdigit(number[i])) // 数字でないなら
79
+ return 1;
80
+ }
81
+ for (int i = 9; i <= 12; i++) { // 9, 10, 11, 12 が
82
+ if (!isdigit(number[i])) // 数字でないなら
83
+ return 1;
84
+ }
85
+ if (number[3] != '-' || number[8] != '-') {
86
+ return 1;
87
+ }
88
+ return 0;
89
+ }
90
+ ```