
こんにちは。私は30代の男性です。
「名前」「身長」「体重」が記載されたCSVファイルの内容を読み取って、構造体の「name」「height」「weight」に格納するプログラムを作っています。CSVの内容は
A,175,80
B,167,89
C,155,45
・
・
・
Z,188,70
だと仮定します。数値が読み取れているか、下記のように「tp = strtok(file_image, ",\n" );」の前後に「printf("%s\n", file_image);」を置いてみたら、strtok前では全て表示されるのに、strtok後では「ABC」しか表示されません。これでは全てのデータを構造体に格納できないので、困っています。
1.どのようにすれば、数字も取り出せる(読み取れる)でしょうか?
2.効率よく構造体に格納するには、どのようにしたらよいでしょうか?
アドバイスを頂ければ幸いです。宜しくお願いいたします。
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
int main(int argc, char *argv[])
{
FILE *fp = NULL;
int rtn = 0;
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("ファイルオープンに失敗しました。\n");
return 1;
}
if (argc != 2)
{
printf("ERROR: オプションの数に過不足があります。\n");
return 1;
}
rtn = change_csv(fp);
return 0;
}
int change_csv(FILE *fp)
{
int i;
int j;
char file_image[256]; /* 読み込んだ先のメモリの領域 */
char *tp;
for (i = 0; i <= 256; i++)
{
if (fgets(file_image, 256, fp) == NULL)
{
if (ferror(fp) != 0)
{
printf("ERROR: 読み込みに失敗しました。\n");
return 1;
}
}
if (feof(fp) != 0)
{
break;
}
printf("%s\n", file_image);
tp = strtok(file_image, ",\n" );
printf("%s\n", file_image);
}
fclose(fp);
return 0;
}
No.3ベストアンサー
- 回答日時:
★過去に似たような質問がありました。
・その質問は『改ページ』で区切られた文字列を読み込むにはどうすればよいか?
というものでした。今回は CSV ですが『改ページ』の部分を『カンマ文字』に
指定すれば文字列を分割できます。
・そのほか細かい点をアドバイスしますと
(1)main 関数の『FILE *fp = NULL;』や『int rtn = 0;』は代入後に参照しているため初期化の必要はありません。
(2)main 関数の『if (argc != 2){ … }』のリターンの前で『fclose(fp);』を記述しておきましょう。
(3)change_csv 関数に『fclose(fp);』がありますが、main 関数で統一させると分かりやすくなります。
(4)change_csv 関数で『fgets』のバッファ容量は『fgets(file_image,sizeof(file_image),fp)』とすると良いでしょう。
(5)change_csv 関数で『feof』を使うのならば『i』カウンタは必要ない気がします。
while ( fgets(file_image,sizeof(file_image),fp) != NULL ){
/*
行単位で CSV データを分割して構造体にセットする処理
*/
}
if ( feof(fp) ){
printf( "SUCCESS: 正常に読み込みました。\n" );
}
else if ( ferror(fp) ){
printf( "ERROR: 読み込みに失敗しました。\n" );
}
else{
printf( "ERROR: 不明なエラーで読み込みを中止しました。\n" );
}
(6)『strtok』を使うのなら次のようにします。→分かりやすくするためループしない記述です。
char *array[ 3 ];
char *token = " ,\t\r\n";
array[ 0 ] = strtok( file_image, token );…名前(name)
array[ 1 ] = strtok( NULL, token );……身長(height)
array[ 2 ] = strtok( NULL, token );……体重(weight)
最後に:
・『strtok』もよいがカンマ文字の前後にタブやスペースがないならば『strchr』関数でも分割できます。
その方法が下の『参考URL』でサンプルを載せています。どうぞ参考に。
・以上。頑張って下さい。私も30代の男性です。
参考URL:http://oshiete1.goo.ne.jp/qa2749340.html
Oh-Orange様
毎回ご回答頂き、ありがとうございます。(1)~(6)までのアドバイスを反映させて頂きます。Oh-Orange様も30代でしたか。私は最近C言語の勉強を始めたばかりです。
またの機会にアドバイスを頂ければ幸いです。
今後とも宜しくお願いいたします。
No.2
- 回答日時:
CSVファイルの1行のデータの並びがすでに決まっているのなら、
fgets で1行分読み込んで sscanf で一度に各要素に分解するのが
簡単だと思います。同時に書式チェックもできますし。
質問の例で書くと、1行分の取得は、名前が40バイトまでとするなら
char name[41],dummy[2];
int height, weight;
// 1行読み込み(ファイル終了/エラー処理は省略)
fgets(file_image, sizeof(file_image), fp);
// 各要素に分解して取得&同時に書式チェック
if (sscanf(file_image,"%40[^,],%d,%d%1s",name,&height,&weight,dummy) == 3) {
// 正常に取得されたときの処理
...
} else {
// 書式エラー時の処理
...
}
ただし、文字列要素にカンマが含まれててその文字列が引用符で
囲まれてるようなCSVなど、複雑な場合は簡単に済ませるわけには
いきませんが。
ご回答ありがとうございます。
>sscanf で一度に各要素に分解するのが簡単だと思います。同時に書式チェックもできますし。
そのような機能もあったのですね。勉強になります。
ありがとうございました。
No.1
- 回答日時:
> strtok前では全て表示されるのに、strtok後では「ABC」しか表示されません。
strtokはそのような動作をします。strtokは対象文字列を書き換えますから。
> これでは全てのデータを構造体に格納できないので、困っています。
そんなことはありません。strtokの使い方をちゃんと調べましたか?
http://www9.plala.or.jp/sgwr-t/lib/strtok.html
strtokでのトークン分割動作を確認したいなら、
> tp = strtok(file_image, ",\n" );
> printf("%s\n", file_image);
を以下のように書き換えてください。
for(tp = strtok(file_image, ",\n" ); tp != NULL; tp = strtok(NULL, ",\n" ) ){
printf("%s\n", tp);
}
それと、main関数でのargcのチェックはfopenの前にやった方が良いのでは。
あと、fopenとfcloseが別の関数にあるのはちょっと気持ち悪いですね。
ご回答ありがとうございます。
>それと、main関数でのargcのチェックはfopenの前にやった方が良いのでは。
>あと、fopenとfcloseが別の関数にあるのはちょっと気持ち悪いですね。
なるほど。言われてみればそうですね。勉強になります。そのように致します。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
- C言語・C++・C# #include <stdio.h>int main(void) { int buf[100] = 6 2022/11/01 22:45
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
memcpyについて
-
バイナリ形式の読み込み
-
CSVファイルを読み込み構造体の...
-
C言語でクロマキー合成をする方法
-
C言語でセグメンテーションエ...
-
複数ファイルの同時読み込みの...
-
ファイルからCR/LFを除去したい
-
「Aに対するBの割合」と「Aに対...
-
信頼区間の1.96や1.65ってどこ...
-
有効数字について 以前質問をし...
-
Fortran において変数の定義
-
C++の課題が分かりません。
-
Unicode でのWin32アプリのプロ...
-
.NET 小数点以下の切り捨てにつ...
-
c言語マップ探査ゲーム プログ...
-
2÷3などの余りについて
-
c++ 文字列を入力して、一文字...
-
C言語について
-
マイナスからプラスへ転じた時...
-
C言語をお願いします
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
複数ファイルの同時読み込みの...
-
C言語でファイル読み書きを早く...
-
fopenでファイル名に、変数を使...
-
c言語でのfscanfについて
-
ファイルへの書込み処理が異常...
-
ファイル出力で改行を入れたい!
-
fscanfでループしてしまう。
-
C言語にてXMLファイルから任意...
-
テキストファイル内に対して, ...
-
datファイルの読み込み
-
ファイルに行番号を追加
-
大量の入力ファイルを扱うとき...
-
辞書順にソートしたいのですが...
-
InternetReadFileを使ったファ...
-
C言語 連番データの読み込み
-
C言語におけるファイル読み込み...
-
数値のみ抽出(C言語)
-
簡易grep関数ができません。助...
-
VisualStudioでのファイルの入...
-
fgets( ) の返り値は何?
おすすめ情報