reallocとstrtokの併用について

このQ&Aのポイント
  • reallocすると先頭から徐々にデータが文字化けしていきます。
  • 5つ目が見つかった時点では出力に問題は無いのですが、6個目から侵食が始まっていきます。
  • 原因がどうしても自分では分からなかったので、誰かお願い致します。
回答を見る
  • ベストアンサー

reallocとstrtokの併用について

fscanfで文字列を読み込み、strtokでカンマ区切りにするという関数を作りたいのですが、 reallocすると先頭から徐々にデータが文字化けしていきます。 まず最初に4つ分のchar*を取ります。 もし、5つ目が見つかったらさらに4つ増やし、9つ目が見つかったらさらに。。。というようになっております。 n個目の判定はcntがn-1で真になり、reallocが成功したら個数を増やすようになってます。 5つ目が見つかった時点では出力に問題は無いのですが、6個目から侵食が始まっていきます。 原因がどうしても自分では分からなかったので、誰かお願い致します。 words.txtの内容(末尾改行なし) iii,jjj,kkkkkkkkk,l,m,n,ooooo,pppppppp,a,s,d,f,g main.c #include<stdio.h> #include<stdlib.h> #include<string.h> #include"C:\borland\bcc55\Include\malloc.h" int readlinefile(FILE *fp,char **words){ int cnt=0,len; char *line=(char *)malloc(256); char *tmp; if(line==NULL) return 0; if(fscanf(fp,"%s",line)!=EOF){ if((tmp=(char *)realloc(line,sizeof(char)*(strlen(line)+1)))==NULL){//できるだけメモリを節約してみる return 0; }else{ line=tmp; } len=strlen(line); printf("line:%d:%d:%s\n",len,_msize(line),line); if(len>1){//ファイル終端の改行を排除 int i; char *tok=strtok(line,",");//カンマで区切ったアドレスを得る while(tok){ if(cnt==0)printf("tok:1st:%x\n",tok); if(cnt>3&&cnt%4==0){//サイズが足りなくなった時 char **tmp2; if((tmp2=(char **)realloc(words,sizeof(char *)*(4+4*(cnt%4))))==NULL){ printf("words realloc ERROR\n"); break; }else{ printf("realloc\n"); words=tmp2;//reallocを適用 } } words[cnt]=tok; if(cnt){ printf("line(func)"); for(i=0;i<len+1;i++){ printf("%c",words[0][i]); } printf("\n"); } tok=strtok(NULL,","); printf("words[%d]:%x:%s\n",cnt,words[cnt],words[cnt]); printf("\n"); printf("tok:%d回目:%x\n",cnt+1,tok); cnt++; } return cnt;//正常終了した }else{ free(line); } } return 0; } int main(){ FILE *fp=fopen("words.txt","r"); if(fp){ int cnt=1; while(cnt){ int i; char **words=(char **)malloc(sizeof(char *)*4); words[0]=NULL; cnt=readlinefile(fp,words); printf("mainに戻りました\n"); if(cnt) printf("words:%d\n",cnt); for(i=0;i<cnt;i++){ printf("words[%d]:%x:%s\n",i,words[i],words[i]); } free(words[0]); words[0]=NULL; printf("\n"); free(words); } }else{ printf("file open ERROR\n"); } return 0; } 実行結果 なぜかコピペできないので実行するか斧でダウンロードお願いします。 http://www1.axfc.net/u/3352789.txt 全てまとめたもの http://www1.axfc.net/u/3352796.zip

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

  • ベストアンサー
  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.2

>if(cnt>3&&cnt%4==0){//サイズが足りなくなった時 >char **tmp2; >if((tmp2=(char **)realloc(*words,sizeof(char *)*(4+4*(cnt%4))))==NULL){ ifの条件とrealloc()するサイズをよくみましょう。 また直接関係する事ではありませんがポインタ値を"%x"で出力させるのは間違ってます(sizeof(int) == sizeof(void *)の環境では動きはしますが)。

jororo0
質問者

お礼

ご回答ありがとうございます。 cnt>3で初めての時は4=cntのときにcnt%4==0で5個目で、 cnt>3で2回目の時は8=cntの時にcnt%4==0で9個目で、 …でここは合ってますか? sizeofの後の定数は元のサイズで、4*(cnt%4)は…ゼロ!? 動きました!ありがとうございます!! 本当にありがとうございます。全然気づきませんでした。 アドレスの出力の方ですが、まさしくポインタの値は整数と同じビット数だと思ってました。 これからは%pの方に直します。

その他の回答 (2)

  • honor
  • ベストアンサー率35% (25/71)
回答No.3

分割したトークンの実体を格納している領域はどこですか?

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.1

readlinefileは、realloc()したwordsをどうやってmain()に返してるんでしょうか。

jororo0
質問者

補足

ご回答ありがとうございます。 返して無いですね。reallocで返ってきたアドレスが同じだったみたいです。 修正版上げました。ー>http://www1.axfc.net/u/3352861.c いい忘れましたが、ソースファイルで字下げの無いところは削除しても問題ありません。

関連するQ&A

  • reallocについて

    現在、領域を拡張しながら、 ファイルを読み込んで呼び元に返却するPGを作成しています。 reallocがうまくいかないので、試しに小さいのを作って みましたが、これだとreallocの2度目で落ちます。 100文字ずつ呼んでいるので、拡張も100文字ずつ行っています。 メモリ確保に失敗なら、まだ分かるのですが、 ちょっと理由がわかりません。 reallocを複数繰り返していることも問題だと思いますが、 まずは正常に処理を流したいと考えています。 よろしくお願いします。 ~~~~~~ソース~~~~~~~~ //ファイルを読み込んでから領域を確保する #include <stdio.h> #include <string.h> #include <stdlib.h> #define BUFF 100 int main() { FILE *fp; char tmp[BUFF+1]; char *str; int len = 0; fp = fopen( "c:/test.txt" , "rb" ); if(fp ==0){ printf("ファイルがありません\n"); return -1; } //領域を初期化 str = (char *)malloc(1); memset(str,'\0',sizeof(str)); while(feof(fp)==0){ memset(tmp,'\0',sizeof(tmp)); fgets(tmp,BUFF,fp); //領域を再確保 len += BUFF+1; if(NULL == ((char *)realloc(str,len))){ printf("メモリ確保エラー"); } //読み込んだ値を変数に追加 strcat(str,tmp); } printf("文字列\n\n%s\n",str); printf("長さ:%d\n",len); fclose(fp); return 0; }

  • C言語 strtok

    失礼します。現在こちらでアドバイスを頂きfgetcを使用して配列に格納をすることができたのですが、CSVをカンマ区切りで格納したいのですが上手くいかず困っています。strtokを使用方法をドキュメントを読んでもうまく区切ったものを配列に入れる方法がわかりません 何卒よろしくお願いします。 ソースコード #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include<string.h> #define MAXITEM 1400 int split(char *str, const char *delim, char *outlist[]) { char *tk; int cnt = 0; tk = strtok(str, delim); while (tk != NULL && cnt < MAXITEM) { outlist[cnt++] = tk; tk = strtok(NULL, delim); } return cnt; } int main(void) { FILE *fp; char *fname = "testfile.csv"; char *tp; char *array[1400]; char *test[11][1400]; char c; int i = 0; int n,y; char *tp[1400]; fp = fopen(fname, "r"); if (fp == NULL) { printf("%sファイルが開けません¥n", fname); return -1; } while ((c = fgetc(fp)) != EOF) { array[i] = (char)c; i++; } tp = strtok(array, ","); puts(*tp); while (tp != NULL) { tp = strtok(NULL, ","); if (tp != NULL)puts(tp); } for (n = 0; n < 11; n++) { for (y = 0; y < 1400; y++) { test[n][y] = tp[y]; printf("%c", test[n][y]); } } fclose(fp); return 0; }

  • realloc

    reallocの使いかたに関してです。 #include <stdio.h> #include <stdlib.h> main () { int narray[5]; int *pn, *pn2; pn=narray; printf("%p <=> ",pn); printf("%p\n",narray); memset(pn,0,sizeof(int)*5); if((pn2 = (int *)realloc(pn, sizeof(narray)*2))==NULL){ printf("error"); exit(0); } pn=pn2; memset(pn,0,sizeof(int)*5*2); printf("realloc!\n"); return(0); } この記述はどこかまちがっているでしょうか? 最初の配列のサイズを2倍に増やすというだけのぷろぐらむなのですが。 どうもreallocの場所でセグメンテーションフォルトになります。

  • malloc関数(strtok関数の自作版)につきまして分からないこと

    malloc関数(strtok関数の自作版)につきまして分からないことがあります。 以下のプログラムにmallo関数がフリーする最適な位置を明示しなさいといわれました。 文字が分離した時にfreeすると助言されたのですが いまいち理解できません・・・。 条件式の中で使用するともいわれていました。(おそらくif文・・・。) 色んな意見を参考にしたいので詳しい方助言のほうよろしくおねがいします。 なおプログラムはほかの箇所を変更したり、他の場所でもmalloc関数を使用することが認められています。 またfreeする場所はメイン関数ではなくあくまでもstrtok関数の中で宣言するようです。 よろしくお願いします。 #include <string.h> #include <stdio.h> #include <stdlib.h> main(){ char* s2 = ",/"; char* result; char* r1; char* r2; char* r3; char* r4; result = strtok("//123//,45/,678,9/","/,"); r1 = strtok(NULL, s2); r2 = strtok(NULL, s2); r3 = strtok(NULL, s2); r4 = strtok(NULL, s2); printf("%s\n",result); printf("%s\n",r1); printf("%s\n",r2); printf("%s\n",r3); printf("%s\n",r4); return; } char *strtok(char *s1, const char *s2) { int i,len; char *str1, *str2 , *str3; static char *tok ; static char* mstr; if(s1 != NULL) { str1 = s1; } else { str1 = tok; } str2 = str1 + strspn(str1, s2); /* strspnを利用 */ if (*str2 == '\0') { return (NULL); } len = 1; i = 0; while(*(str2 + i) != '\0'){ len++; i++; } mstr = (char*)malloc(sizeof(char)*len); if(mstr == (NULL)) { return 0; } i = 0; while(*(str2 + i) != '\0'){ *(mstr + i) = *(str2 + i ); i++; } *(mstr + i ) = '\0'; str3 = mstr + strcspn(mstr, s2); /* strcspnを利用 */ if (*str3 != '\0'){ *str3 = '\0'; str3 = str3 + 1; } tok = str3; return (mstr); }

  • ネットで落ちていた「Excelで作ったデータ(CSVファイル)の読み込

    ネットで落ちていた「Excelで作ったデータ(CSVファイル)の読み込みプログラム」をそのままコンパイルして実行しようと思ったのですが、 sample.c: In function 'main': sample2.c:9: warning: return type of 'main' is not 'int' と、表示されてしまいます。 プログラミング初心者なので、どこが間違っているのかわかりません。 回答またはアドバイスの程、よろしくお願いいたします。 ネットで落ちていたプログラムを以下に記載します。 sample2.c #include <stdio.h> #define MAX_ITEM_SIZE 100 #define MAX_LINE_SIZE 1024 char *GetCSVItem(char *wp, char *buff, int size); void main(int argc, char *argv[]) { FILE *fp; char buff[MAX_LINE_SIZE], *wp, item[3][MAX_ITEM_SIZE]; int i1, len; if(argc != 2){ printf("コマンドの入力形式が間違っています.\n"); return; } fp = fopen(argv[1], "r"); if(fp == NULL){ printf("ファイルがオープンできません[%s].\n", argv[1]); return; } for(;;){ if(fgets(buff, MAX_LINE_SIZE, fp) == NULL) break; len = strlen(buff); if(len == 0 || buff[len-1] != '\n'){ if(feof(fp) == 0){ printf("データが不正です[%s].\n", buff); return; } } buff[len-1] = '\0'; wp = buff; if((wp = GetCSVItem(wp, item[0], MAX_ITEM_SIZE)) == NULL){ printf("エラー(1)\n"); break; } if((wp = GetCSVItem(wp, item[1], MAX_ITEM_SIZE)) == NULL){ printf("エラー(2)\n"); break; } if((wp = GetCSVItem(wp, item[2], MAX_ITEM_SIZE)) == NULL){ printf("エラー(3)\n"); break; } if(*wp != '\0'){ printf("エラー(4)\n"); break; } for(i1 = 0; i1 < 3; i1++){ printf("%d:%s\n", i1+1, item[i1]); } } fclose(fp); } char *GetCSVItem(char *wp, char *buff, int size) { int i1; buff[0] = '\0'; while(*wp == ' ' || *wp == '\t') wp++; if(*wp == '\0'){ return(NULL); } for(i1 = 0; i1 < MAX_ITEM_SIZE; i1++, wp++){ if(i1 >= size) return(NULL); buff[i1] = *wp; if(*wp == '\0'){ buff[i1] = '\0'; return(wp); } if(*wp == ','){ wp++; buff[i1] = '\0'; break; } } return(wp); }

  • cygwinを使ってcsvファイルを読み込み、出力させようとしています

    cygwinを使ってcsvファイルを読み込み、出力させようとしています。 とりあえず、読み込みのみのプログラムを作成し、 実行させてみたのですが(run ファイル名.csv と入力) 「Error: could not start C:\cygwin\home\ユーザー名ファイル名.csv」 と出力され、読み込みができず、困っています。 プログラム初心者です。 恐縮ですがご回答よろしくお願いします。 以下に、読み込みプログラムとcsvファイルを記載します。 (プログラムは拾い物です。) <プログラム> #include <stdio.h> #define MAX_ITEM_SIZE 100 #define MAX_LINE_SIZE 1024 char *GetCSVItem(char *wp, char *buff, int size); void main(int argc, char *argv[]) { FILE *fp; char buff[MAX_LINE_SIZE], *wp, item[3][MAX_ITEM_SIZE]; int i1, len; if(argc != 2){ printf("comand error nyuuryoku keishiki\n"); return; } fp = fopen(argv[1], "r"); if(fp == NULL){ printf("can not open file[%s].\n", argv[1]); return; } for(;;){ if(fgets(buff, MAX_LINE_SIZE, fp) == NULL) break; len = strlen(buff); if(len == 0 || buff[len-1] != '\n'){ if(feof(fp) == 0){ printf("data error[%s].\n", buff); return; } } buff[len-1] = '\0'; wp = buff; if((wp = GetCSVItem(wp, item[0], MAX_ITEM_SIZE)) == NULL){ printf("error(1)\n"); break; } if((wp = GetCSVItem(wp, item[1], MAX_ITEM_SIZE)) == NULL){ printf("error(2)\n"); break; } if((wp = GetCSVItem(wp, item[2], MAX_ITEM_SIZE)) == NULL){ printf("error(3)\n"); break; } if(*wp != '\0'){ printf("error(4)\n"); break; } for(i1 = 0; i1 < 3; i1++){ printf("%d:%s\n", i1+1, item[i1]); } } fclose(fp); } char *GetCSVItem(char *wp, char *buff, int size) { int i1; buff[0] = '\0'; while(*wp == ' ' || *wp == '\t') wp++; if(*wp == '\0'){ return(NULL); } for(i1 = 0; i1 < MAX_ITEM_SIZE; i1++, wp++){ if(i1 >= size) return(NULL); buff[i1] = *wp; if(*wp == '\0'){ buff[i1] = '\0'; return(wp); } if(*wp == ','){ wp++; buff[i1] = '\0'; break; } } return(wp); } <csvファイル> 1,2,3 11,12,13 21,22,23

  • 漢字を配列に入れたいのですが

    漢字を配列に入れたいのですが、うまくいきません。 3列、60行のcsvファイルを読み込んで配列に入れようをしているのですが、1列目、2列目、3列目にある漢字をそれぞれ配列に入れようとしているのですが、出力するとうまくいかないんです。誰か教えてください。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXBUFFSIZE 256 #define MAXWORDS 15 int split(char* words[], int length, char* split_ch,char* str){ int i,j; for(i=0;i<length;i++){ if((words[i] = strtok(str,split_ch))==NULL)break; str=NULL; } return(i); } int main(int argc, char* argv[]){ if(argc !=2){ printf("入力エラー"); return(0); } FILE *fp; char *ll, *words[MAXWORDS], ch, buff[MAXBUFFSIZE]; int i,j; unsigned int data1[60], data2[60], data3[60]; if((fp =fopen(argv[1],"r"))==NULL){ printf("ファイルが開けません。\n"); } j=0; ll= fgets(buff,MAXBUFFSIZE,fp); while((ll= fgets(buff,MAXBUFFSIZE,fp)) != NULL){ split(words, MAXWORDS, ",",ll); data1[j] = words[0]; data2[j] = words[1]; data3[j] = words[2]; j++; } printf("%s\n%s\n%s\n", data1,data2,data3); }

  • reallocでうまくメモリを拡張出来ていない?気がしますが・・・

    OS:WindowsXP SP3 コンパイラ:Visual C++ 2008Express Edition with Service Pack 1 質問なんですが、 ttp://homepage3.nifty.com/mmgames/c_guide/ ↑こちらの練習問題19の3-1なんですが、4人以上のデータを入力して showdata関数で表示させると4人目からのデータが入力したデータと 違います。 (reallocのところが間違っているような気がするのですが?です) どなたかアドバイスお願いします。 他の問題点も良ければアドバイス頂けると幸いです。 *******************以下自分で書いたソース******************** #include <stdio.h> #include <stdlib.h> //構造体 typedef struct { char name[64]; int age; int sex; } stat; //プロトタイプ宣言 int status(stat * ,int *); void showdata(stat *, int); int main() { int cnt, max = 3; //構造体ポインタの宣言 stat *data; //動的配列の宣言 data = (stat *)malloc(sizeof(stat) * max); if ( data == NULL ) { exit(0); } //入力用関数の呼び出し cnt = status(data, &max); //出力用関数の呼び出し showdata(data, cnt); //メモリの開放 free(data); return 0; } int status(stat *data, int *max) { int i = 0; //年齢に-1が入力されるまでループ do { if ( (i + 1) > (*max) ) { *max += 10; data = (stat *)realloc(data, sizeof(stat) * (*max) ); if ( data == NULL ) { exit(0); } } printf("名前入力:"); scanf("%63s", data[i].name); getchar(); fflush(stdin); printf("年齢入力(-1入力で入力終了):"); scanf("%d", &data[i].age); getchar(); //1か2でない場合再入力 do { printf("性別を入力(1.男性 2.女性) <1 or 2>:"); scanf("%d", &data[i].sex); getchar(); if ( (data[i].sex < 1) || (data[i].sex > 2) ) { data[i].sex = 3; printf("1か2で入力してください\n"); } } while ( (data[i].sex) == 3 ); i++; } while ( (data[i-1].age) != -1 ); return i - 1; } void showdata(stat *data, int cnt) { int i; for ( i = 0; i < cnt; i++ ) { printf("\n%d人目のデータ\n", i + 1); printf("名前:%s\n", data[i].name); printf("年齢:%d\n", data[i].age); if ( data[i].sex == 1 ) { printf("性別:男性\n"); } else { printf("性別:女性\n"); } } return; }

  • reallocの断片化対策について

    初めにお断りしておきたい事があります。 出先で緊急な事でしたので、今即興で書いたソースになります。 Cコンパイル環境が有りませんでしたので、動作確認がとれておりません。 その為、ケアレスミス等有るかもしれませんがご容赦願います。 例として標準入力より文字列を取得する処理を記述しました。 以下の処理でreallocの際の断片化対策となるでしょうか。 (最終的に*strにセットされている領域が断片化されていない事) 実際の処理では1行辺り0~30000文字程の可変長の文字列を読み込む事を想定しております。 C(windows)のみ可でC++は不可になります。 その他、冗長な記述等指摘が有りましたらよろしくお願い致します。 #define MAX_BUF_SIZE 128 int getText(char **str) { char *buf[MAX_BUF_SIZE]; char *tmp = NULL; int tmpsize = 0; if ((tmp = (char*) malloc(1)) == NULL) { return FALSE; } *tmp = '\0'; while (fgets(buf, MAX_BUF_SIZE, stdin) != NULL) { tmpsize += MAX_BUF_SIZE; if ((tmp = realloc(tmp, tmpsize)) == NULL) { free(tmp); return FALSE; } strcat(tmp, buf); } if (*str != NULL) { free(*str); } if (*str = (char*) malloc(strlen(tmp) + 1) != NULL) { return FALSE; } strcpy(*str, tmp); free(tmp); return TRUE; }

  • コンパイルエラーの原因がわからず困っています。

    こんばんは。 どなたか以下のプログラム(test4.c)が何故コンパイル出来ないのか教えて頂けませんか。行数は見やすいように一時的につけさせて頂きました。 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<unistd.h> 5 #include<errno.h> 6 #include<signal.h> 7 #include<sys/types.h> 8 9 10 11 12 13 int main(){ 14 FILE *fp,*fp2; 15 char str[1024]; 16 char *tok; 17 char buf[256]; 18 fp = fopen("file.txt","r"); 19 int i = 0; 20 fp2 = fopen("out.txt","a"); 21 22 while((str = fgets(str,1024,fp)) == EOF){ 23 24 while(1){ 25 // 前文を取得 26 tok = strtok(str, "("); 27 printf("%s\n",tok); 28 strcat(buf, tok); 29 30 // 中文を取得 31 tok = strtok(NULL, ")"); 32 if(tok == NULL)break; 33 tok = strtok(NULL, ")"); 34 if(tok == NULL)break; 35 36 *(tok + 1) = '\0'; 37 tok = strtok(NULL, "CEUFRSAP.");//フラグをトークンの材料にする 38 strcat(buf,tok); 39 40 // 後文を取得 41 tok = strtok(NULL, "("); 42 tok = strtok(NULL, ")"); 43 strcat(buf,"tcp "); 44 strcat(buf,tok); 45 break; 46 } 47 printf("%s\n",buf); 48 printf("%d行目です/n",i++); 49 fputs(buf,fp2); 50 } 51 52 printf("合計%d行です\n",i); 53 fclose(fp); 54 fclose(fp2); 55 return 0; 56 } 以下がコンパイルエラーの全文です。 test4.c: In function ‘main’: test4.c:22: error: incompatible types in assignment どんな些細な意見でも結構です。アドバイスをして頂けないでしょうか。どうぞよろしくお願いします。

専門家に質問してみよう