構造体をmallocにより動的確保を行っていたのですが、例えば
typedef struct _point{
int x, y;
} point;

point *pelem_point;

pelem_point = (point *)malloc(sizeof(point)*5);

このように、point型の構造体を5つ確保するとします。
しかし、
(pelem_point+100)->x = 1;
(pelem_point+100)->y = 2;

printf("%d\n", (pelem_point+100)->x);
printf("%d\n", (pelem_point+100)->y);

とやったら、確保していない100個先のところも構造体として利用できました。
なぜなのでしょうか。

自分の考えではこのようになりました。
mallocによりヒープ領域から適当な空いているメモリのアドレスが渡されるため、そこからはヒープ領域より先に、限りがあるまで進めてしまうために確保外のサイズにアクセスしても使えてしまっている。
また、mallocにより確保した場合は使用中のラベルがはられるため他に侵されることはないが、先の例のようにmallocによって確保してない場合はいくら使用できたとしても、空いているとコンピュータでは認識されるため、何かヒープ領域を使う場合に勝手に上書きされてしまう可能性がある。

しかし、この考えでも、なぜ確保外の領域が構造体のサイズ分ずつ区切られているのか納得いきません。

わかる方いましたらよろしくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (4件)

> しかし、この考えでも、なぜ確保外の領域が構造体のサイズ分ずつ区切られているのか納得いきません。



#1の回答にに補足します。
int x[10];
とあったとき、x + 3と(char*)(x) + 3は同じ値でしょうか違う値でしょうか?

*(x + 3)とあったら、コンパイラーはxはint型の配列だからということで、xが100だったとして、x + 3は100 + sizeof(int) * 3の値になります。(char*)(x) + 3は100 + sizeof(char)*3の値になります。

確保しているわけではなく、コンパイラーがそう扱うというだけです。確保されているかどうかをコンパイラーは気にしませんし、実行してみるまでそれはわかりません。(配列として確保している場合、コンパイラーによっては警告くらい出しそうですが。)


「何かヒープ領域を使う場合に勝手に上書きされてしまう可能性がある」どころか、ライブラリーが管理のために作っている構造を破壊して、予測不能な動きをさせることもありそうですが。
mallocの動きはmallocの実装によって異なります。
様々なmallocの実装の解説はすでに多数公開されていますからそれらを読んでみてはいかがでしょうか。
http://ja.wikipedia.org/wiki/Malloc

glibc
http://www.slideshare.net/kosaki55tea/glibc-malloc
http://www.valinux.co.jp/technologylibrary/docum …
ソースコード: https://sourceware.org/git/?p=glibc.git;a=tree;f …

tcmalloc
http://goog-perftools.sourceforge.net/doc/tcmall …
ソースコード: https://code.google.com/p/gperftools/source/brow …

jemalloc
https://www.facebook.com/note.php?note_id=480222 …
和訳: http://d.hatena.ne.jp/repeatedly/20110110/129463 …
ソースコード: http://fxr.watson.org/fxr/source/stdlib/malloc.c …
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

具体的な例を挙げてくださったおかげで、理解しやすかったです。ありがとうございます。
もちろんこのようなコードを多分に利用するとかそういったわけではないですが、気になったので質問させていただきました。
まだより深い、内部的な知識は全くないので、どういった実装になっているかなどしっかりと勉強していきたいと思います。
URLまで載せていただき感謝です。

お礼日時:2014/12/07 23:19

malloc じゃなくって, 単純に配列を使っても同じでしょ?

    • good
    • 0
この回答へのお礼

回答ありがとうございます。

確かに配列でも似たようなことが言えました。ただ、配列では要素数を越えた場合エラーが出てくれると思っているのですが、mallocにより確保したポインタではそのようなことが起こらなかったため疑問を持ってしまいました。

お礼日時:2014/12/07 23:26

C/C++ でのポインタについて、少し調べられた方が良いと思います。


ポインタ型は、配列として使えますが、全く別物です。
mallocは、指定のバイト数の領域を確保し、その先頭アドレスを返します。
(構造体 何個分のデータかどうかは、mallocの関与するところではない)
そのアドレスを構造体へのポインタとしてキャストする事で、構造体としての利用が可能となりますが、構造体何個分の領域が確保され、使えるかを管理するのは、完全にプログラマの責任で、セキュリティ上のバッファオーバーフロー問題とかに関係してくる事となります。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

現在大学の課題でプログラムを作っているときにふと生じた疑問でしたが、構造体へのポインタとしてのキャストをしていることによりそういったことが起こっていたんですね。
久しぶりにC言語を扱ったので、再度ポインタについて学び直したいと思います。

お礼日時:2014/12/07 23:23

>なぜ確保外の領域が構造体のサイズ分ずつ区切られているのか納得いきません。



区切られているワケではなく、構造体のサイズからコンパイラがアドレスを「算出」しているだけです。

>mallocによりヒープ領域から適当な空いているメモリのアドレスが渡されるため、そこからはヒープ領域より先に、限りがあるまで進めてしまうために確保外のサイズにアクセスしても使えてしまっている。

管理状態によります。
実際に読み書きする時に仮想アドレスにメモリを割り当てる。
とかの場合は、例外発生して死ぬ可能性もあります。
# OSが例外を受け取って、ライブラリに転送してごにょごにょ…とか、そういう場合もあるかも知れませんが。

いずれにしろ、正しい使い方ではないので何が起こっても文句は言えません。
# 確保された領域外の変数に値を設定したらハードディスクがフォーマットされてしまった。とかなっても。


バッファオーバーランを引き起こす正しいコードではありますけどね。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

Cの勉強はlinuxでやるため、VMwareの仮想環境上で行っているので、ハードが必要以上にフォーマットされることはとりあえず大丈夫だと思っています。

おっしゃるとおり、正しい使い方ではないのでもちろんこれを通すつもりではないですが、たまたま気になってしまって質問してしまいました。
当たり前ですが、実際ではmallocにより確保した分だけを使いたいと思います。

お礼日時:2014/12/07 23:11

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qmallocで確保するメモリの領域を限定する方法

mallocで確保するメモリの領域を限定する方法というものは存在するのでしょうか?

例えば、
mallocを使ってメモリを確保するときに、
アドレス:0x00001000から0x00002000の間でメモリを確保してください。

といった感じです。
宜しくお願いいたします。

Aベストアンサー

特定アドレスのメモリを割り付けるのであれば、静的に割り付けるか、それに近い方法を取らざるをえません。
処理系に依存しない方法はありませんので、処理系を補足してください。

いずれにせよ、取りうる方法は限られています。
ひとつは、リンク時にアドレス指定で配列を割り付ける方法であり、もうひとつは(もし使えるのであれば)MMUを自分で制御して、該当アドレスに仮想メモリを配置する方法です。
ハードウェアの設計も自分でできる(能力的にも権限的にも)のであれば、もっと別の方法があるかもしれません。

Q構造体の領域確保について

以下のソースでコンパイルは出来るのですが、実行時にセグメンテーション違反のエラーが出ます。
------------------------------------------------
struct magicpacket {
char mgc_syn[6];
char mgc_mac[6][12];
} mgcpkt; /* (1) */


int main(int argc, char **argv) {
struct magicpacket *mgc; /* (2) */
char mac[6] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0xff };
make_magic_packet(mgc, mac); /* (3) */
}

void make_magic_packet(struct magicpacket *mgc, const char *macaddr) {
char *cur;
int i, j;
/* 初期シーケンス */
for(i = 0; i < 6; i++) {
mgc->mgc_syn[i] = 0xff;
}
/* MAC ADDRESS部 */
cur = &mgc->mgc_mac[0][0];
for(j = 0; j < 16; j++) {
memcpy(cur, macaddr, 6);
cur += 6;
}
}
------------------------------------------------
(3)の第一引数を&mgcpkt(1)とするか、(3)の前にmgc = malloc(sizeof(struct magicpacket));
を入れると正常に動作します。(2)では正常にメモリ領域が確保されていないのでしょうか?
それとも、他に原因があるのでしょうか。ご教授お願いします。

以下のソースでコンパイルは出来るのですが、実行時にセグメンテーション違反のエラーが出ます。
------------------------------------------------
struct magicpacket {
char mgc_syn[6];
char mgc_mac[6][12];
} mgcpkt; /* (1) */


int main(int argc, char **argv) {
struct magicpacket *mgc; /* (2) */
char mac[6] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0xff };
make_magic_packet(mgc, mac); /* (3) */
}

void make_magic_packet(struct magicpacket *mgc, const char *macaddr) {
char ...続きを読む

Aベストアンサー

> (2)では正常にメモリ領域が確保されていないのでしょうか?

(2)で確保されているのは、
"magicpacket構造体のポインタ変数"
であって、"構造体の実体"がメモリ上に確保されているわけではありません。
単純に書くと、こういうことをやっています。

----------
{
char * cHoge;
*cHoge = 'a';
}
----------
cHogeはどこを指しているか解らないポインタです。
ということは*cHogeに値を代入すると、どこに格納されるか解りません。

Qmalloc、new のメモリ確保について

mallocで確保できる最大メモリ領域と
newで確保できる最大メモリ領域を知りたいです。

ご存知の方、教えて下さい。

Aベストアンサー

> malocで確保出来る最大メモリ領域は決まっていない
> と言うことで宜しいのでしょうか。

決まっていないのではなく、知る方法がないのです。
実装によっては、決まっていない(そのときどきの状況による)場合もあると思います。

> new演算子で、charの配列のメモリ領域を確保しようとする場合
>
> char * buff;
> buff = new char[100000];
>
> も同様に、確保できるメモリ領域は決まっていない
のでしょうか?

この場合、割付けに成功すれば、少なくとも100000バイトを確保できるだけです。実際にどれだけ確保したのか、あるいは同様の割付けをどれだけ行えるかを知る一般的な方法はありません。

Qmalloc関数によるメモリの確保

C初心者です。
malloc関数によるメモリの確保に関して教えてください。

2次元配列のサイズに対してmalloc関数の引数値をたとえば、
(double*)malloc(datasize*sizeof(double))
などとしメモリ領域を確保すると、メモリアドレスはデータのサイズ
によらず一定 1234044、1234048となります。
データサイズを大きくし、datasize*sizeof(double)が16Kバイトを超えるとcmd.exeがエラーとなり落ちます。
デバックモードで実行すると
「"System.AccessViolationException"のハンドルされていない例外が不明なモジュールです。で発生しました。

追加情報:保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリがこわれていることが考えられます」
というメッセージがでます。

コンパイラはExpressEdition2008です。
この現象を回避するにはどうすべきか、なぜこのようなことが起こるのかご教授ください。

よろしくお願いいたします。

C初心者です。
malloc関数によるメモリの確保に関して教えてください。

2次元配列のサイズに対してmalloc関数の引数値をたとえば、
(double*)malloc(datasize*sizeof(double))
などとしメモリ領域を確保すると、メモリアドレスはデータのサイズ
によらず一定 1234044、1234048となります。
データサイズを大きくし、datasize*sizeof(double)が16Kバイトを超えるとcmd.exeがエラーとなり落ちます。
デバックモードで実行すると
「"System.AccessViolationException"のハンドルされていない例外が不明...続きを読む

Aベストアンサー

質問の意味が今ひとつ解らないのですが、
for(k=0;k<len1/8;k++){

for(i=0;i<8;i++){

*(in+i+8*k)=data[i];

}

}

の部分で、in配列は
int in[2000];
なのに、
*(in+i+8*k)
のkの最大値は(len1/8-1)です。len1は
int len1=10000;
なので、in配列の後のメモリを破壊してしまいます。

Qmallocで char *型の配列を確保したい

char *方の配列を動的確保する必要が出たのですが、

char **array=(char **)malloc((char *) * 10);
としてうまくいきません
どうすれば確保できるのでしょうか
知っている方がいましたら教えてください

ちなみに確保した配列はこの様に使えるようにしたいです
strcpy(array[0],"testest");

Aベストアンサー

char **array = (char**)malloc(sizeof(char*) * 10);
↑の一行はokだけど、これはアドレスを格納する箱を10個用意するだけですよ。
なので実際に使うときは、箱の中のエリアを確保せねばなりません。
array[0] = (char*)malloc(256);
strcpy(array[0], "testtest");
これはarray[1]~array[9]もすべて同じ。
もちろんmallocで確保したメモリはfreeで解放するのも忘れずに。
free(array[0]);
;
free(array[9]);
free(array);


人気Q&Aランキング

おすすめ情報