- ベストアンサー
C言語 構造体(2)
ご質問です。 構造体で、あらかじめメンバ数を固定したものではなく、 テキストファイルを読み込んだときにメンバ数を変えて読み込みたいのです。 (カンマできりたい) aaa.txt ------------------------ あああ,いいい ------------------------ となっているときは、 tmp.nm[0]=あああ tmp.nm[1]=いいい となり、 kamoku.nm[0] kamoku.nm[1] をprintf。 aaa.txt --------------------------- あああ,いいい,ううう,えええ --------------------------- の場合は tmp.nm[0]=あああ tmp.nm[1]=いいい tmp.nm[2]=ううう tmp.nm[3]=えええ kamoku.nm[0] kamoku.nm[1] kamoku.nm[2] kamoku.nm[3] をprintf。 下記は動きません。。 よろしくお願いいたします。 #include <stdio.h> struct kamokumei { char nm[10]; }kamoku; int main(void) { int i,P,t; FILE *fp; struct kamokumei kamoku[20]; char buf[1024]; fp = fopen("aaa.txt", "r"); P=3; t=0; while( fgets(buf, sizeof(buf), fp) ){ struct kamokumei tmp; sscanf(buf, "%s", tmp.nm[t]); nm[t++] = tmp; } for(i = 0; i < P; i++) { printf("%s\n", kamoku.nm[i]); } return 0; }
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
FILE *fp; char buf[1024]; while( fgets(buf, sizeof(buf), fp) ) これだと 1行が1024文字以上だと当然うまく読み込めません。 まずその部分から改善する必要があります。 #include <stdio.h> #include <string.h> #include <malloc.h> #define MAX_BUF 2 int main() { FILE *fp; int len; char buf[MAX_BUF]; int buflen; fp = fopen("aaa.csv", "r"); char *pBuf2 = NULL; while( fgets(buf, MAX_BUF , fp) ){ int buflen = strlen(buf); if ( buf[buflen - 1] == '\n'){ buf[buflen - 1] = '\0'; pBuf2 = (char*)realloc( pBuf2 , buflen ); printf("%s\n",pBuf2); if (pBuf2) free(pBuf2); pBuf2 = NULL; }else{ if ( pBuf2 == NULL ){ pBuf2 = (char*)malloc( buflen + 1 ); strcpy( pBuf2 , buf ); }else{ pBuf2 = (char*)realloc( pBuf2 , buflen + 1 ); strcat( pBuf2 , buf ); } } } if (pBuf2) free(pBuf2); }
その他の回答 (5)
- sha-girl
- ベストアンサー率52% (430/816)
訂正 int i,j; for( i = 1 ; i <= mycsv.cnt ; i++ ){ printf( "(mycsv.line + i)->cnt=%d\n" , (mycsv.line + i - 1)->cnt ); for( j = 1 ; j <= (mycsv.line + i - 1)->cnt ; j++ ){ printf( "%d行目%d列目は「%s」\n" ,i,j, ReadCsv( &mycsv , i-1 , j-1 ) ); } } ちなみにこのソース、最後が改行で終わっていなければ 最後の行が読まれませんでした。 printf( "2行目3列目は「%s」" , ReadCsv( &mycsv , 2 - 1 , 3 - 1 ) ); の上に if (pBuf2) AddCsv( &mycsv , pBuf2 ); を追加すれば解消します。
- sha-girl
- ベストアンサー率52% (430/816)
>aaa.txtを読み込んだ時の >最大行の数、最大列の数はどの変数にあたるのでしょうか? 最大行の数:mycsv->cnt 1行目の最大列の数:mycsv->line->cnt 2行目の最大列の数:(mycsv->line + 1)->cnt int i,j; for( i = 1 ; i <= mycsv->line->cnt ; i++ ){ for( j = 1 ; j <= (mycsv->line + i)->cnt ; j++ ){ printf( "%d行目%d列目は「%s」" ,i,j, ReadCsv( &mycsv , i-1 , j-1 ) ); } }
補足
早速回答を頂きありがとうございます。 すみません、再々度質問なのですが、、 -> か ->* の左には構造体のポインタが必要 とerrorがでます。 ポインタについて本を読みながらやっているものの、 解決できません、、 よろしくお願いいたします。 http://oshiete1.goo.ne.jp/kotaeru.php3?q=1217707 でも受け付けています。
- const
- ベストアンサー率66% (12/18)
最終的に何がしたいのかわからないのですが、元のソースをベースに1行を分割するものを書いてみます。 複数の行ならばkamokuを二次元配列にする必要があり、最大の列・行数が不定ならばsha-girlさんのように書く必要があります。 #include <stdio.h> #include <string.h> struct kamokumei { char name[32]; }; static char *split(char *buf, char delimiter) { char *next = strchr(buf, delimiter); if (next == NULL) return buf + strlen(buf); *next = '\0'; return next + 1; } static int split_csvline(char *buf, struct kamokumei *dest, int max) { char *next, *item; int i; for(i = 0, item = next = buf; *next != '\0' && i < max; i++, item = next) { next = split(item, ','); strcpy(dest[i].name, item); } return i; } int main(void) { int i, count, length; FILE *fp; struct kamokumei kamoku[20]; char buf[1024]; fp = fopen("aaa.txt", "r"); if (fgets(buf, sizeof buf, fp)) { buf[sizeof buf - 1] = '\0'; length = strlen(buf); if (buf[length - 1] == '\n') buf[length - 1] = '\0'; count = split_csvline(buf, kamoku, sizeof kamoku / sizeof kamoku[0]); for(i = 0; i < count; i++) printf("%s\n", kamoku[i].name); } return 0; } ちなみにテキストファイルを処理して出力するだけならばperlをお勧めします。 open(FP, "<aaa.txt") or die; while (<FP>) { chomp; @columns = split(/,/); push(@csv, [@columns]); } printf('2行目3列目は「%s」' , $csv[2-1]->[3-1]);
補足
回答を頂いた皆様へ ありがとうございます。 >二次元配列にする必要があり、最大の列・行数が不定ならば・・・ できれば二次元配列にしたいので、sha-girlさんから回答いただいたソースを元にしたいと思います。 printf( "2行目3列目は「%s」" , ReadCsv( &mycsv , 2 - 1 , 3 - 1 ) ); は、理解できたのですが、 その他の動きがまったくわからない状態です、、 aaa.txtを読み込んだ時の 最大行の数、最大列の数はどの変数にあたるのでしょうか? たとえば、 最大行の数=x 最大列の数=y i=1,j=1として、 i=1 to x j=1 to y とし、ループで全部表示させることが目的です。 printf( "%d行目%d列目は「%s」" , i,j,ReadCsv( &mycsv , i - 1 , j - 1 ) );
- sha-girl
- ベストアンサー率52% (430/816)
とりあえず書いてみました。 aaa.csvから読み込み char* ReadCsv( MYCSV* pCsv , int l , int r ) の関数で読み込みます。 printf( "2行目3番目は「%s」" , ReadCsv( &mycsv , 2 - 1 , 3 - 1 ) ); の部分で2行目3番目にある項目を表示しています。 #include <stdio.h> #include <string.h> #include <malloc.h> typedef struct ___mycsvline{ int cnt; char **str; } MYCSVLINE; typedef struct ___mycsv{ int cnt; MYCSVLINE* line; } MYCSV; #define MAX_BUF 2 char* ReadCsv( MYCSV* pCsv , int l , int r ) { MYCSVLINE* pLine; if ( l >= pCsv->cnt ){ return ""; } pLine = (pCsv->line + l ); if ( r >= pLine->cnt ){ return ""; } return *(pLine->str + r); } int GetStrToken(char* str){ int cnt = 0; while( *str != '\0' && *str != ',' ){ cnt++; str++; } return cnt; } int GetConmaCnt(char* str){ int cnt = 0; while( *str != '\0'){ if ( *str == ',' ) cnt++; str++; } return cnt; } void AddLine( MYCSVLINE* pLine , char* str ){ int i; int NextConma; int ConmaCnt = GetConmaCnt(str); pLine->cnt = ConmaCnt + 1; pLine->str = (char**)malloc( sizeof(char*) * pLine->cnt ); for( i = 0 ; i < pLine->cnt ; i++ ){ NextConma = GetStrToken(str); *(pLine->str + i) = (char*)malloc( NextConma + 1 ); strncpy( *(pLine->str + i) , str , NextConma ); *( *(pLine->str + i) + NextConma ) = '\0'; str += ( NextConma ); if ( *str == ',' ) str++; } } void AddCsv( MYCSV* pCsv , char* str ){ pCsv->cnt++; pCsv->line = (MYCSVLINE*)realloc( pCsv->line , sizeof( MYCSV ) * pCsv->cnt ); AddLine( (pCsv->line + (pCsv->cnt - 1) ) , str ); } void AllFree( MYCSV* pCsv ){ int i,j; MYCSVLINE* pLine; for ( i = 0 ; i < pCsv->cnt ; i++ ){ pLine = (pCsv->line + i); for( j = 0 ; j < pLine->cnt ; j++ ){ free( *(pLine->str + j) ); } free(pLine->str); } free( pCsv->line ); } int main() { FILE *fp; char buf[MAX_BUF]; int buflen; int ttlbuflen = 0; fp = fopen("aaa.csv", "r"); char *pBuf2 = NULL; MYCSV mycsv; mycsv.cnt = 0; mycsv.line = NULL; while( fgets(buf, MAX_BUF , fp) ){ buflen = strlen(buf); ttlbuflen += buflen; if ( buf[buflen - 1] == '\n'){ buf[buflen - 1] = '\0'; if (pBuf2 == NULL){ pBuf2 = (char*)malloc( ttlbuflen + 1 ); strcpy( pBuf2 , buf ); }else{ pBuf2 = (char*)realloc( pBuf2 , ttlbuflen + 1 ); strcat( pBuf2 , buf ); } AddCsv( &mycsv , pBuf2 ); if (pBuf2) free(pBuf2); ttlbuflen = 0; pBuf2 = NULL; }else{ if ( pBuf2 == NULL ){ pBuf2 = (char*)malloc( ttlbuflen + 1 ); strcpy( pBuf2 , buf ); }else{ pBuf2 = (char*)realloc( pBuf2 , ttlbuflen + 1 ); strcat( pBuf2 , buf ); } } } printf( "2行目3列目は「%s」" , ReadCsv( &mycsv , 2 - 1 , 3 - 1 ) ); AllFree( &mycsv ); if (pBuf2) free(pBuf2); }
お礼
回答を頂いた皆様へ ありがとうございます。 >二次元配列にする必要があり、最大の列・行数が不定ならば・・・ できれば二次元配列にしたいので、sha-girlさんから回答いただいたソースを元にしたいと思います。 printf( "2行目3列目は「%s」" , ReadCsv( &mycsv , 2 - 1 , 3 - 1 ) ); は、理解できたのですが、 その他の動きがまったくわからない状態です、、 aaa.txtを読み込んだ時の 最大行の数、最大列の数はどの変数にあたるのでしょうか? たとえば、 最大行の数=x 最大列の数=y i=1,j=1として、 i=1 to x j=1 to y とし、ループで全部表示させることが目的です。 printf( "%d行目%d列目は「%s」" , i,j,ReadCsv( &mycsv , i - 1 , j - 1 ) );
- sha-girl
- ベストアンサー率52% (430/816)
#1です。ちょっと下のソースおかしかったので訂正しときます。 int main() { FILE *fp; char buf[MAX_BUF]; int buflen = 0; int ttlbuflen = 0; fp = fopen("aaa.csv", "r"); char *pBuf2 = NULL; char* pp; while( fgets(buf, MAX_BUF , fp) ){ buflen = strlen(buf); ttlbuflen += buflen; if ( buf[buflen - 1] == '\n'){ buf[buflen - 1] = '\0'; if (pBuf2 == NULL){ pBuf2 = (char*)malloc( ttlbuflen + 1 ); strcpy( pBuf2 , buf ); }else{ pBuf2 = (char*)realloc( pBuf2 , ttlbuflen + 1 ); strcat( pBuf2 , buf ); } printf("%s\n",pBuf2); if (pBuf2) free(pBuf2); ttlbuflen = 0; pBuf2 = NULL; }else{ if ( pBuf2 == NULL ){ pBuf2 = (char*)malloc( ttlbuflen + 1 ); strcpy( pBuf2 , buf ); }else{ pBuf2 = (char*)realloc( pBuf2 , ttlbuflen + 1 ); strcat( pBuf2 , buf ); } } } if (pBuf2) free(pBuf2); } ところでC++(stlのvectorやstring)を使うっていうのは無しですよね? Cのみで構造体を可変長にする場合、上記と同じようにreallocやmalloc、callocを 使用します。 可変長文字列かつ可変長リストであるなら typedef struct ___mycsvline{ int cnt; char **str; } MYCSVLINE; typedef struct ___mycsv{ int cnt; MYCSVLINE* line; } MYCSV; CSVは構造体はこんな定義でどうでしょう。
お礼
沢山の回答ありがとうございました。 大変勉強になりました。 (が、結局可変長のところはうまくいかず締め切りがきてしまいました、、) もう少し勉強していきたいと思います。 今後ともよろしくお願いいたします。