HeapReAllocについて質問 VC++5.0 & SDKで作成

このQ&Aのポイント
  • HeapReAllocを使用してメモリを再割り当てし、HEAP_REALLOC_IN_PLACE_ONLYを指定していますが、必ず決まった回数で失敗してしまいます
  • リサイズに失敗した場合、新たに領域を確保しデータをコピーするのが普通なのか疑問です
  • メモリ移動せずに取れるだけの領域がなくて失敗しているのか、または間違った方法で実装しているのかがわかりません
回答を見る
  • ベストアンサー

HeapReAllocについて

HeapReAllocについて質問いたします VC++5.0 & SDK で作成しています 以下のようにメモリを確保し、その後メモリの移動が起こらないように HEAP_REALLOC_IN_PLACE_ONLYを指定してHeapReAllocしています 必ず決まった回数でHeapReAllocが失敗してしまいます やはり下のようにリサイズに失敗したら新たに領域を確保し それまでのデータをコピーするのが普通なのでしょうか? ただ単にメモリを移動せずに取れるだけの領域がなくて失敗しているだけならば いいのですが、それほど大きいサイズでもないし、根本的に間違っているなら 解決にならないと思いまして質問させていただきます よろしくお願いいたします time_t *endtime; time_t *tmptime; if ((endtime = (time_t *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(time_t) * tile_cnt)) == NULL) {  return 0; } while( tile_cnt < 30 ){  tile_cnt++;  // リサイズ  if((tmptime = (time_t *)HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, endtime,                        tile_cnt*sizeof(time_t))) == NULL){   // サイズ拡大できなかったので再度そのサイズで領域確保   if ((tmptime = (time_t *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(time_t) * tile_cnt))                        == NULL) {    HeapFree(GetProcessHeap(), 0, endtime);    return 0;   } else {    // 新しく領域を確保したので今までのデータをコピー    CopyMemory(tmptime, endtime, sizeof(time_t)*(tile_cnt-1));    // 元の領域を開放    HeapFree(GetProcessHeap(), 0, endtime);    endtime = tmptime;   }  } else {   endtime = tmptime;  } } //解放 HeapFree(GetProcessHeap(), 0, endtime);

  • be-be
  • お礼率70% (39/55)

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

  • ベストアンサー
  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1

>やはり下のようにリサイズに失敗したら新たに領域を確保し >それまでのデータをコピーするのが普通なのでしょうか? 移動可能にするのが普通だと思うのですが。 移動可能にできない理由は何でしょうか? 結局自分で再確保してコピーをするのであれば、移動可能にしておくのと同じだと思うのですが。

be-be
質問者

お礼

すみません 補足の欄に書いてしまいました 大きな勘違いをしていました HeapReAllocはメモリの移動が起こっても、データの内容は消えないのすね VBのReDimのイメージがあったもので、行動してしまいました どうもありがとうございました

be-be
質問者

補足

移動可能にできない理由はそれまでに、代入したデータの値を変えたくないからです。 >結局自分で再確保してコピーをするのであれば、移動可能にしておくのと同じだと思うのですが。 それは確かにそうですね。移動可能にしてコピーが普通ですか?

関連するQ&A

  • 多次元配列を動的に取る方法で悩んでいます。

    現在、以下のコードで三次元配列を動的に取る方法を作成しています。 { int i,j; char ***Regdata; LPVOID heapAdr; Regdata = (char ***)HeapAlloc(GetProcessHeap(),HEAP_NO_SERIALIZE,sizeof(char) * 1000); for(i=0;i<=1000;i++){ heapAdr = HeapAlloc(GetProcessHeap(), //ここでエラーが発生します。 HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, sizeof(char) * 6); if(heapAdr != NULL) { Regdata[i] = (char **)heapAdr; for(j=0;j<=6;j++){ heapAdr = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, sizeof(char) * STRING_LENGTH); if(heapAdr != NULL) { Regdata[i][j] = (char *)heapAdr; } else { break; } } } else { break; } } } この方法だと、約40~50回ループした時点でHeapAlloc関数のところで 実行時エラーが発生してしまいます。 GetLastError関数を用いてエラーメッセージを取得したところ、 「No 998:メモリの場所に無効なアクセスがありました。」 というメッセージが返ってきました。 現状、どうしたらよいのかわからない状態です。 ご存知の方がいらっしゃれば、お教えいただきたいです。 以上、宜しくお願いします。

  • 配列の動的確保

    No.847223 reallocについて No.847300 ポインタについて と質問させてもらい、御回答をいただき、理解した(つもりな)のですが、以下のことが実現できなくこまっております。 (以前の質問はこれを実現するために質問しました。) まず配列array[1][20]を用意します(つまり文字列最高20字格納できる要素数1個の配列を用意)。 そして動的にこの配列のサイズを変更して、なにか文字列を入力する毎に、代入するスペースを逐次確保したいわけです。(メモリが溢れない限りスペースを確保しまくる) そこでcallocやreallocの記述の仕方に困っています。 まず、callocについて char array[1][20]; char *pn, *pn2; pn = (char *)calloc(sizeof(array)/sizeof(char),sizeof(char)); このボイドポインタをキャストする部分にchar* と char** のどちらを使えばいいか、です。 そしてreallocについて、 if( (pn2 = (char *)realloc(pn, sizeof(array)*cnt)) == NULL ){ printf("メモリの確保失敗!\n"); exit(0); } pn=pn2; strcpy(pn[cnt],input); 【ただし、cntは毎回1づつ増加する。】 【inputはchar型の配列で、なんらかの文字列がはいっている。】 としているのですが、これもキャストの仕方がわかりませんし、strcpyで、セグメンテーションフォルトになります。構造体を使ったリスト形式も考えたのですが、reallocの使いかたを覚えたいのであえてこの形式で実現しようとしています。 結局どうしたいかというと、realloc部をforループさせて、cntを1ずつ増加させ、 pn[1][20] つぎは pn[2][20] つぎは pn[3][20] とどんどん増やしていきたいわけデス。 すこしわかりにくい説明だとおもいますが、不明点や、言い回しがオカシイ箇所があればご指摘下さい。

  • 文字を格納できる限界を超えてもエラーにならない

    こんにちは。今回、以下のコードを作成して、動的にメモリを確保しようとしています。使用しているのはVisual C++ 2008のC言語で、C99等と言った規格に準拠しているかどうかは不明です。 これは、まずメモリをmallocEx(内部でmalloc)で確保して文字を代入、それをさらにrealloc(内部でrealloc)で領域を増やして文字を追加、最後に出力してfree(内部でfree)する、というコードで、コードに直接矢印で示してありますが、わざとエラーの発生するコードを組み込んであるのですが、これが何の問題もなく処理されてしまいます。また、reallocExを実行すると、代入したイが不定のデータに変わってしまうようで、その後ロを代入するとイが消えてしまいます。 唯一正常に動くものは、freeExを実行後のポインタに代入しようとすると例外として処理されるところだけです。 ポインタを参照渡し等にしてもう少しコードをすっきりさせようとしていたのですが、結局メモリ操作がうまくいっていなかったようなので、freeEx関数以外は戻り値で戻すという形に戻しました。 ------------------ 実行するコード ------------------ char *test; test = mallocEx( 1 * sizeof(char) ); ←エラーが発生するか確かめるために要素は1つだけ確保 strcpy( test,"イ" ); ←要素を1つしか確保していないのに2バイトの文字でエラーなし printf("%s\n", test); test = reallocEx( test, (4 + 1) * sizeof(char)); strcpy( test,"ロ" ); ←これを実行すると、前回代入したイが消える printf("%s\n", test); freeEx(&test); //strcpy( test,"イロハ" ); ←これは例外処理で受け付けられない(正常) keywait(); return 0; ------------------ 使用する関数 ------------------ void *mallocEx( size_t nSize ) { void *tmp; /* malloc関数で割り当てたメモリへのポインタ */ tmp = malloc( nSize ); /* メモリを割り当てる */ /* メモリ割り当てに失敗した場合の処理 */ if( tmp == NULL ) { printf( "\a\n<!> mallocEx関数内、malloc関数のエラー:\nメモリが不足しています。指定された数のメモリブロックが確保できませんでした。\n" ); return NULL; /* 生成失敗 */ } return tmp; /* 生成成功 */ } void *reallocEx( void *ptr, size_t nSize ) { void *tmp; /* realloc関数で割り当てたメモリへのポインタ(安全確認用) */ /* ポインタを生成する型を判定する */ tmp = realloc( ptr, nSize ); /* メモリを再度割り当てる(安全のため(=NULLに備えて)内部ポインタ変数tmpで取得) */ /* メモリの再割り当てに失敗した場合の処理 */ if( tmp == NULL ) { printf( "\a\n<!> reallocEx関数内、realloc関数のエラー:\nメモリが不足しています。指定された数のメモリブロックが確保できませんでした。\n" ); return NULL; /* 再割り当て失敗 */ } return tmp; /* 再割り当て成功 */ } void freeEx( void **ptr ) { if( *ptr != NULL ) { free( *ptr ); *ptr = NULL; } }

  • 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; }

  • 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

  • newを使った領域の動的確保

    お世話になります。 C++での記述方法なのですが 構造体Testの領域を確保しておいて値を入れます。 確保しておいた領域では領域が不足するときに 不足分を追加したいのですがどうすればよいでしょう? Cではreallocを使えばよいと思うのですが C++ではmallocではなくnewを使ったほうがよいと聞きました。 newした領域を再定義した場合(deleteせずに領域を追加) 先に領域に入れたデータは保証されるのでしょうか? 以下例文ソース*部分 以下例文のソース Test *a; a = new TEST[10]; int cnt; int i; for(i = 0;i<10;i++){  //ここでTESTの配列aに値を入れる } cnt = 12; if( cnt > 10 ){  //予想サイズを上回ったら足りない分のサイズの領域を確保し  //データを入れる  a = new[cnt];//*ここで領域を再確保したら元のa[0]~a[9]の         //データは確実に保持されるのか?         //または他に領域を確保する方法があるのか? } 上記例文ソースでは先にcntで領域を確保すれば良いようにみえますが やりたいことは 先に確保されている領域を広げて 先に入れてあったデータと、広げた領域に入れたデータを使いたい のです。 分かりにくい文章かもしれませんがよろしくお願いします。

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

    お世話になります。 メモリ領域の確保の仕方とポインタの動向についての質問です。 呼び出し側の関数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つの違いがどのくらいあるのかお教えいただけたら 助かります。 よろしくお願いします。

  • 関数にポインタを渡して動的確保する時について

    どうにも動的確保について間違っている気がするのでお尋ねいたします。 よくメモリを動的に確保する場合に私は次のようなプログラムを書きます ポインタを用意する(例えばint *p) mallocでメモリ確保 ポインタを関数に渡す(Func(p)) 関数側でreallocし、値を代入する(p=(int *)realloc(p,sizeof(int)*num)) 関数呼び出し側で、その値を使う しかし、この方法を使うとどうにも関数を呼び出した際のポインタ(p)と、reallocした後のポインタ(p)の値が違うことがあり、値が不定になることがあります。 (reallocのメモリの確保の仕方のせいでしょうか) この使い方は恐らくどこか間違っていると思うんですが、いまいち納得のいく解決策が思いつきません。 例えばポインタを引数ではなく戻り値として得ればできますが、2つ以上のポインタについてはできません。 何卒ご教授のほどをよろしくお願いいたします。

  • htmlソースを一文字ずつ取得するには・・

    私は猫でもわかるネットワークプログラミングをよんでふと思ったのですが・ HTMLソースを空白行も含め縦に並べたいのです たとえば・・ < h t m l > ってな感じで・・ つまりは printf("%s(%cでも・・)",一文字); ってな感じにしたいのです・・ 一応作りかけのソース張っておきます。。。。 wininet使ってます・・ //省略 //インターネット(wininet)開始 hInet = InternetOpen("ユーザー名収集プロトタイプ",INTERNET_OPEN_TYPE_PRECONFIG, NULL,NULL,0); hUrl = InternetOpenUrl(hInet,szUrl,NULL,0,0,0); //lpszSrcに1バイトのみ確保 hMem = GlobalAlloc(GHND,1); lpszSrc = (char *)GlobalLock(hMem); //読み出すものがなくなるまで読み出す while(1){ InternetReadFile( hUrl,szBuf,(DWORD)sizeof(szBuf) - 1,&dwRead); szBuf[dwRead] = '\0'; //読み出すものが無くなったらループを脱出 if (dwRead == 0){ break; } //必要バイト数の計算 dwTotal += dwRead; //確保領域の大きさ変更 hMem = GlobalReAlloc(hMem,dwTotal,GMEM_MOVEABLE); if(hMem == NULL){ perror("再アロケート失敗\n"); } lpszSrc = (char *)GlobalLock(hMem); if(lpszSrc == NULL){ perror("メモリ領域確保に失敗\n"); break; } strcat(lpszSrc,szBuf); printf("%s\n",szBuf); } //メモリの開放 GlobalUnlock(hMem); GlobalFree(hMem); //インターネットハンドルの開放 InternetCloseHandle(hUrl); InternetCloseHandle(hInet); return 0; }

  • 動的なメモリ領域の確保

    double型変数5個分のメモリをmalloc関数により確保し,その確保した要素のアドレスを表示するように,プログラムを作る問題で、 (注)に「 %pで表示するためには,double型へのポインタ(double *)をvoid型へのポインタ(void *)にキャストする必要がある.」と書かれていたのですが、どういうことでしょうか? 以下のようでいいのでしょうか? #include<stdio.h> #include<stdlib.h> #define COUNT 5           // 動的に確保するメモリ領域数を示すマクロ定数の定義 int main(void) {  // 動的に確保するメモリ領域のアドレスを保持するポインタ変数の宣言  double * pointer;  int i;                  // for文で使用する変数の宣言  // int型変数5個分のメモリ領域を確保  pointer = (double *)malloc(sizeof(double) * COUNT);  if(pointer == NULL) {        // メモリ領域の確保が失敗した場合   printf("メモリ領域を確保できませんでした.\n");   exit(1);                // プログラムの終了  }  for(i = 0; i < COUNT; i++)   printf("%d番目のアドレスは%pです.\n", i + 1, pointer + i);  free(pointer);            // 確保したメモリ領域の解放  return 0; }

専門家に質問してみよう