• ベストアンサー

メモリの再確保について

テキストファイルを読込む関数を作成しています。 まず最初にある程度の領域をmalloc()関数で確保し、 読み込む過程で領域が不足すると再割り当てを 行うようにしたいのですが、 エラーが出力されます。 ソース(エラー処理は省略)は次の通りです。 textdata = (char *) malloc (size * sizeof (char)); for (i = 0; !feof (stream); ) { character = fgetc (stream); textdata[i] = character; i++; if ((i % size) == 0) { temp = (char *) malloc (2 * size * sizeof (char)); memcpy (temp, textdata, size * sizeof (char)); free (textdata); textdata = temp; } } 出力されるエラーは次の通りです。 *** glibc detected *** ./lsm: malloc(): memory corruption (fast): 0x09a34198 *** (省略) アボートしました どなたか解決方法を御指導願います。

noname#18852
noname#18852

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

  • ベストアンサー
  • jgk
  • ベストアンサー率75% (104/138)
回答No.1

memcpy以降でsizeを二倍してください。 いまのままだと、常にsizeの初期値*2のメモリしか確保されませんので、sizeの初期値*2以上読み込もうとするとメモリ破壊が起きてしまいます。

noname#18852
質問者

お礼

ありがとうございます。 おっしゃる通りです。 うかつでした(^_^ )>

その他の回答 (1)

  • mac_res
  • ベストアンサー率36% (568/1571)
回答No.2

割り増し量の指定にバグがあるのは#1の方のおっしゃるとおりです。malloc(3)されたメモリーの割り増しにはrealloc(3)を使うと便利です。 -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- #include <stdio.h> #include <errno.h> #include <malloc.h> char *prog; int main(int argc, char *argv[]) { FILE *fin; char *buf; int c; size_t n, size = 8; prog = argv[0]; if (argc < 2) { fprintf(stderr, "Usage: %s filename\n", prog); return(EINVAL); } if((fin = fopen(argv[1], "r")) == NULL) { fprintf(stderr,"Can't open %s\n", argv[1]); return(errno); } if ((buf = malloc(size)) == NULL) { fprintf(stderr,"Can't alloc memory\n"); return(errno); } while ((c = fgetc(fin)) != EOF) { if (n > size) { size *= 2; if ((buf = realloc(buf, size)) == NULL) { fprintf(stderr,"Can't alloc memory\n"); return(errno); } } buf[n++] = c; } printf("%s", buf); return 0; }

noname#18852
質問者

お礼

ありがとうございます。 realloc()関数の存在意義も mac_resさんの例示で 理解できました。

関連するQ&A

  • メモリ動的確保について

    こんにちはです。 メモリの動的確保なのですが、 typedef struct DATA{ char name[256]; char pass[256]; int money; }BANK; void insert(BANK *p,int max); int main(){ int i; size_t st; BANK *person; person = (struct DATA *)malloc(sizeof(struct DATA)); //person = (struct DATA *)malloc(5); if(person == NULL){ printf("確保失敗\n"); exit(-1); } //memset(person,'\0',sizeof(struct DATA)); と、言う風に、記載ソースは途中ですがメモリをとりました。 mallocの後ろの部分ですが、sizeof(struct DATA)と5ではどうちがうのでしょう??2通りともコンパイルエラーはないです。 5は動的に最大5までとるって事はわかるのですが、struct DATAの方はいくつとるのです??いくつもで入力次第です? そして、動的したのにたいしてmemsetしたら実行エラー(コンパイルは通りました)おきました。動的にたいしてmemはダメなのでしょうか? アドバイスいただけたらありがたいです。宜しくお願いいたします。

  • malloc関数によるメモリの確保

    C初心者です。 malloc関数によるメモリの確保に関して教えてください。 2次元配列のサイズに対してmalloc関数の引数値をたとえば、 (double*)malloc(datasize*sizeof(double)) などとしメモリ領域を確保すると、メモリアドレスはデータのサイズ によらず一定 1234044、1234048となります。 データサイズを大きくし、datasize*sizeof(double)が16Kバイトを超えるとcmd.exeがエラーとなり落ちます。 デバックモードで実行すると 「"System.AccessViolationException"のハンドルされていない例外が不明なモジュールです。で発生しました。 追加情報:保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリがこわれていることが考えられます」 というメッセージがでます。 コンパイラはExpressEdition2008です。 この現象を回避するにはどうすべきか、なぜこのようなことが起こるのかご教授ください。 よろしくお願いいたします。

  • C言語 動的なメモリの確保 実行できない

    malloc関数を使いメモリを確保しそこへ"ABCD"と記憶させ、ポインタ*Cを使い確保したメモリの内容を表示するプログラムです。 ********************************************* #include <stdio.h> #include <stdlib.h> int main(void) {   int i;   char *C;   C = (char *) malloc (sizeof(char) * 5);   C = "ABCD";   for(i = 0; i < 5; i++){     if(C[i] != NULL){       printf("%s", C[i]);    ←※エラー※     }   }   free(C);   return 0; } ********************************************* 正常にコンパイルできますが実行エラーになります。VCを使いF10のデバッグテストで※のところエラーになります。なぜなのでしょうか?

  • new と malloc によるメモリの動的確保について

    初めて投稿させて頂きます。よろしくお願い致します。 現在、以下のような、2次元配列による動的なメモリの確保を意図して、コードをC/C++にて記述しています。 (コンパイラはMINGW32のg++ 3.4.5) //mallocによるメモリ動的確保 data = (char **)malloc(num * sizeof(char*)); for(i=0; i<rowNum; i++){ data[i] = (char *)malloc(sizeof(char)*256); } //newによるメモリ動的確保 data = new char*[rowNum]; for(i=0; i<rowNum; i++){ data[i] = new char; } C++で書くのならば、 「mallocによるメモリ確保は辞め、newによるメモリ確保をしなさい」 という指摘が、書籍でもwebでもありましたので、 両方書き、両者を比べているのですが、理由がイマイチ分かりません。 10万行ほどのテキストデータで実験させてみたのですが、 mallocによる記述の方が、動作が数秒速いようなのです。 それで、new やmalloc で実際何をやっているのか、コードを見ようと思ったのですが、 newでは、 void* operator new(std::size_t) throw (std::bad_alloc); void* operator new[](std::size_t) throw (std::bad_alloc); void* operator new(std::size_t, const std::nothrow_t&) throw(); void* operator new[](std::size_t, const std::nothrow_t&) throw(); inline void* operator new(std::size_t, void* __p) throw() { return __p; } inline void* operator new[](std::size_t, void* __p) throw() { return __p; } というnewファイルの記述で行き詰まり、 malloc は malloc_allocator.hというファイルで行き詰りました。 以上を踏まえて、 1)そもそも、上記のメモリ動的確保記述はスマートな書き方なのか 2)実際に、newやmallocは、どういった手法でメモリ領域を確保しているのか 以上の2点について、ご教授下さい。よろしくお願い致します。

  • 2次元配列の動的確保

    ある画像を読み込むため、その画像を格納できる幅、高さを持った配列を動的に確保しようと考えています。 幅をxsize、高さをysizeで次のように記述しました。 unsigned char **src; int i; src = (unsigned char**)malloc(sizeof(unsigned char*) * ysize); src[0] = (unsigned char*)malloc(sizeof(unsigned char) * xsize * ysize); for(i=1; i<ysize; i++) src[i] = (src[0] + i * xsize); わざわざポインタのポインタを使用したのは、動的に確保した配列を2次元的なアクセスをしたかったためです。 画像の読み込み時は fread(src[0], sizeof(unsigned char), xsize * ysize, fp); としています。 上に記述したソースは問題なく動作しました。 しかし、上の場合だと全ての配列を連続して確保することができません。つまりsrcでmallocを一回、src[0]でmallocを一回使っているため、ポインタの配列の直後に配列を確保する保障がありません。そこでいっぺんに確保することを考えました。 unsigned char **src; int i; src = (unsigned char **)malloc(sizeof(unsigned char *) * ysize + sizeof(unsigned char) * xsize * ysize); for(i=0; i<ysize; i++) src[i] = (unsigned char *)(src + sizeof(unsigned char *) * ysize + i * xsize); このように組み上げ、読み込み時は上のfreadと同様に記述したところエラーが出てしまいました。 やはり一行目のmallocで無理やりsizeof(unsigned char *) * ysize + sizeof(unsigned char) * xsize * ysize分確保するのは失敗だったのでしょうか?

  • メモリ領域の確保の仕方

    お世話になります。 メモリ領域の確保の仕方とポインタの動向についての質問です。 呼び出し側の関数testで領域Aを確保する。 関数test内で確保した領域に作業領域Bを加え作業をする。 関数testを抜けるときにreallocで呼び出し側から得た サイズに領域Aを戻す。 このときの動作についてなんですが //呼び出し側 void Main(){   DATA *data_p;//データ構造体   long datacount = 5;//データ数(5はテスト用の可変値   data_p = (DATA*)malloc(sizeof(DATA)*datacount);   test(data_p,datacount);   free((void*)(data_p); } //関数test test(DATA data[],long datacount){   DATA *sagyodata_p;   long a = datacount+5;   sagyodata_p = data;   //作業用に領域を広げる   sagyodata_p = (DATA*)malloc(sizeof(DATA)*a);   //領域サイズを戻す   realloc(((void*)sagyodata_p),sizeof(DATA)*datacount); } としたときに 関数testでdata_pを参照したポインタsagyodata_pの中身は問題ないでしょうか? 現在の実行環境 .NET2003 C++では問題なく動いているようですが。 sagyodata_p = data; sagyodata_p = (DATA*)malloc(sizeof(DATA)*a); とするより、 realloc(((void*)data),sizeof(DATA)*a); としたほうがよいのでしょうか? この2つの違いがどのくらいあるのかお教えいただけたら 助かります。 よろしくお願いします。

  • メモリ領域の確保の仕方

    あまりうまく書けなかったのですがよろしくお願いします。 ファイルから二次配列を読み込むプログラムを作ろうとしました。 /*****行列Aに値を入れる********/ for(i = 0; i < Qap->iN; i++){ for(j = 0; j < Qap->iN; j++){ fscanf(fp, "%d", &Qap->matrixA[i][j]); } } /*****行列Bに値を入れる********/ for(i = 0; i < Qap->iN; i++){ for(j = 0; j < Qap->iN; j++){ fscanf(fp, "%d", &Qap->matrixB[i][j]); } } のように書くために、二次配列の領域を確保しようとしたとき、 #define SIZE 100 //行列のサイズ typedef struct hairetu{ int iN; int matrixA[SIZE][SIZE]; int matrixB[SIZE][SIZE]; }hairetu; としてmatrixA[SIZE][SIZE]のようにした場合は Qap = malloc(sizeof(hairetu));//hairetu分の大きさの領域を確保 とすれば領域を確保できたのですが、 typedef struct hairetu{ int iN; int **matrixA; int **matrixB; }hairetu; のように二次配列を**matrixAと表そうとして、 fscanf(fp, "%d", &Qap->iN); のようにファイルから行列のサイズを読み込もうとした場合、 Qap = malloc(sizeof(hairetu));//hairetu分の大きさの領域を確保 とやってもコンパイルはできるのですがアプリケーションエラーが出てしまいます。 何故だかよくわかりません。 二次配列を**matrixAのように表そうとした場合の領域確保の仕方を教えて下さい。 わかりづらくて本当に申し訳ありませんがお願いします。

  • 画像を読み込む配列の確保。

    C言語について質問です。 画像を読み込む時、その画像の幅、高さを入力し、そのサイズに見合った配列を確保します。その後ファイル名を入力し、配列に読み込むプログラムを作成しました。 メインの部分のみ記述します。 int xsize, ysize, i; unsigned char **src; char filename[30]; FILE *fp; printf("ファイル名を入力してください:"); scanf("%s", filename); printf("画像の幅:");scanf("%d", &xsize); printf("画像の高さ:");scanf("%d", &ysize); src = (unsigned char **)malloc(sizeof(unsigned char *) * ysize); for(i=0; i<ysize; i++) src[i] = (unsigned char *)malloc(sizeof(unsigned char) * xsize); fp = fopen(filename, "rb"); fread(src[0], sizeof(unsigned char), xsize * ysize, fp); このように記述し、エラーもなく実行できたのですが、srcをこのまま出力すると変?な画像となって出力されてしまいました。 上のように記述した場合、矛盾する場所はあるでしょうか? そして、この方法以外に配列を確保する方法はあるでしょうか?

  • C 動的メモリ確保後のファイルへの書き込みについて

    ■プログラムの目的。 入力したデータをCSV形式でファイルに出力。 ■プログラムの問題と質問内容。 realloc関数でメモリを再度割り当てると、入力したデータをファイルに出力できません。 ですが、再度割り当て前に入力処理を終了するとファイルに出力できます。 なんとなく原因は、realloc関数の扱い方の問題であることはわかるんですが どこを修正すればいいのかわかりません。 教えてください。よろしくお願いします。 ■プログラムのソース #include<stdio.h> #include<stdlib.h> #define DATASIZE 3 typedef struct{ char str[10]; }CONS; void Input_data(CONS *data) { gets(data->str); return; } void Output_display(CONS *data) { puts(data->str); return; } void Write_data(CONS *data,int count) { FILE *fp; char fname[]="data.csv"; int i; if( (fp = fopen(fname,"w")) == NULL ){ puts("fopen error"); exit(1); } /* write data */ for(i=0; i<=count; i++){ if(data[i].str[0] == '\0') break; fprintf(fp,"%d,%s\n", i, data[i].str); fprintf(stdout,"%d,%s\n", i, data[i].str); } fclose(fp); return; } int main(void) { CONS *data,*data_temp; int data_size = DATASIZE; int i,count; if( (data=(CONS *)malloc(sizeof(CONS)*DATASIZE)) == NULL){ puts("malloc error"); exit(1); } /* Input data */ puts("-- input_data"); for(i=0; ; i++){ count = i; /* Realloc */ if( count == data_size ){ if( (data_temp=(CONS *)realloc(data,sizeof(CONS)*DATASIZE)) == NULL){ free(data); puts("realloc error"); exit(1); }else{ data = data_temp; data_size += DATASIZE; puts("** realloc"); } } /* end of Realloc */ printf("%2d,",i); Input_data(data+i); if(data[i].str[0] == '\0'){ puts("-- end of input_data\n"); break; } } /* end of Input_data */ /* Output_display */ puts("-- output_display"); for(i=0; i<=count; i++){ printf("%2d,",i); Output_display(data+i); } /* end of Output_display */ /* Write_data */ puts("-- Write_data"); Write_data(data,count); /* end of Write_data */ free(data); return 0; }

  • 「動的確保した2次元配列のメモリ解放」を関数化したい

    質問タイトルの通りですが、 「動的確保した2次元配列のメモリ解放」をC言語で関数化したいと思っています。しかし、関数の引数には動的確保した配列の先頭アドレスのみ渡す形にしたいです。そのような場合の関数化は可能ですか? どうもうまくいかず、困っています。 以下、具体的に、サンプルソースを記述します。 わかる方、よろしくお願いします。 //====================================================// #include<stdio.h> unsigned char** AllocByteArray2d(int column, int row); void FreeByteArray2d(unsigned char** box); int main(voidls){ unsigned char array**; array = AllocByteArray2d(2, 3); FreeByteArray2d(array); return 0; } unsigned char** AllocByteArray2d(int column, int row){ unsigned char* box; box = (unsigned char**)malloc( sizeof(unsigned char*)*column ) int i; for(i=0; i<column; i++){ box[i] = (unsigned char*)calloc( row, sizeof(unsigned char)); if(box[i] == NULL) exit(EXIT_FAILURE); } return box; } //引数では配列の先頭アドレスだけ渡す形にしたい void FreeByteArray2d(unsigned char** box){ //ここをどう書いたらいいかわからない }

専門家に質問してみよう