🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

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

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

Q&A

2回答

2398閲覧

[C言語]構造体にファイルデータを入れる

momonga_

総合スコア1

C

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

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

0グッド

0クリップ

投稿2021/01/15 17:18

[C言語]構造体にファイルのデータを入れて表示させたいです

C言語でファイルのデータを構造体に入れたいです。
自分なりにコードを書いてみたのですがエラーが出て行き詰まってしまいました。

発生している問題・エラーメッセージ

last.c:31:10: warning: incompatible pointer to integer conversion assigning to 'char' from 'char [25]' [-Wint-conversion] line[1]= "2020,1,1,10.2,-10.2,10.2"; ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~ last.c:45:14: warning: incompatible integer to pointer conversion passing 'char' to parameter of type 'char *'; take the address with & [-Wint-conversion] p = strtok(line[k],","); ^~~~~~~ & /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/string.h:90:20: note: passing argument to parameter '__str' here char *strtok(char *__str, const char *__sep); ^ last.c:75:12: warning: incompatible integer to pointer conversion passing 'char' to parameter of type 'char *'; take the address with & [-Wint-conversion] fgets( line[k] , sizeof(line[k]) , fp ); ^~~~~~~ & /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/stdio.h:149:30: note: passing argument to parameter here char *fgets(char * __restrict, int, FILE *); ^ last.c:76:16: warning: incompatible integer to pointer conversion passing 'char' to parameter of type 'char *'; take the address with & [-Wint-conversion] p = strtok(line[k],","); ^~~~~~~ & /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/string.h:90:20: note: passing argument to parameter '__str' here char *strtok(char *__str, const char *__sep); ^ 4 warnings generated.

該当のソースコード

#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_CELLS (365 + 1) // セルの個数 typedef struct weather{ int year; int month; int day; double max_tem; double min_tem; double sum_rain; } std; //構造体変数の内容を表示 void printData(int i,std weather) { printf("number : %d\n",i); printf("year_month_day : %d %d %d\n",weather.year,weather.month,weather.day); printf("highest_temperature : %f\n",weather.max_tem); printf("lowest_temperature : %f\n",weather.min_tem); printf("1時間降水量の最大 : %f\n",weather.sum_rain); printf("\n"); } int main() { int i,j=1,k=1; //kはDataの数 FILE *fp; char line[MAX_CELLS]; char *p; line[1]= "2020,1,1,10.2,-10.2,10.2"; std weather[MAX_CELLS] = { { 0, 0, 0, 0.0, 0.0, 0.0 }, // iris[0] (ダミー) }; fp = fopen( "data.csv", "r"); if( fp == NULL ) { fprintf(stderr, "ファイルがオープンできません\n"); exit(1); } p = strtok(line[k],","); weather[k].year = atoi(p); j++; //1つ目のトークンを入力 //情報を読み込み終わるまでループ while(j<=6){ //2回目以降は第一引数はNULL p = strtok(NULL,","); if (p != NULL) { switch (j) { case 2: weather[k].month = atoi(p); case 3: weather[k].day = atoi(p); case 4: weather[k].max_tem = atof(p); case 5: weather[k].min_tem = atof(p); case 6: weather[k].sum_rain = atof(p); } j++; } } j = 1; for(k=2; feof(fp) == 0;k++){ fgets( line[k] , sizeof(line[k]) , fp ); p = strtok(line[k],","); weather[k].year = atoi(p); j++; //1つ目のトークンを入力 printf("%d",atoi(p)); //情報を読み込み終わるまでループ while(j<=6){ //2回目以降は第一引数はNULL p = strtok(NULL,","); if (p != NULL) { switch (j) { case 2: weather[k].month = atoi(p); case 3: weather[k].day = atoi(p); case 4: weather[k].max_tem = atof(p); case 5: weather[k].min_tem = atof(p); case 6: weather[k].sum_rain = atof(p); } j++; } } j = 1; printf("%d",k); } fclose( fp ); for(i = 1; i < k; i++) { printData(i, weather[i]); // std型の値を } // 関数 printData に渡す return 0; }

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

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

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

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

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

guest

回答2

0

line[1]= "2020,1,1,10.2,-10.2,10.2";

初期化式は変数の定義時しかできません

char line[MAX_CELLS]= "2020,1,1,10.2,-10.2,10.2";

とする必要があります

p = strtok(line[k],",");

引数の型が違います

投稿2021/01/15 21:58

編集2021/01/15 22:01
y_waiwai

総合スコア88038

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

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

momonga_

2021/01/16 11:57

エラーは解決できたのですが実行すると結果が表示されず、長時間実行中のままになってしまいます。 解決法で思い当たるものがなにかございましたら、教えて欲しいです
guest

0

31行
line[1]= "2020,1,1,10.2,-10.2,10.2";

strcpy(line,"2020,1,1,10.2,-10.2,10.2");
に変更
(line[1]は意味不明、lineの先頭から格納)

char line[MAX_CELLS];の定義は365日分のデータが格納できない。
1行分のデータしか格納できない。もし1行256バイトとして
365日分のデータを格納したいなら、
char line[MAX_CELLS][256];
のように定義しないといけない。
しかし、今回は、1行分のデータを保持できれば良いので、
char line[MAX_CELLS];のままとする。
本来は、

C

1#define BUFF_SIZE (256) 2char line[BUFF_SIZE]; 3

のように定義すべき。

45行
p = strtok(line[k],",");

p = strtok(line,",");
に変更(line[k]は意味不明、lineの先頭から処理)

75行
fgets( line[k] , sizeof(line[k]) , fp );

fgets( line , sizeof(line) , fp );
に変更(line[k]は意味不明、lineの先頭へ読み込む)

76行
p = strtok(line[k],",");

p = strtok(line,",");
に変更(line[k]は意味不明、lineの先頭から処理)

上記の修正で、エラーがとれます。
動作確認はしていません。

>エラーは解決できたのですが実行すると結果が表示されず、長時間実行中のままになってしまいます。
上記の解決方法ですが
for(k=2; feof(fp) == 0;k++){
fgets( line , sizeof(line , fp );

for (k = 2; ; k++) {
if (fgets(line, sizeof(line), fp) == NULL) break;
に変えてください。

この現象には2つの問題があります。
問題1
ファイルの終了判定が正しくない。
fgets( line , sizeof(line , fp );で最後の行を読んだ後で、forに戻り
feof(fp) == 0が実行されたとき、feof(fp)の値は非0にならず、0のままです。
fgetsでNULLが返った時が、ファイル終端をを検知したときです。
そのあとで、feof(fp)を実行すると非0になります。
そのため、上記のようにしました。
fgetsでNULLが返るのはファイル終端に達した場合か、エラーが発生した場合かのどちらかです。
通常はファイル終端であると判断して良いと思いますが、
厳密にエラーが発生していないことを確認したいなら(ファイル終端であることを確認したいなら)
forのループのあとで、
ferror(fp)==0を判定し、それが成立すれば、エラーは発生していないので、ファイル終端になります。

問題2

C

1 //情報を読み込み終わるまでループ 2 while (j <= 6) { 3 4 //2回目以降は第一引数はNULL 5 p = strtok(NULL, ","); 6 7 if (p != NULL) { 8 switch (j) { 9 case 2: 10 weather[k].month = atoi(p); 11 case 3: 12 weather[k].day = atoi(p); 13 case 4: 14 weather[k].max_tem = atof(p); 15 case 5: 16 weather[k].min_tem = atof(p); 17 case 6: 18 weather[k].sum_rain = atof(p); 19 } 20 j++; 21 } 22 }

このwhile(j<=6)は、データが正常であれば問題ありませんが、データが異常の場合問題になります。
1行のデータの項目数が6個未満の場合、もしくは、,,,のように中身がない場合です。
これらの場合、p = strtok(NULL, ",");はNULLが返りPはNULLになります。
そうすると、jの値が増えない為、whileで永久ループに入ります。
今回の「長時間実行中のまま」になる現象は、以下のような状態になっています。
1.ファイルの最後の行を読んだ後、for(k=2; feof(fp) == 0;k++)で
feof(fp) == 0なので、forを抜けないで、
fgets( line , sizeof(line , fp );が実行される。
再後の行まで処理されたので、fgetsからはNULLが返り、lineにはなにもセットされない。
従って、前の状態が残ったままである。
strtokを実行した場合は、各データのカンマ(,)の位置に\0が設定され、そこが文字の終端となる。
そのため、最初の項目の,の位置に\0がセットされ1つも項目だけがlineの存在することになる。
その為、while(j<=6)が成立し、永久ループとなる。
この個所は、問題のあるコードですが、ファイル終端の処理を正しく修正した場合は、ボロが出ません。
(項目数が6つあるので)
従って、このままでも、問題はありません。(項目数が足りない等の不正なデータの場合はボロがでます)

投稿2021/01/16 06:19

編集2021/01/17 05:50
tatsu99

総合スコア5493

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

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

momonga_

2021/01/16 11:56

ありがとうございます。 上記回答通りに修正しましたらエラーは取れコンパイルはできました。 ただ、実行すると結果が表示されず、長時間実行中のままになってしまいます。 解決法で思い当たるものがなにかございましたら、教えて欲しいです
pepperleaf

2021/01/16 12:16

例えば、 > printf("%d",k); これをprintf("%d\n",k); とすると途中経過が分かるかも、、。 もっとも無限ループに陥っていると、やはり、強制終了か? あと、caseで、break; が無いと次の行も実行されます。
tatsu99

2021/01/17 05:51

>長時間実行中のままになってしまいます。 >解決法で思い当たるものがなにかございましたら、教えて欲しいです 回答欄に追記しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問