回答編集履歴

1

文言追記しました。

2021/01/17 05:50

投稿

tatsu99
tatsu99

スコア5493

test CHANGED
@@ -87,3 +87,133 @@
87
87
  上記の修正で、エラーがとれます。
88
88
 
89
89
  動作確認はしていません。
90
+
91
+
92
+
93
+ >エラーは解決できたのですが実行すると結果が表示されず、長時間実行中のままになってしまいます。
94
+
95
+ 上記の解決方法ですが
96
+
97
+ for(k=2; feof(fp) == 0;k++){
98
+
99
+ fgets( line , sizeof(line , fp );
100
+
101
+
102
+
103
+ for (k = 2; ; k++) {
104
+
105
+ if (fgets(line, sizeof(line), fp) == NULL) break;
106
+
107
+ に変えてください。
108
+
109
+
110
+
111
+ この現象には2つの問題があります。
112
+
113
+ 問題1
114
+
115
+ ファイルの終了判定が正しくない。
116
+
117
+ fgets( line , sizeof(line , fp );で最後の行を読んだ後で、forに戻り
118
+
119
+ feof(fp) == 0が実行されたとき、feof(fp)の値は非0にならず、0のままです。
120
+
121
+ fgetsでNULLが返った時が、ファイル終端をを検知したときです。
122
+
123
+ そのあとで、feof(fp)を実行すると非0になります。
124
+
125
+ そのため、上記のようにしました。
126
+
127
+ fgetsでNULLが返るのはファイル終端に達した場合か、エラーが発生した場合かのどちらかです。
128
+
129
+ 通常はファイル終端であると判断して良いと思いますが、
130
+
131
+ 厳密にエラーが発生していないことを確認したいなら(ファイル終端であることを確認したいなら)
132
+
133
+ forのループのあとで、
134
+
135
+ ferror(fp)==0を判定し、それが成立すれば、エラーは発生していないので、ファイル終端になります。
136
+
137
+
138
+
139
+ 問題2
140
+
141
+ ```C
142
+
143
+ //情報を読み込み終わるまでループ
144
+
145
+ while (j <= 6) {
146
+
147
+
148
+
149
+ //2回目以降は第一引数はNULL
150
+
151
+ p = strtok(NULL, ",");
152
+
153
+
154
+
155
+ if (p != NULL) {
156
+
157
+ switch (j) {
158
+
159
+ case 2:
160
+
161
+ weather[k].month = atoi(p);
162
+
163
+ case 3:
164
+
165
+ weather[k].day = atoi(p);
166
+
167
+ case 4:
168
+
169
+ weather[k].max_tem = atof(p);
170
+
171
+ case 5:
172
+
173
+ weather[k].min_tem = atof(p);
174
+
175
+ case 6:
176
+
177
+ weather[k].sum_rain = atof(p);
178
+
179
+ }
180
+
181
+ j++;
182
+
183
+ }
184
+
185
+ }
186
+
187
+ ```
188
+
189
+ このwhile(j<=6)は、データが正常であれば問題ありませんが、データが異常の場合問題になります。
190
+
191
+ 1行のデータの項目数が6個未満の場合、もしくは、,,,のように中身がない場合です。
192
+
193
+ これらの場合、p = strtok(NULL, ",");はNULLが返りPはNULLになります。
194
+
195
+ そうすると、jの値が増えない為、whileで永久ループに入ります。
196
+
197
+ 今回の「長時間実行中のまま」になる現象は、以下のような状態になっています。
198
+
199
+ 1.ファイルの最後の行を読んだ後、for(k=2; feof(fp) == 0;k++)で
200
+
201
+ feof(fp) == 0なので、forを抜けないで、
202
+
203
+ fgets( line , sizeof(line , fp );が実行される。
204
+
205
+ 再後の行まで処理されたので、fgetsからはNULLが返り、lineにはなにもセットされない。
206
+
207
+ 従って、前の状態が残ったままである。
208
+
209
+ strtokを実行した場合は、各データのカンマ(,)の位置に\0が設定され、そこが文字の終端となる。
210
+
211
+ そのため、最初の項目の,の位置に\0がセットされ1つも項目だけがlineの存在することになる。
212
+
213
+ その為、while(j<=6)が成立し、永久ループとなる。
214
+
215
+ この個所は、問題のあるコードですが、ファイル終端の処理を正しく修正した場合は、ボロが出ません。
216
+
217
+ (項目数が6つあるので)
218
+
219
+ 従って、このままでも、問題はありません。(項目数が足りない等の不正なデータの場合はボロがでます)