CSVファイルの読み込み

C言語で「ファイルの読込」「文字列データの扱い」「連結リスト」の勉強をするためにCSVファイルを読み込んで連結リストに格納するコードを書いてみた。配列サイズ、変数サイズを予め決めない。fgets(), strtok()は用いていない。fgetc()で1バイトずつ読んで、たまったところでstrcpy()で書き込み。

#include 
#include
#include

typedef struct { // 連結リスト用構造体
void *data; // データへのポインタ
struct CELL *next; // 次のセルのアドレス
} CELL;

typedef struct { // 読み込んだリストの基本データ用構造体
CELL *cell_init; // 連結リストの先頭セルのアドレス
int row_max; // リストの行数
int column_max; // リストの列数
int strlen_max; // 要素の文字列長の最大値
} CSV_DATA;

// CSVファイル読み込み関数
CSV_DATA read_csv( // [OUT] CSVのデータ
char *name // [IN] CSVファイル名
){
CSV_DATA csv;
CELL *cell_init= 0,*cell_line,*cell_curr;
FILE *fp;
char a[128];
int row_max=0,column_max=0,column_tmp=0,strlen_max=0;

// CSVファイルの読み込み
if( (fp= fopen(name,"r")) != NULL ){
int c,strlen_tmp=0;
// 連結リストの先頭セルの作成
cell_curr= cell_line= cell_init= calloc(1,sizeof(CELL));
do{
c= fgetc(fp);
switch(c){
case -1: // EOF
case 10: // 改行
case 44: // コンマ(デリミタ)
a[strlen_tmp]='\0'; // 文字列の終了
cell_curr->next= calloc(1,sizeof(CELL)); // 列セルの作成
cell_curr= (CELL*)cell_curr->next;
// データ格納領域の作成
cell_curr->data= malloc( (strlen_tmp+1)*sizeof(char) );
column_tmp++; // 列カウンタの数え上げ
// 文字列長、列数の最大値の記録
if( strlen_max < strlen_tmp ) strlen_max= strlen_tmp;
if( column_max < column_tmp ) column_max= column_tmp;
strcpy(cell_curr->data,a); // CSVデータ要素の格納
if( c==10 ){ // 改行検出時の処理
cell_line->data= calloc(1,sizeof(CELL)); // 行先頭セルの作成
cell_line= (CELL*)cell_line->data;
cell_curr= cell_line; // 列セルの書き換え
column_tmp=0; // 列カウンタの初期化
row_max++; // 行カウンタの数え上げ
}
strlen_tmp=0; // 文字数カウンタの初期化
break;
default:
a[strlen_tmp]=c; // 文字データのスタック
strlen_tmp++;
break;
}
} while ( c != EOF );
fclose(fp);
}
// CSV基本データの格納
csv.cell_init= cell_init;
csv.row_max= row_max;
csv.column_max= column_max;
csv.strlen_max= strlen_max;
return csv;
}

// 連結リスト内のデータの読み出し関数
char *read_cell_data( // [out] 文字列@(行番号,列番号)へのポインタ
CELL *cell_init // 連結リストの先頭アドレス
,int row // 行番号
,int column // 列番号
){
int i;
CELL *cell= cell_init;
// 行を進める
for(i=0;idata;
if(cell==0) goto null_pointer;
}
// 列を進める
cell= (CELL*)cell->next;
if(cell==0) goto null_pointer;
for(i=0;inext;
if(cell==0) goto null_pointer;
}
// 文字列データへのポインタを返す
return (char*)cell->data;
null_pointer: return (char*)0;
}

int main(int argc,char *argv[]){
if( argc > 1 ){
CSV_DATA csv;
CELL *cell_init;

// CSVファイルの読み込み
csv= read_csv(argv[1]);

// 読み込み結果
printf("row %d column %d strlen %d\n"
,csv.row_max,csv.column_max,csv.strlen_max);

// CSVデータの表示
cell_init=csv.cell_init;
if( cell_init ){
int i,j;
for(i=0;i\n",i,j,read_cell_data(cell_init,i,j));
}
}
}
}
}
return 0;
}