配列の操作やメモリの確保のミスについて

このQ&Aのポイント
  • 配列の操作やメモリの確保でエラーが起きた場合、他のプログラムにも影響を与える可能性があるのか?
  • 配列のメモリを確保している際に要素数以上の値を書き込んだり参照したりすると、想定外のメモリ領域に値が書き込まれる可能性があり、他のプログラムの動作に影響を与えることがある。
  • プログラミング初心者が配列の操作やメモリの確保でミスをすると、OSや他のプログラムにエラーが起きる可能性があるのか不安。
回答を見る
  • ベストアンサー

配列の操作やメモリの確保のミスについて

プログラミング初心者です。 Visal Studio 2010を使用してC++の勉強をしています。 配列の操作やメモリの確保でエラーを起こした場合、OSや他のプログラムにもエラーを引き起こすことがあるのでしょうか? (記述・実行しているプログラムは教材に記されているただのコンソールアプリです。複雑であったり大規模なものではありません。) たとえば、mallocで配列のメモリを確保したが、その配列の要素数以上に値を書き込んだり参照したり、freeをし忘れたりした場合です。 その時、想定していないメモリ領域に値が書き込まれることで、他のプログラムが壊れたりするんじゃないかと心配です。 というのも、配列の操作やmallocを失敗したときに、パソコンの動作が不安定になるのです。(画面がちらついたり、表示がおかしくなる。) explorer.exeを再起動するだけで収まるように見えるのですが、何が起きているのか不思議です。 以上になります。長文お読みいただきありがとうございました。 よろしくお願いいたします。

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

  • ベストアンサー
回答No.1

プログラムの詳細を見ていないので推測ですが、malloc で巨大なメモリ領域を確保した為ではないでしょうか。 > 配列の操作やメモリの確保でエラーを起こした場合、OSや他のプログラムにもエラーを引き起こすことがあるのでしょうか? これは OS にも依存する話ですが、現代のパソコン用の OS (Visual Studio 2010 が動くような最近の Windows も含む) では、他のプログラムに直接エラーを引き起こす事はありません。最近の OS は「仮想メモリ」という仕組みを利用して、プログラム毎に「仮想的なメモリ」を定義しています。例えば、プログラムA から見たアドレス 12345 と、プログラム B から見たアドレス 12345 は、物理的には異なる記憶領域に割り当てられます。(細かい事を無視して書くと、) プログラムAのアドレス空間とプログラムBのアドレス空間は重複がない様に物理的なアドレスに割り当てられるので、プログラムAが暴走して他のプログラムの仮想メモリ空間のデータを書き換えてしまうという事はありえません。あくまでプログラムAが異常動作するだけです。 しかし、他のプログラムに間接的に影響を与える可能性として「物理メモリ」の枯渇があるかと思います。プログラム毎にメモリ空間が分かれていたとしても、それを実際に割り当てる先の記憶領域は一つですので、「全てのプログラムが使っているメモリの総量」に上限があります。従って、特定のプログラムが巨大な領域を malloc したり、領域を free せずに malloc し続けると、やがてメモリの上限に達し、どのプログラムも新しくメモリ領域を確保できない状態になってしまいます。この状態になると、どのプログラムでも malloc (に類する操作) に失敗する危険性が出てきます。 しかし、巨大なメモリ領域を占有していたプログラムが終了すれば、そのプログラムの「仮想メモリ」もろとも OS が解放してくれますので、free をし忘れていても後遺症が残るという事はありません。 > explorer.exeを再起動するだけで収まるように見えるのですが、何が起きているのか不思議です。 しかし、話はもう少し複雑です。簡単化していうと、仮想メモリの割当先は主記憶(RAM, いわゆるメモリ)だけではなくて補助記憶(ハードディスク)の一部もその対象です (先に述べたメモリ総量の「上限」は主記憶の大きさよりも大きいです)。但し、補助記憶に割り当ててしまうと動作が遅いので、通常は主記憶だけにメモリを割り当てるものですから explorer.exe なども軽快に動作します。しかし、使用中のメモリが巨大になってくると補助記憶上の領域を使わざるをえなくなるので、その時に休んでいるプログラム (explorer.exe など) のデータを主記憶から補助記憶上に退避してしまいアドレス割当先を退避先の補助記憶に変更してしまいます。 そして、メモリを占有していたプログラムが終了しても、一旦退避した他のプログラムのメモリは補助記憶に退避されたままです。他のプログラムはメモリにアクセスする為に一旦補助記憶装置に読みに行かなければならないので、直後は動作が遅くなってしまいます(動作が遅いだけでエラーにはならない筈です)。しかしそれも、使っている内に、退避したメモリ領域が徐々に補助記憶から主記憶に復帰されるので、その内に軽くなります。まあ、explorer.exe を再起動してしまえば、「徐々に復帰」ではなく、新しく「一気に主記憶にメモリを割り当てる」のですぐに動作が元に戻るのでしょうね。 (分かりやすさのため厳密でない所もあると思いますが、御容赦下さい)

Mods-Rockers
質問者

お礼

ご回答ありがとうございます。 仰るとおり物理メモリの枯渇が原因だったのかもしれません。 いずれにせよ、他のプログラムに影響を及ぼすことはないのですね。安心してプログラミングできます。 ありがとうございました。

関連するQ&A

  • 2次元配列を確保したいのですが、

    2次元配列を確保したいのですが、 size of array 'buf' is too large というエラーで確保できません。 mallocを使って確保しようとしましたが、コンパイルできましたが、 実行するとメモリ確保に失敗します。 大きな2次元配列を確保する方法を教えてください。

  • アドレス格納のための二次元配列のメモリ動的確保

    アドレス格納のための二次元配列のメモリ動的確保 二次元配列のためにメモリを動的確保しなければならないのですが、 その配列に格納したいものが 「DATA型のポインタ」です。(DATA型はtypedefした構造体です。) プログラム実行中にmallocで確保した、数あるDATA型の構造体の、その先頭アドレスを リストアップするための配列です。 この場合、どのような形でmallocすればよいのでしょうか? 教えていただけるとありがたいです。よろしくお願いいたします。 -- たとえば m×n のint型の配列は、 ◆ int *i; ◆ i = (int *)malloc( m * n * sizeof(int) ); となりますよね。 この要領がでやるのが一般的にわかりやすいものだとするならその方法でやりたい (後発の人が自分のソースコードを読む可能性があるため)のです。 -- 同様にm×nの「DATA型のポインタを格納するための二次元配列」を動的確保したい場合、 ◆ DATA *d; ◆ d = (DATA *)malloc( m * n * sizeof(DATA) ); この文にどのように付け加えたら良いのでしょう? もうあと一歩な気がするのですが(笑)。しかし参考書等で勉強しましたがわかりませんでした・・・。 わかる方、どなたかよろしくお願いいたしますm(_ _)m あとこれだけ通ればコンパイルが通るんです!!!!! たぶん(笑)

  • 2次元配列の動的確保について

    共分散行列を2次元配列に格納しようとしているのですが、 その要素は、左下半分と右上半分が同じになるため 対角要素と、どちらか半分だけを格納してメモリを節約したいと考えています。 以下のように動的確保することでメモリは節約できているでしょうか? if( (a = (double **)malloc(sizeof(double *) * (N) ))==NULL ){ fprintf(stderr, "error malloc for a\n"); exit(0); } for( i=0; i<NN; i++ ){ if( ( a[i] = (double *)malloc(sizeof(double) * (i+1) ))==NULL ){ fprintf(stderr, "error malloc for a\n"); exit(0); } } *節約しない場合は、i+1 が N になります。 確保できているのなら、どのように参照すればいいのでしょうか?データの並び(?)は、a[0][0],a[1][0],a[1][1],a[2][0],a[2][1],a[2][2],,,というように並んでいるでしょうか? 例えば、a[0][1]を参照しようとすると、シグメンテーションフォルトなど起こりうるでしょうか。必要であれば、上プログラム内Nは、3000程度と考えてください。 そして、もし他にメモリを節約する上で良い方法があれば、ご教授していただけたらと思います。 よろしくお願い致します。

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

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

  • 配列のメモリの確保

    先日メモリについてご質問させていただいたものですが、 今ファイルから読み込んだ文字列を配列に格納する作業を行なっています。 今は char buf[1000]; FILE fp; if((fp=fopen("○○.txt","r")) ==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) != NULL){ としてファイルを一行ずつ読み込んでその後単語ごとに配列に組み込みます このときファイルの文字列を格納する配列はbuf[1000]ですが このメモリでは足りないかもしれませんし多すぎるかもしれません。 足りない場合はエラーになるし多すぎる場合はメモリの無駄ですよね。 このような場合はメモリを取り直すべきなのでしょうか?その場合 どのような方法がありますか?調べてもint型の領域確保とかそういうのはあるんですがファイルから読み込んだ文字列の領域確保とかは見つからなかったので教えて下さい。

  • メモリの動的確保(大容量)について

    今640*480の画像を、10枚読み込み、1枚を1行に入れた 2次元配列、10*307200を作りました。これをXとおきます。 この転置行列、307200*10と、Xを掛けて、 307200 * 307200 の行列を作りたいです。 その行列の確保に、 xx = (double (*)[307200])malloc(sizeof(double) * 307200 * 307200); とやったところ、 warning C4307: '*' : 整数定数がオーバーフローしました。 というエラーが出てしまいました。 これって、メモリが確保出来ないっていうエラーですよね? 無知なので教えて頂きたいのですが、 doubleって8バイトなので、この計算だと 8 * 307200 * 307200 = 700G以上のメモリを必要としてしまう。ということでしょうか? そうだとしたら、やっぱり、こんな容量のメモリを確保するのは無謀ですよね。 でも、この計算はしたいのですが、何か方法はありますでしょうか?

  • ポインタ配列の動的確保

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #include<stdio.h> #include<stdlib.h> #define kensu 3 main() { char abc[kensu+1]={'A','B','C','\0'}; char *ptr[kensu]; int i; printf("3つの整数を入力して下さい。\n"); for(i=0;i<kensu;i++){ ptr[i]=(char*)malloc(sizeof(char)*10); if(ptr[i]==NULL){ printf("メモリの取得に失敗しました"); exit(1); } printf("整数%c:",abc[i]); fgets(ptr[i],10,stdin); if(ptr[i][strlen(ptr[i])-1]=='\n') ptr[i][strlen(ptr[i])-1]='\0'; } for(i=0;i<kensu;i++) free(ptr[i]); } ちゃんと動いているようです。 しかし、ポインタ配列の動的確保をネットで調べてみると、ポインタのポインタ(?)を使って、下記のように2度mallocしています。 #include <stdio.h> #include <stdlib.h> #define N 3 int main(void) { char** arr; int i,j; arr = (char**)malloc(N * sizeof(char*)); /* ポインタ配列を確保 */ /* 配列の要素それぞれにつき、メモリ領域を確保 */ for(i=0;i<N;i++) arr[i] = (char*)malloc(N * sizeof(char));   ・・・ ポインタの配列を宣言して、配列の各要素に動的確保するのと ポインタのポインタを宣言し、ポインタ配列を動的確保して、再度配列の要素に動的確保するのとでは、何か違いがあるのでしょうか? ポインタのポインタを宣言し、ポインタ配列を確保する必要性が良く分かっていないのです。 ネット等で調べて見たのですが、理解力がないのかよく分かりませんでした。 どうか教えてください。

  • メモリの確保

    C++で倒立振子のプログラムを書いている者です。 現在、思考回数を500でやらせるために、500の配列を用意してやっているのですが、この思考回数を500以上にすると、コンパイルは通るのですが、実行画面が出てすぐ消えてしまう現象が起こってします。おそらく、メモリが足りないのだと思い、mallocを試してみたのですが同じ現象が起きてしまいましい、どうようにして解決していいのかわかりません。宜しくお願い致します。

  • メモリ破壊で困っています。

    学生です。 現在、cの課題プログラムを作成していて、メモリ破壊と思われる現象で困っています。具体的には、 mallocである構造体へのポインタの3次元配列を確保したはずのものが(malloc時にNULLは返ってきていない)、その後、関係のない関数を呼んだ瞬間にその配列の値が書き換えられている。もしくはアクセスできなくなるといった状況です。 gdbで調べてみたところメモリを確保してから破壊されるまでにfreeはしていません。「関数を呼んだ瞬間に」値が変わるというのは原因がまったくわかりません。 どなたか心当たりある方、ぜひともアドバイスをよろしくお願いします。

  • 配列動的確保

    結論から申しますと,aaa[値1][値2][値3][値4]配列を動的に確保したいのです. unsigned short *****aaa; という方法では確保できるのですが,unsigned short ****aaaとようにしてできるのでしょうか? この他にも違う方法があればご教授ください. どうぞよろしくお願いいたします.

専門家に質問してみよう