6

メモリ割り当ての順序について質問があります。次のコードでは、ループに4つの文字列を割り当てます。しかし、アドレスを印刷すると、それらが次々に割り当てられていないように見えます...何か間違ったことをしているのでしょうか、それともバッファオーバーフローを防ぐためにOSによって実装されている何らかの防御メカニズムでしょうか?(私はWindows Vistaを使用しています)。

ありがとうございました。

 char **stringArr;
 int size=4, i;

 stringArr=(char**)malloc(size*sizeof(char*));
 for (i=0; i<size; i++)
    stringArr[i]=(char*)malloc(10*sizeof(char));

 strcpy(stringArr[0], "abcdefgh");
 strcpy(stringArr[1], "good-luck");
 strcpy(stringArr[2], "mully");
 strcpy(stringArr[3], "stam");

 for (i=0; i<size; i++) {
  printf("%s\n", stringArr[i]);
  printf("%d  %u\n\n", &(stringArr[i]), stringArr[i]);
 }

出力:

abcdefgh 9650064 9650128

幸運96500689638624

mully 9650072 9638680

stam 9650076 9638736

4

7 に答える 7

7

通常、を介してメモリを要求するmalloc()と、Cランタイムライブラリは要求のサイズを最小割り当てサイズに切り上げます。これにより、次のことが確実になります。

  • ランタイムライブラリには、簿記情報のための余地があります
  • ランタイムライブラリが、あるサイズ(16バイトなど)のすべての倍数である割り当てられたブロックを管理する方が効率的です。

ただし、これらは実装の詳細であり、の特定の動作に実際に依存することはできませんmalloc()

于 2010-01-24T22:25:56.333 に答える
4

しかし、アドレスを印刷すると、次々に割り当てられていないようです...

それで?

私は何か間違ったことをしていますか、それともバッファオーバーフローの可能性を防ぐためにOSによって実装されたある種の防御メカニズムですか?

おそらく「どちらでもない」。

興味がないのですが、どのアドレスを取得しますか?

于 2010-01-24T22:23:35.010 に答える
4

mallocによって返される値の特定の順序や間隔に依存しないでください。それは神秘的で予測不可能な方法で動作します。

于 2010-01-24T22:24:09.487 に答える
4

通常、一連の時系列の割り当てにより、何らかの形で関連するメモリアドレスが生成されると予想するのが妥当ですが、他の人が指摘しているように、ヒープマネージャの要件ではありません。ただし、この特定のケースでは、断片化ヒープが低い結果が表示されている可能性があります。Windowsは、要求をすばやく満たすことができるメモリの小さなチャンクのリストを保持します。これらは任意の順序にすることができます。

于 2010-01-24T22:53:56.517 に答える
3

連続したアドレスを提供するためにmallocに依存することはできません。それは完全に実装とおそらくヒープの現在の状態次第です。いくつかの実装はそうかもしれませんが、多くはそうしません。

アドレスを連続させる必要がある場合は、メモリの1つの大きなブロックを割り当て、その中のさまざまな領域を指すようにポインタを設定します。

于 2010-01-24T22:56:55.123 に答える
2

他の人が述べているように、malloc()によって割り当てられたメモリブロックをメモリに配置する順序を指定する標準はありません。たとえば、解放されたブロックはヒープ全体に分散させることができ、任意の順序で再利用できます。

しかし、ブロックがたまたま次々になっている場合でも、それらは連続したブロックを形成しない可能性があります。断片化を減らすために、ヒープマネージャーは特定のサイズのブロック(たとえば、2の累乗(64、128、256、512など))のみを割り当てます。したがって、文字列用に10バイトを予約すると、その後に22バイトまたは54バイトの未使用バイトが存在する可能性があります。

メモリオーバーヘッドは、本当に必要でない限り動的メモリ割り当てを使用することが適切でないもう1つの理由です。静的配列を使用するだけの方がはるかに簡単で安全です。

于 2010-01-25T00:09:21.900 に答える
1

によって返されるアドレスを知ることに興味があるので、malloc()それらを正しく印刷していることを確認する必要があります。「適切に」とは、printf()アドレスを印刷するために適切なフォーマット指定子を使用する必要があることを意味します。なぜあなた"%u"はあるものと"%d"別のもののために使っているのですか?

"%p"ポインタの印刷に使用する必要があります。これは、Cでのキャストが必要なまれなケースの1つでもあります。printf()可変個引数関数であるため、コンパイラは、引数として渡すポインタが型である必要があるvoid *かどうかを判断できません。

また、の戻り値をキャストしないでくださいmalloc()

上記を修正すると、プログラムは次のようになります。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char **stringArr;
    int size=4, i;

    stringArr = malloc(size * sizeof *stringArr);

    for (i=0; i < size; i++)
        stringArr[i] = malloc(10 * sizeof *stringArr[i]);

    strcpy(stringArr[0], "abcdefgh");
    strcpy(stringArr[1], "good-luck");
    strcpy(stringArr[2], "mully");
    strcpy(stringArr[3], "stam");

    for (i=0; i<size; i++) {
        printf("%s\n", stringArr[i]);
        printf("%p %p\n", (void *)(&stringArr[i]), (void *)(stringArr[i]));
    }
    return 0;
}

実行すると、次の出力が得られます。

abcdefgh
0x100100080 0x1001000a0
good-luck
0x100100088 0x1001000b0
mully
0x100100090 0x1001000c0
stam
0x100100098 0x1001000d0

私のコンピューターでは、char **ポインターの長さは8バイトなので、&stringArr[i+1]は8バイト大きくなり&stringArr[i]ます。これは標準によって保証されています。スペースがある場合malloc()、そのスペースは隣接しています。4つのポインターにスペースを割り当てましたが、これらの4つのポインターのアドレスは隣り合っています。次のようにすると、それをより明確に確認できます。

printf("%d\n", (int)(&stringArr[1] - &stringArr[0]));

これは1を出力するはずです。

後続malloc()のsについては、それぞれstringArr[i]が別々のから取得されるためmalloc()、実装はそれらに適切なアドレスを自由に割り当てることができます。私の実装では、その特定の実行では、アドレスはすべて0x10バイト離れています。

あなたの実装では、char **ポインタは4バイトの長さのようです。

個々の文字列のアドレスについては、malloc()ある種のランダム化を行っているように見えます(これは許可されています)。

于 2010-01-25T00:55:33.990 に答える