• ベストアンサー

プログラムソースの誤りを教えてください

CSVファイル(カンマでデータの要素が区切られている)の左から数えて15個目と16個目の間のデータを読みとるプログラムをつくりたいのですが、できません。どこがおかしいのか教えてください。 #include<stdio.h> int main(){ FILE *fp; char buff[562],yakusyoku[10]; int youso,n,konma; fp = fopen("jinji.csv","r"); if(fp == NULL) exit(1); fgets(buff,sizeof(buff),fp); n = 0,youso = 0,konma = 0; while (youso < sizeof(buff)){ if(buff[youso] == ','){ konma++; if (konma == 15){//カンマが15個になったら次の処理を行う while(buff[youso] != ','){//次のカンマ(16個目のカンマに会うまで次の処理を行う) yakusyoku[n] = buff[youso]; youso++,n++; break; } } } youso++; } fclose(fp); }

質問者が選んだベストアンサー

  • ベストアンサー
  • tokichim
  • ベストアンサー率42% (88/205)
回答No.1

もっといい書き方はありますが、それは置いておいて… breakの位置がおかしいのでは? 16個目のカンマを探すwhileループをすぐ抜けてしまいますね、これだと。 やりたかったのは16個めのカンマを発見したら最初のwhileループを抜けたい、ということですよね? ifなどで判定してbreakしないとだめですね。 ちなみに、string関係のライブラリを使った方が楽です。

gooaist
質問者

補足

ご回答、ありがとうございます。そうですね。breakの位置が違っていました。でも、2重文を強制終了させるので、goto文を使いました。それからほかにもいろいろ修正して、実行させることができました。ありがとうございます。 n = 0,youso = 0,konma = 0; while (youso < sizeof(buff)){ if(buff[youso] == ','){ konma++; if (konma == 15){ youso++; while(buff[youso] != ','){ yakusyoku[n] = buff[youso]; if(buff[youso] == ','){ konma++; goto label; } youso++,n++; } //break; } } youso++; } label: printf("%s",yakusyoku); string関係のライブラリを使った方が楽です。 →私もそう思うのですが、うまくできませんでした。tokichim様ならどう作りますか?お手数ですが、プログラムソースを作っていただけるでしょうか?

その他の回答 (3)

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.4

(暇な年寄りが割り込み) >プログラムソースを作っていただけるでしょうか? ★切り出し部分を関数化してみました。  ・質問者様の while 文を for 文で作ってみました。  ・テキストファイルの行端項目(◆)を切り出すことにも対応しています。  ・テストデータはテキストファイルのレコード(行端)を模しています。  (関数でのエラーに、呼出し側で対応していません) ☆10人いれば10とおりのソースが・・。 ------------------------------------------ #include <stdio.h> #include <string.h> #define DLMT 0x2C // CSV int StrKiridashi( char cBuff[], char cWork[], int iBasyo ) {  int i, iCnt = 0, iLen;  char *cNext;  for( i = 0; i < 512; i++ ){   if( 0x0D >= cBuff[i] ) return( -9 ); // 異常行?   if( DLMT == cBuff[i] ){    iCnt++; // カンマ加算    if( iBasyo == iCnt ){ // 指定場所     cNext = strchr( &cBuff[ i + 1 ], DLMT );     if( NULL == cNext ){ // ◆      strcpy( cWork, &cBuff[ i + 1 ] );      iLen = strlen( cWork ) - 1;      cWork[iLen] = 0x00; // \n → \0      return( 0 );     }     *cNext = 0x00;     strcpy( cWork, &cBuff[ i + 1 ] );     *cNext = DLMT; // CSV 復活     return( 0 );    }   }  }  return( -9 ); // 異常行? } void main() {  char cBuff[512] = ",,,,,,,,,,,,,,,test,行端\n";  char cWork[64];  StrKiridashi( cBuff, cWork, 5 );  printf( "[%s]\n", cWork );  StrKiridashi( cBuff, cWork, 15 );  printf( "[%s]\n", cWork );  StrKiridashi( cBuff, cWork, 16 );  printf( "[%s]\n", cWork ); } 注:インデントに全角空白を用いています。   タブに一括変換して下さい。

  • php504
  • ベストアンサー率42% (926/2160)
回答No.3

string使って作ってみましたよ #include <stdio.h> #include <string.h> int main(void) { char buff[562] = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20"; // test data char yakusyoku[10] = {0}; char *start, *end; int i; start = buff; /* , を15個読み飛ばしその1個先にstartをセット */ for (i = 0; i < 15; i++) { start = strchr(start, ','); if (start == NULL) { fprintf(stderr, "error missing %dth comma", i+1); return 1; } start++; } /* 16 個目の , を文字列終端にするために \0 に変更 */ end = strchr(start, ','); if (end == NULL) { fprintf(stderr, "error missing 16th comma"); return 1; } *end = '\0'; memcpy(yakusyoku, start, 9); printf("%s", yakusyoku); return 0; }

  • YOKO-bee
  • ベストアンサー率50% (2/4)
回答No.2

まず現状はどのような処理結果が出ていますか? 次にフローチャートを机上チェックされましたか? チェックした上で理想とする処理結果は以下のデータだと どうなりましたか? [テストデータ]--------------------- 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 ----------------------------------- そのフローチャートとソースは同じですか?

関連するQ&A

  • tab

    下のプログラムソースは、jinji.txtの各行の一列目を読み取るプログラムです。 jinji.txtには項目がtabで区切られています。 たとえば、下のようになっています。 番号 tab 姓 tab 名 1 tab 高田 tab 太郎 2 tab 山田 tab 順平 … 300 tab 永井 tab 晃 ソースの真ん中ぐらいに、 while(buff[count]!=' ') とあります。これは最初のtabまで読み取る、つまり一列目を読み取るコードなのですが、tabは「' '」でいいのでしょうか?「' '」でtabだと判断できますか? #include<stdio.h> #define num 100 int main(){ FILE *fp; char buff[num],bango[10]; int count; fp = fopen("jinji.txt","r"); if(fp == NULL) exit(1); fgets(buff,sizeof(buff),fp); count=0; while(buff[count]!=' '){ bango[count]=buff[count]; count++; } //printf("%s\n",bango); fclose(fp); }

  • ある関数のソースがわかりません。

    KOKUGO=100 SUUGAKU=80 RIKA=0 SYAKAI=60 というファイルを取得して数字だけ構造体に渡す関数のソースです。 define KOKUGO 3; define SUUGAKU 2; define RIKA 1; define SYAKAI 2; 構造体は typedef struct{ char koku[KOKUGO +1]; char suu[SUUGAKU +1]; char rika[RIKA + 1]; char sya[SYAKAI + 1]; }data; です。 全体ではデータを読み取ってcsv形式で出力するプログラムなんですが main関数、出力関数はちょっと省きます。 int Readfile(data *txtfile, char *ptxt) { FILE *fp; char *fullcode = NULL; char search = '='; char buff[30] = {'\0'}; int enum[4] = {'\0'}; int err = 0; char *rtxt = NULL; /*ファイルオープン*/   fp = fopen(ptxt, "r"); if(fp == NULL){ puts("オープンエラー"); return(1); } /*ファイル読み取り*/   while(1){ /*データを一行ずつ読み取り*/    rtxt = fgets(buff, sizeof(buff), fp); if(rtxt == NULL){ break; } /*データ名確認*/    if(strncmp(buff, "KOKUGO=", 7) == 0){ ••••••••••• (1) /*'='を含むデータ確認*/   fullcode = strchr(buff, search); /*'='より後ろの点数確認*/ fullcode += 1; /*点数桁数確認*/   if(strlen(fullcode) == KOKUGO + 1){ /*構造体に点数のみ格納*/     strncpy(txtstr -> koku, fullcode, KOKUGO); enum[0] += 1; }else{ puts("データが違います") return(1); } }else if(strncmp(buff, "SUUGAKU=", 8) == 0){   fullcode = strchr(buff, search); fullcode += 1;   if(strlen(fullcode) == SUUGAKU + 1){     strncpy(txtstr -> suu, fullcode, SUUGAKU); enum[1] += 1; }else{ puts("データが違います") return(1); } } else if(strncmp(buff, "RIKA=", 5) == 0){   fullcode = strchr(buff, search); fullcode += 1;   if(strlen(fullcode) == RIKA + 1){     strncpy(txtstr -> rika, fullcode, RIKA); enum[2] += 1; }else{ puts("データが違います") return(1); } } else if(strncmp(buff, "SYAKAI=", 7) == 0){   fullcode = strchr(buff, search); fullcode += 1;   if(strlen(fullcode) == SYAKAI + 1){     strncpy(txtstr -> sya, fullcode, SYAKAI); enum[3] += 1; }else{ puts("データが違います") return(1); } } } for(err = 0; err < 4; err ++){ if(enum[err] != 1){ puts("データが違います"); return(1); } } /*ファイルを閉じる*/   fclose(fp); return(0); } という風に書いてあるんですが(1)の部分で7文字比較して等しければ 次の/*'='を含むデータ確認*/に進むと思うんですが等しくなければ どういう処理が行われ、どこに進むのかわかりません。 基本的にこの無限ループの流れがわかりません。 このソースの読み方を教えてください。 友達が以前書いたソースなんですが聞いてももうわからないらしくて・・・。    すいませんが、勉強し始めたばかりなので詳しくお願いします。

  • ファイルから読み取った「行の長さ」は・・?

    すみません。 while (fgets(buff, 256, pFile) != NULL) { ~~~ } として1行ずつファイルを読み込み、その中で1文字ずつ処理する為に 必要なforループのループ回数を得たいのですが・・ char buff[256]; // 先に確保した配列を、fgetsした後に int buff_length = sizeof(buff) /sizeof(buff[0]); // 長さを得ようとする こうすると確保したサイズ256が返ってきてしまい困っています。(当然かもですが・・ ファイルの1行の長さを毎回取得する方法は無いでしょうか?

  • C言語について教えてください。

    数日前に「http://okwave.jp/qa4903738.html」で質問させてもらった者です。 前回、寝起きでボケてるうちに回答を締め切ってしまって、 回答してくださった方との対話ができていませんでした。 すみません。 今回は前回の指摘された部分を含めて回答を戴きたく投稿させてもらいます。 質問内容はほぼ変わりありません。 CSVファイルの内容をfreadで読み込み、strtokを使わずにbuffに格納した後、 buffから1文字ずつbuff2へコピーさせていって、コンマがきたら数字、 改行がきたら名前と判別して、自作関数に渡して表示させたいです。 あと、fgetsは使わないようにしたいです。 CSVファイルの内容は 『11,名前1(改行) 15,名前2(改行) 18,名前3』 といった感じです。 ----------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE 1 #include <stdio.h> #include <string.h> #include <stdlib.h> #define NUM 256 struct kou { short nenrei; char namae[30]; }; void pri(struct kou o) { printf("%d\n%s\n",o.nenrei,o.namae); } int main(void) { FILE *fp; // ファイルポインタ char buff1[NUM] = {0}; char buff2[NUM] = {0}; char *fname = "text1.csv"; // ファイル名を指定 int n = 0; struct kou p; fp = fopen(fname, "r"); if(fp == NULL) { printf("%sファイルをオープンできませんでした。\n",fname); return 1; } fread(buff1, 1, NUM, fp); // ここでファイルの内容が全てbuffに入る。 // printf("%s\n",buff1); // buff1にファイルの内容が書き込まれているか確認する。 while((buff2[n] = buff1[n]) != NULL) // buff2[0]からbuff1の中が終わるまで一文字ずつコピーしていく。 { if(buff2[n] == ',') // buff2に格納されていく中にコンマがきたら以下の作業を行う。 { p.nenrei = atoi(buff2); // char型からshort型への変換し、p.iAgeに入れていく。 } if(buff2[n] == '\n') { strcpy(p.namae,buff2); // p.namaeにbuff2をコピー。 pri(&p); } n++; } fclose(fp); printf("ファイルをクローズしました。\n"); return 0; } ----------------------------------------------- 前回指摘されたwhileの条件式ですが、 まだchar型とポインタを比べてることになっているので正しくないんですよね? 正直、どうすればいいかわかりません。 あと、今のままでは名前3の後が改行ではないので表示されることないですよね・・・。 どうすれば表示されるようになるでしょうか。 これも前回言われましたが while内の1つ目のif文の所で、カンマを処理したので次に取り込むbuff2への書き込み位置の変更というのもわかりません。 カンマが来た時点でbuff2[n]のnは2になっているんですよね? ということはbuff2[3]からまた読み込めたらいいということですよね? 厚かましくも立て続けに質問してしまって申し訳ありませんが回答を戴けたらありがたく思います。 宜しくお願いします。

  • C言語についてアドバイスをください。

    CSVファイルの内容をfreadで読み込み、strtokを使わずにbuffに格納した後、 buffから1文字ずつbuff2へコピーさせていって、コンマがきたら数字、 改行がきたら名前と判別して、自作関数に渡して表示させたいです。 CSVファイルの内容は 『11,名前1(改行) 15,名前2(改行) 18,名前3』 といった感じです。 ------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE 1 #include <stdio.h> #include <string.h> #include <stdlib.h> #define NUM 256 struct kou { short nenrei; char namae[30]; }; void pri(struct kou *o) { printf("%d\n%s\n",o->nenrei,o->namae); } int main(void) { FILE *fp; // ファイルポインタ char buff1[NUM] = {0}; char buff2[NUM] = {0}; char *fname = "text1.csv"; // ファイル名を指定 short i = 0; int n = 0; struct kou p; fp = fopen(fname, "r"); if(fp == NULL) { printf("%sファイルをオープンできませんでした。\n",fname); } fread(buff, 1, NUM, fp); while(buff1[n] != NULL) { buff2[n] = buff1[n]; // buff2[0]からbuff1の中を一文字ずつコピーしていく。 if(buff2[n] == ',') // buff2に格納されていく中にコンマがきたら以下の作業を行う。 { i = (short)atoi(buff2); // char型からshort型への変換 p.nenrei = i; } if(buff2[n] == '\n') { strcpy(p.namae,buff2); // p.namaeにbuff2をコピー。 pri(&p); } n++; } fclose(fp); printf("ファイルをクローズしました。\n"); return 0; } ------------------------------------------------------- 今のままだと 『11 11,名前1 11 11,名前1 15,名前2』 という表示になってしまいます。 while 内で既に読み込んだ部分を読み込ませないよう(表示させないよう)にできたら良いと思うんですが、そういったやり方はあるのでしょうか? むしろやり方を変えたほうが良いでしょうか・・・。 まだC言語を学び始めて日が浅いので、色々間違っている部分もあると思いますが、 そういったことを含めてアドバイスをいただけたらと思います。 よろしくお願いします。

  • if文で…

    いつもお世話になっております。 ------------------------ typedef struct douken_ { char tiku[11]; char ken[9]; } douken; int main(void){ FILE *fp; douken dou [100]; char buff [18 /* douken */ + 2 /* CrLf(\n\r) */ + 1 /* \0 */]; int i; i = 0; fp = fopen("ex3.fil","rb"); if ( fp == 0 ){ printf("can't open\n"); exit(1); } memset (dou , '\0' , sizeof dou); memset (buff, '\0' , sizeof buff); 問題はここから----------------- while (fgets(buff,sizeof buff,fp) != NULL){ memcpy(&dou[i].tiku ,buff,10); memcpy(&dou[i].ken ,buff+10,10); if (&dou[i].tiku == &dou[i-1].tiku){ printf("%s %s",&dou[i-1].tiku,&dou[i].tiku,&dou[i].ken);} else{ printf("-----------------------"); } ------------------------ 上記のプログラムでは ファイルから読み込んだデータを 構造体に格納して if文で現データと全データを 比較するという処理をしています。(つもり) 構造体に格納するところまでは 出来たのですが if文のところが上手く行きません。 例えば 現データ(tiku)関東地区 前データ(tiku)関東地区 と、同じ場合は 関東地区 東京 と、表示したいのに ----------- と、elseの処理をしてしまいます。 対処方法をご存じでしたら、 ご教授して頂けたら幸いです。

  • C++初心者です。ご指導よろしくお願いします。

    C++初心者です。ご指導よろしくお願いします。 C++で特定の行の値を読み込むプログラムを作っています。 a.txtとb.txtが入力ファイルで、c.txtが出力ファイルです。 a.txtには 237891 193203 1355876 ・ ・ ・ (以下1~5000000の数値がランダムに15000行分) b.txtには 0.333333 0.333333 0.397396 ・ ・ ・ (以下0.333333~0.822222までの数値がランダムに5000000行分) が書いてあって、 c.txtに a.txtの1行目の数値の行に対応するb.txtの値 a.txtの2~ a.txtの3~ ・ ・ ・ (以下15000行分) を出力するプログラムを作りたいと思っています。 以下のように、プログラムを書きましたが、a.txtが10行、b.txtが20行程度の時は問題なく動くのですが、行数が多くなると急に動かなくなります。 charのところを変えたり、offsetのところを変えたりしたのですが、最初の1行を読み込んだところで止まってしまいます。 (buffの値は=237891 no2の値は=237891まで) どのようにすれば動くようになるでしょうか? ご指導よろしくお願いします。 #include <stdio.h> #include <iostream> #include <fstream> #include <cstdlib> #include <cstring> using namespace std; int main(void) { FILE *fp,*fp2,*fp3; char buff[256],buff2[256]; long int offset[100],offset2[100]; long int max,max2; long int no=0; long int no2=0; for(no=1; no<=15000; no++){ fp = fopen("input/a.txt","r"); if(fp == NULL){ cout << "入力ファイルをオープンできません\n"; } for ( max = 0 ; !feof(fp) ; max++ ){ if ( max >= 100 ){ break; } offset[ max ] = ftell( fp ); fgets( buff, sizeof(buff), fp ); } fseek( fp, offset[no - 1], SEEK_SET ); fgets( buff, sizeof(buff), fp ); cout << "buffの値は=" << buff << "\n"; no2 = atoi(buff); cout << "no2の値は=" << no2 << "\n"; fp2 = fopen("input/b.txt","r"); if(fp2 == NULL){ cout << "入力ファイルをオープンできません\n"; } for ( max2 = 0 ; !feof(fp2) ; max2++ ){ if ( max2 >= 100 ){ break; } offset2[ max2 ] = ftell( fp2 ); fgets( buff2, sizeof(buff2), fp2 ); } fseek( fp2, offset2[no2 - 1], SEEK_SET ); fgets( buff2, sizeof(buff2), fp2 ); cout << "buff2の値は=" << buff2 << "\n"; fp3 = fopen("input/c.txt","a"); if(fp2 == NULL){ cout << "入力ファイルをオープンできません\n"; } fprintf(fp3, buff2); strcpy(buff,"0"); strcpy(buff2,"0"); no2=0; cout << "buff2は初期化されて=" << buff2 << "\n"; fclose(fp); fclose(fp2); fclose(fp3); } }

  • 単語の出現頻度を調べるプログラム

     ファイルからデータを読み込んで、単語の出現頻度を調べるプログラムを作ろうと考えて、下記のようなプログラムを書いてみました。 #include <stdio.h> #include <string.h> main() { struct data {char word[128]; int freq;} word_data[128]; char words[128]; char term[128]; int i=0; int nw=0; int j; char buff[128]; FILE *fp_in=fopen("data.txt","r"); while(fgets(fp_in,128,buff)!=EOF){ char buff[128]; int k; for(k=0;k<=128;k++){ printf("%s",buff); if(('A'<=buff[k] && buff[k]<='Z')||('a'<=buff[k] && buff[k]<='z')) term[i++]=buff[k]; else if(i>0) term[i]='\0';} for(j=0;j<nw;j++){ if(strcmp(term,word_data[j].word)==0) break; if(j==nw) {strcpy(word_data[j].word,term); word_data[j].freq=1; nw++;} else if(j!=nw) {word_data[j].freq++; i=0;} }} for(j=0;j<nw;j++) printf("%s %d",word_data[j].word,word_date[j].freq); return 0;} コンパイルは通ったのですが、実行しても画面に何も表示されません。原因は何処にあるのでしょうか?分かる方がいましたら、ご回答宜しくお願いします。

  • プログラムの合成願い

    あらかじめ行列の数がわかっているN行*M列のエクセルデータをCSV形式にし、 読み込むプログラムを作成しました。 そのプログラムを下に示します #include <stdio.h> #include <stdlib.h> #include <string.h> /* 確保するデータ保存領域の大きさ(N行×M列) */ #define N 23 #define M 6 /* データの区切り文字*/ #define SEP_DATA',' int csv_read(char filename[], double csv[N][M]) { /* ファイルオープン*/ FILE *fp; if( (fp = fopen(filename, "r")) == NULL ) { printf(" file open error!!\n"); return -1; } /* 1行毎に読み出し*/ char line[256], *ptr; int i, j, k; i=0; while (fgets(line, 256, fp) != NULL) { printf("*%s", line); ptr = line; j=0; do{ /* line[j]から次のタブ文字までを数値に変換*/ csv[i][j] = atof(ptr); /* 次のタブ文字の位置を探す*/ ptr = strchr(ptr, SEP_DATA); /* タブ文字の次の文字を示す*/ if (ptr!=NULL) { ptr++; } j++; }while(ptr!=NULL && j<M); i++; } /* ファイルクローズ*/ fclose(fp); return 0; } int main(int argv, char *argc[]) { char filename[256]; if( argv > 1){ strcpy(filename, argc[1]); } else { printf("Please Input Filename:"); scanf("%s", filename); } /* データ保存用の領域を確保*/ double (*csvdata)[M]; csvdata = (double(*)[M])malloc(sizeof(double[M]) * N); //malloc(sizeof(*csvdata) * N); if ( csvdata == NULL ){ return -1; } int i,j; /* 配列の初期化*/ for( i=0; i<N; i++) { for( j=0; j<M; j++) { csvdata[i][j] = 0.0; } } /* CSVデータの読み込み*/ if( csv_read(filename, csvdata) < 0 ) { return -1; } /* 配列の出力*/ for( i=0; i<N; i++) { printf("%lf", csvdata[i][0]); for( j=1; j<M; j++) { printf("\t%lf", csvdata[i][j]); } printf("\n"); } free(csvdata); csvdata = NULL; return 0; } また、行列の数を計算するプログラムを作成しました。(プログラムは別途URLを書き込みます) http://www.kent-web.com/pubc/book/test/uploader/uploader.cgi?mode=downld&no=3797 これら二つのプログラムを合わせかたがわかりません。 プログラムで示していただきたいです。お願いします。 環境はC++です。

  • c言語でcsvファイルの処理で、処理速度が速いプログラムを書こうと思っ

    c言語でcsvファイルの処理で、処理速度が速いプログラムを書こうと思っています。 以下のようなcsvファイル、件数は約10000000件以上あるものを使います shop,ymd,gend,age,area,amt 20,2008-05-01,3,5,014,128 22,2008-05-01,2,4,015,350 : 二列目の日別、つまりymd別に最後列のamdの小計を出したいんですが、組んだプログラムを実行してみると、セグメンテーション違反ですと出てしまうんです。以下のようなプログラムを組んだんですが #include <stdio.h> #include <string.h> #include <time.h> #define MM 256 int main() { FILE *fp; char str[MM],*p1, *p2,*ymd; int num, sum; clock_t start,end; start = clock(); fp = fopen("csv.csv","r"); if(fp == NULL){ printf("ファイルが開けませんでした。\n"); return(0); } sum = 0; fgets(str, sizeof(str), fp); while(fgets(str, sizeof(str), fp) != NULL){ p1 = strtok(str, ","); p1 = strtok( NULL,","); ymd = p1; p2 = strrchr(str,','); sum[ymd] = atoi(p2+1); break; } while( fgets(str, sizeof(str), fp) != NULL && p1 != NULL){ p1 = strtok(str, ","); p1 = strtok( NULL,","); p2 = strrchr(str,','); if ( p2 != NULL ) { if(ymd == p1){ sum[ymd] += atoi(p2+1); }else{ printf("%s ,%d \n",ymd,sum[ymd]); strcpy(ymd,p1); } } } printf("%s ,%d \n",p1,sum); fclose(fp); end=clock(); printf("%.2f秒\n",(double)(end-start)/CLOCKS_PER_SEC); return(0); } うまくいきません。大体、処理速度は3秒以内を目指しています。 どなたかご教授御願いいたします。

専門家に質問してみよう