10

私はこのコードを持っています

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

int main(){
    void *a, *b;

    a = malloc(16);
    b = malloc(16);
    printf("\n   block size (for a): %p-%p : %li", b, a, b-a);

    a = malloc(1024);
    b = malloc(1024);
    printf("\n   block size (for a): %p-%p : %li", b, a, b-a);  
}

これは、最後に割り当てられたブロック サイズ (16 または 1024) を出力するべきではありませんか? 代わりに 24 と 1032 が出力されるため、割り当てられたメモリの量には 8 バイト余分にあるようです。

私の問題は、(このテスト ケースを作成する前に)malloc()関数 (1024 バイト) で実行し、割り当てられた結果を返すことです。関数の戻り値でブロック サイズを確認すると、516 ブロックが返されます... 理由がわかりません。これが、割り当てられたバッファで何らかの処理を行った後に発生するメモリ破損の理由である可能性があると思います:)

編集: C のポインターから配列のサイズを取得するにはどうすればよいですか? 同じことを尋ねているようです、再投稿してすみません。

例をより具体的なコードに書き直しました。

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

short int * mallocStuff(long int number, short int base){
    short int *array;
    int size=1024;

    array=(short int*)calloc(1,size);
    //array=(short int*)malloc(size);

    return array;
}

int main(){
    short int **translatedArray;

    translatedArray=malloc(4*sizeof(short int));

    int i;
    for(i=0;i<4;i++){
        translatedArray[i]=mallocStuff(0,0);

        if(i>0)
            printf("\n   block size (for a): %p-%p : %i",
                translatedArray[i], translatedArray[i-1], translatedArray[i]-translatedArray[i-1]);
    }

    return 0;
}

そして、出力は

   block size (for a): 0x804a420-0x804a018 : 516
   block size (for a): 0x804a828-0x804a420 : 516
   block size (for a): 0x804ac30-0x804a828 : 516

1024より大きい上記の投稿によると、私は間違っていますか?

4

12 に答える 12

31

まず、Malloc は、2 つの連続する malloc 呼び出しが連続するポインターを返すことを保証しません。

次に、特定のアーキテクチャに応じて、異なるアライメント ルールが適用されます。場合によっては 1 バイトを要求することもありますが、アーキテクチャでは 8 または 4 バイト間隔での割り当てが優先されます。

3 番目に、malloc は、割り当てられたブロックの大きさなどを格納するために、いくらかのオーバーヘッドを必要とします。

ドキュメントに記載されていることを超えて malloc が何をしているのかを推測しないでください。

于 2009-01-09T23:48:53.870 に答える
18

このmalloc関数は、簿記情報を保存するために、常に要求よりもわずかに多く割り当てます。結局のところ、呼び出すときfree()は、ブロックの大きさを知る必要があります。

また、一般に、malloc実装では、要求されたサイズを次の 8 または 16 の倍数、またはその他の丸めっぽい数値に丸めます。

更新:あなたの質問に対する本当の答えは、short int型の使用にあります。型指定されたポインター間でポインター演算 (減算) を行う場合、C と C++ は、ポイントされているもののの差を返します。サイズが 2 バイトの を指しているためshort int、返される値は期待値の半分です。

一方、後で結果を何にキャストしても、malloc常に指定されたバイト数を割り当てます。これを試して:

    array=(short int*)malloc(sizeof(short int) * size);
于 2009-01-09T23:47:20.707 に答える
12

2 つの malloc 呼び出しが正確にまとめられたブロックを返すという保証はありません。実際、結果についての保証はまったくありません。

内部的には、ほとんどの malloc は、ヒープの管理に役立つ作業データを保持しています。たとえば、これらの 8 バイトには 2 つのポインターが含まれる場合があります。1 つは次のブロックを指し、もう 1 つは前のブロックを指します。実行しているOSについて言及していないため、これらの8バイトが何であるかはわかりませんが、mallocが舞台裏でメモリを使用するのは完全に正常です。

一部のアロケーター (Windows など) は、指定されたポインターのブロック サイズを検出するライブラリ関数を提供しますが、かなり難解な機能であるため、そうでないものもあります。

于 2009-01-09T23:49:53.757 に答える
10

バグがあります。それ以外の:

translatedArray=malloc(4*sizeof(short int));

あなたが持っている必要があります

translatedArray=malloc(4*sizeof(short int*));

コード内のポインターが欠落していることに注意してください。これが、あなたの観察された行動の由来であると思います。


0x804a420 - 0x804a018 = 1032ではないことにも注意してください516。この式translatedArray[i] - translatedArray[i - 1]は、バイト数ではなく、2 つのアドレス間の要素(short int、またはより簡単には short) の数を示します。

于 2009-01-10T00:04:29.750 に答える
5

malloc が返すものは、malloc の実装とアーキテクチャによって異なります。他の人がすでに言っているように、要求された量のメモリ、または NULL を取得することが保証されています。これが、配列の末尾を超えて書き込むことができ、セグメンテーション違反が発生しない場合がある理由でもあります。それは、あなたが実際にこのメモリへの有効なアクセス権を持っているためです。あなたはそれを知らなかっただけです.

于 2009-01-09T23:53:14.610 に答える
4

malloc() は通常、利用可能なヒープをさまざまなサイズのチャンクに分割することによって実装されます。あなたの場合、malloc() は 2 つの連続した 1024 (または 16) バイトのチャンクを返します。あなたが言及した8バイトのスペースは、簿記情報のためにmalloc()によって使用されます。

Doug Lea の malloc() impl ノートを参照して、舞台裏で何が起こっているかを理解してください: http://g.oswego.edu/dl/html/malloc.html

于 2009-01-10T00:04:14.573 に答える
3

malloc()独自のオーバーヘッドがあります。

言うまでもなく、2 つの連続した割り当てが最初から隣り合っているという保証はありません。

于 2009-01-09T23:47:31.190 に答える
2

mallocがnull以外を返す場合、プログラムに割り当てられたメモリには、に渡したサイズがありますmalloc。への 2 つの差分呼び出しの戻り値の間のポインターの差分を取ると、malloc任意の値を持つ可能性があり、最初に割り当てられたブロックのブロック サイズとは (ほとんど) 関係がありません。

于 2009-01-09T23:49:46.567 に答える
2

私はこれを見つけました..詳細については、以下のリンクを確認してください。

割り当て

次の式を使用して、最初に要求されたバイトをバケット配列内のインデックスに変換することにより、フリー プールからブロックが割り当てられます。

必要 = 要求された + 8

必要な場合 <= 16、バケット = 0

必要な場合 > 16 の場合、バケット = (log(必要)/log(2) を最も近い整数に切り捨て) - 3

バケットによって固定されたリスト内の各ブロックのサイズは、ブロック サイズ = 2 バケット + 4 です。バケット内のリストがヌルの場合、sbrk サブルーチンを使用してメモリが割り当てられ、ブロックがリストに追加されます。ブロック サイズが 1 ページ未満の場合、sbrk サブルーチンを使用してページが割り当てられ、ブロック サイズをページ サイズに分割することによって得られたブロックの数がリストに追加されます。ブロック サイズが 1 ページ以上の場合、sbrk サブルーチンを使用して必要なメモリが割り当てられ、バケットのフリー リストに 1 つのブロックが追加されます。フリー リストが空でない場合、リストの先頭にあるブロックが呼び出し元に返されます。リストの次のブロックが新しいヘッドになります。

http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.aix.genprogc/doc/genprogc/sys_mem_alloc.htm

于 2009-04-13T04:29:15.140 に答える
1

割り当てられたメモリの量には8バイト余分にあるようですか? malloc()システムの実装では、ヒープセクションの大きさ、開始アドレスなどの情報などのメタデータ情報を維持するために、余分なバイトが割り当てられているようです。

ただし、プラットフォームによって異なります。X86 システムでは、要求している場合でも、malloc() 最小バイト数を割り当てます。17malloc(0)

int main(void) {
    int *p = malloc(0);
    if(p == NULL) {
        /* error handling */
    }
    printf("%d\n",p[-1]);/ *it prints 17 bytes */
    /* some code */
    return 0;
}
于 2015-09-20T08:21:00.017 に答える
1

ポインターが次の配列のサイズを表す前に、これは 32/64 ビット整数です (符号付きか符号なしかはわかりません)。

于 2009-01-09T23:46:39.303 に答える
0

malloc() は連続したメモリを割り当てる可能性がありますが、malloc() を 2 回呼び出すと、2 つのポインタ変数を減算することによって、割り当てられたメモリが連続しているとは期待できません...

ただし、割り当てられたメモリはカーネル実装の一部である仮想メモリであり、具体的にはメモリ管理(VFS)です。アプリケーションの機能には影響しない場合があります。

于 2018-02-16T10:09:19.690 に答える