• ベストアンサー

ポインタを引数に渡してメモリ領域をとる

C++でアプリケーションを作っています。 メモリ領域を動的に確保するコードを書いているところなのですが、 int *pr; // ポインタ kakuho(pr,100); // 新たにメモリ領域int100個分確保し、先頭番地をprに返す関数 というコードを作りたいのですが、 kakuho(int *pr,int num){ pr=new int[num]; return; } このようなプログラムを書いてVisual C++.NETでコンパイルすると、コンパイルは成功するのですが、実行時に Run-Time Check Failure #3 - The variable 'pr' is being used without being defined. このメッセージの意図することがよくつかめぬまま、ここで開発が止まっています。 どういう意味なのか、また、解決するにはどのようにしたらよいか教えてください。

noname#129397
noname#129397

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

  • ベストアンサー
  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.5

「変数 'pr' が定義される前に参照されている」と言うエラーです。 kakuho(int *pr,int num){  pr=new int[num];  return; } このように書いた場合、prはグローバル変数ではなく、関数に渡された引数prを初期化しています。そして、引数prは関数を抜けた瞬間に消えて無くなります(つまり、初期化したのが「無かった事」にされる) 「C、C++では、引数は実体渡しされない。一時的な変数が作成され、値が一時変数にコピーされてから関数が呼ばれ、関数から抜けると同時に、引数は自動的に破棄される」と言うのを覚えておいて下さい。 関数内で何かの変数を初期化する(変数に値を設定して来て欲しい)場合は、変数のアドレスを渡す必要があります(変数の実体にアクセスする為の手掛りを渡す) 呼び出し側の int *pr; kakuho(pr,100); では、アドレスが未定義のままのprを引数に渡そうとしているので「変数 'pr' が定義される前に参照されている」と言う事になります。 「引数に渡す=参照」です。「引数に渡す」とは「一時変数を作成して、その一時変数に値をコピーする」と言う事なので、値をコピーしようとして「参照」を行う事になります。 以下のように書き替えて下さい。 int *kakuho(int num); main() {  int *pr;  pr = kakuho(100);  return 0; } int *kakuho(int num) {  return new int[num]; } 以下のような記述でもOKですが、関数からの戻り値を使わない分、無駄が増えます。(こちらの方が、質問者さんが書いたソースコードに近い) void kakuho(int **p,int num); main() {  int *pr;  kakuho(&pr,100);  return 0; } void kakuho(int **p,int num) {  *p = new int[num]; }

noname#129397
質問者

お礼

回答ありがとうございました。サンプル通りにやるとうまくできました。 ところで、kakuho()の中で確保した領域に値を代入するにはどうすればよいのでしょうか? void kakuho(int **p,int num) { *p=new int[num]; *(p+0)=1; // 先頭の領域に1を格納したつもり *(p+1)=2; // 2番目の領域に2を確保したつもり } とすると int *u; kakuho(u,20); // 20個分確保 cout << u[0] << endl; cout << u[1] << endl; とすると、 1 4301832 と、1番目はうまくいっていますがそれ以降がうまくいっていません。 どうすればよいのでしょうか(皆さんの回答を理解しきっていないということになってしまいますが…)

その他の回答 (6)

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.7

void kakuho(int **p,int num) { *p=new int[num]; *(p+0)=1; // 先頭の領域に1を格納したつもり *(p+1)=2; // 2番目の領域に2を確保したつもり } 上記プログラムはメモリを破壊します。 引数pは「intのポインタへのポインタ」ですから *p=new int[num]; (*p)[0]=1; (*p)[1]=2; と書く必要があります。 判りやすく書き直すと void kakuho(int **array_ptr,int num) {  int *array; // 配列の先頭を保持する一時変数  array = new int[num]; // 配列を確保  *array_ptr = array; // 確保アドレスを呼出元に返す  array[0]=1; // 先頭の領域に1を格納 //(*array_ptr)[0]=1;でも同じ  array[1]=2; // 2番目の領域に2を格納 //(*array_ptr)[1]=2;でも同じ } となります。

  • keroro001
  • ベストアンサー率23% (71/304)
回答No.6

あぁ答え書いてる間に回答出てたわ。。。orz じゃあ1つだけ。 mallocは使ってはいかんのですか? ANSIレベルで定義されているし、簡単だと思うのですが・・・

  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.4

変数varの内容を変更する関数であれば、引数に渡すものは変数varへのポインタか変数varの参照である必要があります。 関数kakuhoの中で変数prに何らかの値を設定する、つまり変数prの内容を変更したいのですよね。 > kakuho(pr,100); という文は関数kakuhoに「変数prの値」を渡しいます。これでは変数prの内容は変わりません。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.3

ポインターに確保したメモリのアドレスをセットする為には、以下のようにします。 int *pr; // ポインタ kakuho(pr,100); を kakuho(&pr,100); // pr->&pr kakuho(int *pr,int num){ pr=new int[num]; return; } を kakuho(int **pr,int num){ //*pr -->**pr *pr=new int[num]; //pr --> *pr return; } 上記のように変更して下さい。

回答No.2

/* target を 0 に設定する */ void set0(int target) { target = 0; } int x = 3; set0(x); これでxは0になるでしょうか? なりませんよね。 void set0(int* target) { *target = 0; } int x = 3; set0(&x); これならOK. ポインタについても同様です。 # '*'がひとつ足りないのです。

  • mithsc
  • ベストアンサー率33% (1/3)
回答No.1

その英文は分かりませんが、kakuho(pr,100);した時にprが不定値だからNULLを入れておけばエラーはなくなるんじゃないでしょうか。

関連するQ&A

  • 不正なメモリ領域へのアクセスについて

    C言語では、 確保されていないメモリ領域へアクセスするコードを書いても、コンパイルエラーが出ないので気をつける必要がある。 と言う記述がしばしば出てきます。 だったら、コンパイルエラーがでるように変更すれば良いじゃん。と単純に思ってしまうのですが、エラーが出ないようにしてあるメリットって何か有るのですか?

  • C言語におけるローカル変数が使用するメモリについて

    例のようなC言語のプログラムを動かした場合、 確保されるメモリ領域はどうなるのでしょうか。 例 #include <stdio.h> int main(void) { int a = 0; } このとき、変数aはint型なのでスタック領域に4バイトのメモリが確保されると理解しています。 と同時にaという変数名と確保されたスタック領域の番地を紐づけるようなメモリがどこかに確保されるのではないかと思ってるのですが、この理解で正しいでしょうか。 またその場合は変数aの番地はどの領域に確保されるのでしょうか。 ご教示お願いいたします。

  • VC2005で数値を文字列に変換

    数値を文字列に変換しようとしているのですがうまくいきません。 _itoa(),sprintf()を試したのですが何れもうまくいきません。 _itoa()の場合は, #include <stdlib.h> #include <stdio.h> CString k; int answer = 2; _itoa(answer,k); のようにすると error C2660: '_itoa' : 関数に 2 個の引数を指定できません。 というようなことが表示されます。 sprintf()の場合は、 #include <stdio.h> char* k; int answer = 2; sprintf(k,"%d",answer); のようにするとコンパイルは出来るのですが計算をし始めると、 Run-Time Check Failure #3 - The variable 'k' is being used without being defined. というメッセージボックスが表示されます。 誰か助けてください。

  • ポインタで、実装メモリの先頭から100バイト分参照してみたい

    いつもお世話になります。 Cの質問です。 ポインタの勉強中なのですが、ポインタを用いて、実装メモリの先頭から100バイト分を参照してみたい、と思いました。 先輩が言うには「メモリの先頭領域にはメモリのメーカーとか、文字コードが順番に入ってるよ」とのことなのですが、どうにもプログラムが作れません。 mallocでは、どうやら「コンパイル時にメモリ領域を確保する」らしく、指定したメモリ位置(つまりアドレス0)からxxバイト分確保することはできないようです。 私が試しに書いてみたソースは以下になります。 #include<stdio.h> #include<stdlib.h> int main(void){ int i; char *p; p = (char*)malloc(sizeof(char) * 100); for (i=0;i<100;i++){ printf("%c",*p); p++; } 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; }

  • Run-Time Check Failure #3というエラーが出ます。

    //Run-Time Check Failure #3 - The variable 'Data' is being used without being defined. //というエラーが出ます。どうしたらいいですか? //プログラムの内容は、数値を格納するときに、二分木構造で格納していくというものです。 //多分違うような気がしますが、、 //よろしくお願いします。 #include<stdio.h> struct DATA { DATA *Small; DATA *Large; int Number; }; void InputData(DATA *Dat,int num) { if(Dat==NULL){Dat=new DATA;Dat->Number=num;return;} if(Dat->Number<num) { Dat->Large=new DATA; Dat=Dat->Large; InputData(Dat,num); } else if(Dat->Number>num) { Dat->Small=new DATA; Dat=Dat->Small; InputData(Dat,num); } return; } int main() { DATA *Data; InputData(Data,20);//<-ここでエラーが出ます。 InputData(Data,10); InputData(Data,30); return 0; }

  • 配列ポインタの関数中のメモリ領域

    C初心者です。 関数中で配列ポインタを宣言する場合についての質問です。 たとえばDouble型の2次元のローカルな配列ポインタを用いる場合、 その配列要素数が100である場合は void 関数名(引数1,引数2,...){ int i; double *a[2]; for(i=0;i<2;i++){ a[i] = (double*)malloc(100*sizeof(double)); } for(i=0;i<2;i++){ free(a[i]); } } またこの値を引数1とする場合、引数1をoutとすると void 関数名(double *out,....) とし、 for(i=0;i<2;i++){ out[i] = a[i]; } とすればよいのでしょうか? もしこれがあっているとすると、つぎのような現象で困っています。 配列要素数を50000個ぐらいとし、複数の関数で、同様に mallocを用いて、配列ポインタのローカルでメモリ領域を確保しようとした場合、コンパイルは成功するのですが、その後実行すると、エラーが発生したというメッセージとともにコマンドウィンドが強制終了します。 コンパイラはVisual C++ EXpress Edition 2008です。 データサイズを小さくすると、エラーは起きません。 malloc関数で確保するメモリサイズは、関数の入力引数で定義された変数を用いて計算しており、データサイズに応じて変更されます。 よろしくお願いいたします。

  • システム領域で起こるメモリリーク

    メモリリークを起こしているのはシステム領域で、ユーザ領域は正常です。 処理の概要はディレクトリパスをDBから取得(Pro*C)し、そのディレクトリ内のファイルを削除(remove関数)するです。 Cの関数でシステム領域のメモリを確保するものはあるのでしょうか?ご存知の方がおられるなら回答お願いします。

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

    あまりうまく書けなかったのですがよろしくお願いします。 ファイルから二次配列を読み込むプログラムを作ろうとしました。 /*****行列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のように表そうとした場合の領域確保の仕方を教えて下さい。 わかりづらくて本当に申し訳ありませんがお願いします。

  • VC++でmciSendString

    Visual C++ 2005 Express Editionで以下のコードを書くと Run-Time Check Failure #3 - The variable 'pszReturnString' is being used without being defined. ハンドルされていない例外が発生しました: 0xC0000005: 場所 0xcccccccc に書き込み中にアクセス違反が発生しました。 と出ます。 デバッグ時lpstReturnStringの部分には CXX0030: エラーです: 式を評価できません となっています。引数の型が違っているのでしょうか?原因が分からず困っています・・・。 ----------------- ~クラス宣言(省略)~ Music::Music(std::string fn) : FileName(fn){} PTSTR Music::play() { PTSTR pszReturnString; std::string str = "open " + FileName + " test"; mciSendString((PCTSTR)str.c_str(), pszReturnString, 125, 0); return pszReturnString; } int WINAPI WinMain(・・・) { std::string str = "C:\\test.mp3"; Music test(str); test.play(); }

専門家に質問してみよう