ページ 1 / 1
CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月01日(土) 14:04
by takoman
開発環境:EasyIDEC
環境OS:windows7
1. 自分は今何がしたくて
C言語でCSV(文字列)を読み込んで二次元配列に格納し表示させたい。
2. どう取り組んで(作ったプログラムはどれで
下記に記述させていただきます。
3. どのようなエラーやトラブルで困っていて
単純な表示はできましたが、それを二次元配列に格納することができない。
4. 自分は何が解らないのか、知りたいのか
どのようにすれば二次元配列にトークンを格納できるのか。
5. 今のCの知識はどの程度なのか
初めて1か月ほどになります。
CSVの詳細
日本の首都は,東京,京都,静岡,沖縄,1
1+1は,2,3,4,5,1
1+2は,3,4,4,5,1
1+3は,4,5,4,5,1
初めまして。初めて質問させていただきます。
現在勉強のため、簡単なクイズアプリを作成しようと作業しております。
現在CSVを読み込んでカンマ区切りで表示させる方法はできたのですが、
それを二次元配列に入れる方法がよくわかりません。何の知識がないため
こういった事象になっているのか判断つけるためにもぜひともご教授いただけますでしょうか。
「おそらく問題であろうと自分なりに考えた箇所」
二次元配列の初期化ができていないため処理ができていないのではないか。
コード:
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *fp;
char *csv = "quiz.csv";//ファイルの読み込み
char buf[1024];
char *kakunou;
char array[80][128];
int i; //行インデックス
int j; //列インデックス
//////////////////ファイル読み込み/////////////////
fp = fopen( csv, "r" ); //ファイル読み込み
if( fp == NULL ){
printf( "%sファイルが開けません\n", csv);
return -1;
}
//////////////////ファイル読み込み/////////////////
//////////////////csv解析処理開始/////////////////
i = j = 0;
while(fgets(buf, sizeof(buf), fp)){
kakunou = buf;
//printf("%s",kakunou); //1行ずつの取得問題なし
while( (kakunou = strtok(kakunou,",\0")) != NULL){
//array[i][j++] = ;ここをどういった処理にすればいいのかがわからないです。
//printf("%s\n",kakunou);トークンごとの表示問題なし
kakunou = NULL;
}
i++;
j = 0;
}
//////////////////csv解析処理開始/////////////////
fclose( fp ); //ファイルのクローズ
return 0;
}
ご教授よろしくお願いいたします。
Re: CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月01日(土) 14:56
by usao
おそらく 文字列の2次元配列 にデータを格納したいのだと思いますが,
コード:
char str[100]; //文字列('\0'を含めて100byteまで)
char str_1DArray[5][100]; //文字列の1次元配列
char str_2DArray[3][5][100]; //文字列の2次元配列
なので,arrayの型が違うかな?とか.
(固定長でいいのか?とかいうこともあるけど)
文字列同士のコピーはstrcpy()とか使えばよいかと思います.
Re: CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月01日(土) 15:00
by takoman
>> usao さん
ご返信ありがとうございます。
>>なので,arrayの型が違うかな?とか
そうなんですね。。勘違いしておりました。
>>(固定長でいいのか?とかいうこともあるけど)
こちらは可変長を考えております。
>>文字列同士のコピーはstrcpy()とか使えばよいかと思います.
ありがとうございます。まずはやってみようと思います。
Re: CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月01日(土) 15:22
by takoman
>> usao さん
たびたびすみません。
たとえば
1行目:日本の首都は,東京,京都,静岡,沖縄,1
2行目:1+1は,2,3,4,5,1
というCSVファイルがあった際に
array配列に
array[1行目][日本の首都は]
array[1行目][東京]
という格納方法をしたい場合は
文字列の一次元配列ということでよろしいのでしょうか。
Re: CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月01日(土) 16:39
by non
takoman さんが書きました:
(固定長でいいのか?とかいうこともあるけど)
こちらは可変長を考えております。
すると、動的にメモリを確保しなくてはいけないですね。
問題数は固定で用意しますか?それともこちらも可変ですか?
Re: CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月01日(土) 16:49
by かずま
takoman さんが書きました:
1行目:日本の首都は,東京,京都,静岡,沖縄,1
2行目:1+1は,2,3,4,5,1
というCSVファイルがあった際に
array配列に
array[1行目][日本の首都は]
array[1行目][東京]
という格納方法をしたい場合は
配列の添え字は整数なのでそんなことはできません。
おそらく、
array[0][0] = "日本の首都は"
array[0][1] = "東京"
array[0][2] = "京都"
array[0][3] = "静岡"
array[0][4] = "沖縄"
array[0][5] = "1"
array[1][0] = "1+1は"
array[1][1] = "2"
array[1][2] = "3"
array[1][3] = "4"
array[1][4] = "5"
array[1][5] = "1"
としたいのではありませんか?
コード:
char *array[80][6];
char *tok;
for (i = 0; i < 80 && fgets(buf, sizeof(buf), fp); i++) {
tok = strtok(buf, ",\n");
for (j = 0; j < 6 && tok; j++) {
array[i][j] = strdup(tok);
tok = strtok(NULL, ",\n");
}
}
ただし、strdup は標準関数ではないので、それをどうするかは宿題です。
初心者にはむずかしいかもしれません。
Re: CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月02日(日) 12:28
by takoman
>>non さん
ご返信ありがとうございます。
返答遅くなり失礼しました。
>すると、動的にメモリを確保しなくてはいけないですね。
動的にメモリを確保ということはmallocを使って確保させる必要がある
ということででしょうか。
>問題数は固定で用意しますか?それともこちらも可変ですか
こちらも可変を考えております。
Re: CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月02日(日) 12:31
by takoman
>かずま さん
ご返信ありがとうございます。
返答遅くなり失礼しました。
>おそらく、
>array[0][0] = "日本の首都は"
>array[0][1] = "東京"
>としたいのではありませんか?
おっしゃる通りです。こちらの説明が解りづらく失礼いたしました。
>ただし、strdup は標準関数ではないので、それをどうするかは宿題です。
参考ソースありがとうございます。拝見させていただきぜひ勉強いたします。
>初心者にはむずかしいかもしれません。
あきらめたくないので頑張ってみます。
Re: CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月02日(日) 14:45
by non
takoman さんが書きました:>>non さん
ご返信ありがとうございます。
返答遅くなり失礼しました。
>すると、動的にメモリを確保しなくてはいけないですね。
動的にメモリを確保ということはmallocを使って確保させる必要がある
ということででしょうか。
>問題数は固定で用意しますか?それともこちらも可変ですか
こちらも可変を考えております。
そうですね。mallocを使うのが正道でしょうね。でも、学校の課題でないなら、かずまさんがサンプルを書いているstrdup を
使うのが簡単です。
問題数が可変の場合は、問題の最大数が決められるのなら、配列で最大数を用意する方が簡単です。
もちろん、これも動的に用意してもかまいません。ただし、動的に用意するなら、構造体を使ったほうが良いです。
趣味で作ろうとされているのだろうと思いますので、かずまさんが載せているサンプルを元に、作るのが良いと思います。
Re: CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月02日(日) 15:16
by taketoshi
可変長で書くためには固定長でのコードが書けないと難しいと思います。
ロジックさえ理解していれば後から可変長に書き直せますので、まずは固定長で書いてみてはいかがでしょうか。
私は決まったフォーマットのcsvファイルの読み込みを構造体で実施します。
takomanさんのコードに手を加えたものを掲載しておきますので、良かったら参考にしてみてください。
► スポイラーを表示
コード:
#include <stdio.h>
#include <string.h>
#include<stdlib.h>
//問題を格納するための構造体
typedef struct{
char a[5][100];
}Question;
int main(void)
{
FILE *fp;
char *csv = "quiz.csv";//ファイルの読み込み
char buf[1024];
Question *lpQuestion;
//////////////////ファイル読み込み/////////////////
fp = fopen( csv, "r" ); //ファイル読み込み
if( fp == NULL ){
printf( "%sファイルが開けません\n", csv);
return -1;
}
//////////////////ファイル読み込み/////////////////
//CSVファイルの行数を読み込むため一度最後まで空読みする
int count = 0;
while(fgets(buf, sizeof(buf), fp)){
count++;
}
//バッファのリセット
memset(buf,0,sizeof(buf));
//行数の確認
printf("csvファイルの行数 = %d行\n",count);
//ファイルポインタを先頭に戻す
fseek(fp,0,SEEK_SET);
//Question構造体を問題数だけ確保する
lpQuestion = (Question *)calloc(count,sizeof(Question));
//////////////////csv解析処理開始/////////////////
int i=0;
//sscanf用バッファ
char buff[5][100];
while((fgets(buf, sizeof(buf), fp) )){
//sscanfで格納していく最後が%[^,]だと読み込みがおかしくなる
sscanf(buf,"%[^,],%[^,],%[^,],%[^,],%s", buff[0], buff[1], buff[2], buff[3], buff[4]);
//代入
strncpy(lpQuestion[i].a[0],buff[0],sizeof(lpQuestion[i].a[0]));
strncpy(lpQuestion[i].a[1],buff[1],sizeof(lpQuestion[i].a[1]));
strncpy(lpQuestion[i].a[2],buff[2],sizeof(lpQuestion[i].a[2]));
strncpy(lpQuestion[i].a[3],buff[3],sizeof(lpQuestion[i].a[3]));
strncpy(lpQuestion[i].a[4],buff[4],sizeof(lpQuestion[i].a[4]));
//確認
printf("%s,%s,%s,%s,%s\n",lpQuestion[i].a[0],lpQuestion[i].a[1],lpQuestion[i].a[2],
lpQuestion[i].a[3],lpQuestion[i].a[4]);
//行数のカウントアップ
i++;
}
//////////////////csv解析処理開始/////////////////
//メモリの解放
free(lpQuestion);
fclose(fp); //ファイルのクローズ
return 0;
}
諦めずにぜひ最後までやってみてください。
楽しいですよ。
Re: CSV(文字列)を二次元配列に格納する方法
Posted: 2013年6月04日(火) 10:03
by takoman
>non さん
ご返信ありがとうございます。
>そうですね。mallocを使うのが正道でしょうね。でも、学校の課題でないなら、かずまさんがサンプルを書いているstrdup を
>使うのが簡単です。
ありがとうございます。かずまさんのサンプルをもとに作成して無事動作することができました。
「標準関数ではないので、それをどうするかは宿題」という点に関して考えていきます。
>問題数が可変の場合は、問題の最大数が決められるのなら、配列で最大数を用意する方が簡単です。
>もちろん、これも動的に用意してもかまいません。ただし、動的に用意するなら、構造体を使ったほうが良いです。
アドバイスありがとうございます。現状の作品が完了した段階で構造体を使ったバージョンも作成しようと考えております。
>taketoshiさん
ご教授ありがとうございます。
可変長で書くためには固定長でのコードが書けないと難しいと思います。
ロジックさえ理解していれば後から可変長に書き直せますので、まずは固定長で書いてみてはいかがでしょうか。
はい。おっしゃる通りまだまだ理解したつもりになっている箇所が多数ありますので、固定長で書いてみます。
>takomanさんのコードに手を加えたものを掲載しておきますので、良かったら参考にしてみてください。
参考コードありがとうございます。本当に勉強になります。
>諦めずにぜひ最後までやってみてください。
>楽しいですよ。
ありがとうございます。私のような初心者に暖かいお言葉本当に力になります。
またわからない点がでたら質問させてください。
こちらの質問を解決とさせていただきます。
皆様ありがとうございました。またよろしくお願いいたします。