web-dev-qa-db-ja.com

malloc(0)は何を返しますか?

malloc(0)は何を返しますか? realloc(malloc(0),0)についても答えは同じでしょうか?

_#include<stdio.h>
#include<malloc.h>
int main()
{
        printf("%p\n", malloc(0));
        printf("%p\n", realloc(malloc(0), 0));
        return 0;
}
_

Linux gccからの出力:

_manav@manav-workstation:~$ gcc -Wall mal.c
manav@manav-workstation:~$ ./a.out
0x9363008
(nil)
manav@manav-workstation:~$
_

出力は、malloc(0)のたびに変化し続けます。これは標準的な答えですか?そして、学術研究以外に、なぜこのような指針を得ることに興味があるのでしょうか?

編集:

malloc(0)がダミーポインターを返す場合、次の動作はどのようになりますか。

_int main()
{
    void *ptr = malloc(0);
    printf("%p\n", realloc(ptr, 1024));
    return 0;
}
_

編集:

次のコードは、反復ごとに「可能」を出力します。なぜ失敗しないのですか?

_#include<stdio.h>
#include<malloc.h>
int main()
{

        int i;
        void *ptr;
        printf("Testing using BRUTE FORCE\n");
        for (i=0; i<65000; i++)
        {
                ptr = malloc(0);
                if (ptr == realloc(ptr, 1024))
                        printf("Iteration %d: possible\n", i);
                else
                {
                        printf("Failed for iteration %d\n", i);
                        break;
                }
        }
        return 0;
}
_
53
manav m-n

他の人は、malloc(0)がどのように機能するか答えています。あなたが尋ねた質問のうち、まだ答えられていないものに答えます(私は思う)。問題はrealloc(malloc(0), 0)についてです:

malloc(0)は何を返しますか?答えはrealloc(malloc(0),0)でも同じでしょうか?

標準では、realloc(ptr, size)について次のように記述されています。

  • ptrNULLの場合、malloc(size)のように動作します。
  • それ以外の場合(ptrNULLではありません)、ptrによって古いオブジェクトポインターの割り当てを解除し、新しい割り当てられたバッファーへのポインターを返します。しかし、sizeが0の場合、C89はその効果はfree(ptr)と同等であると言います。興味深いことに、C99ドラフト(n1256またはn1336)にはそのステートメントが見つかりません。 C89では、その場合に返される実用的な値はNULLのみです。

そのため、2つのケースがあります。

  • malloc(0)は、実装でNULLを返します。 realloc()呼び出しはrealloc(NULL, 0)と同等です。これは、上記のmalloc(0)と同等です(この場合はNULLです)。
  • malloc(0)NULL以外を返します。次に、呼び出しはfree(malloc(0))と同等です。この場合、malloc(0)realloc(malloc(0), 0)notと同等です。

ここには興味深いケースがあることに注意してください。2番目のケースでは、malloc(0)が成功時にnon _NULLを返す場合、失敗を示すNULLを返すことがあります。これにより、realloc(NULL, 0)のような呼び出しが行われます。これは、NULLを返す場合と返さない場合があるmalloc(0)と同等です。

C99の省略が見落としなのか、それともC99でrealloc(ptr, 0)が非NULLptrfree(ptr)。私はこれを_gcc -std=c99_で試しましたが、上記はfree(ptr)と同等です。

編集:私はあなたの混乱が何であるかを理解していると思います:

サンプルコードのスニペットを見てみましょう。

_ptr = malloc(0);
if (ptr == realloc(ptr, 1024))
_

上記はmalloc(0) == realloc(malloc(0), 1024)と同じではありません。 2番目では、malloc()呼び出しが2回行われますが、最初の呼び出しでは、以前に割り当てられたポインターをrealloc()に渡します。

最初に最初のコードを分析しましょう。 malloc(0)が成功時にNULLを返さないと仮定すると、ptrは有効な値を持ちます。 realloc(ptr, 1024)を実行すると、realloc()は基本的にサイズ1024の新しいバッファーを提供し、ptrは無効になります。準拠する実装は、すでにptrにあるアドレスと同じアドレスを返す場合があります。したがって、if条件はtrueを返す場合があります。 (ただし、realloc(ptr, 1024)の後にptrの値を見ると、未定義の動作になる可能性があります。)

ここであなたが尋ねる質問:malloc(0) == realloc(malloc(0), 1024)。この場合、LHSとRHSのmalloc(0)の両方がnon _NULLを返すと仮定しましょう。その後、それらは異なることが保証されます。また、LHS上のmalloc()からの戻り値はまだfree() dになっていないため、他のmalloc()calloc()、またはrealloc()はその値を返さない場合があります。つまり、条件を次のように記述した場合:

_if (malloc(0) == realloc(malloc(0), 1024)
    puts("possible");
_

出力にpossibleは表示されません(malloc()realloc()の両方が失敗してNULLを返さない限り)。

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

int main(void)
{
    void *p1;
    void *p2;

    p1 = malloc(0);
    p2 = realloc(p1, 1024);
    if (p1 == p2)
        puts("possible, OK");

    /* Ignore the memory leaks */
    if (malloc(0) == realloc(malloc(0), 1024))
        puts("shouldn't happen, something is wrong");
    return 0;
}
_

OS Xでは、コードを実行しても何も出力されませんでした。 Linuxでは、_possible, OK_を出力します。

44
Alok Singhal

malloc(0)は、C99に関する限り、実装定義です。

からC99 [セクション7.20.3]

calloc、malloc、およびrealloc関数への連続した呼び出しによって割り当てられるストレージの順序と連続性は指定されていません。割り当てが成功した場合に返されるポインターは、任意のタイプのオブジェクトへのポインターに割り当てられ、割り当てられたスペース内のそのようなオブジェクトまたはそのようなオブジェクトの配列にアクセスするために適切に位置合わせされます(スペースが明示的に割り当て解除されるまで) 。割り当てられたオブジェクトの有効期間は、割り当てから割り当て解除まで延長されます。そのような各割り当ては、他のオブジェクトとは別のオブジェクトへのポインタを生成します。返されたポインターは、割り当てられたスペースの開始点(最下位バイトアドレス)を指します。スペースを割り当てることができない場合、nullポインターが返されます。 要求されたスペースのサイズがゼロの場合、動作は実装定義です:nullポインターが返されるか、または動作はサイズがゼロ以外の値であるかのようになりますが、返されるポインターはオブジェクトへのアクセスには使用しないでください。

33
Prasoon Saurav

C89では、malloc(0)は実装依存です-C99がこれを修正したかどうかはわかりません。 C++では、次を使用します。

char * p = new char[0];

明確に定義されています-有効な、null以外のポインターを取得します。もちろん、ポインターを使用して、未定義の動作を呼び出さずにポインターが指すものにアクセスすることはできません。

これが存在する理由については、一部のアルゴリズムにとって便利であり、ゼロ値のテストでコードを散らかす必要がないことを意味します。

15
anon

C99標準

スペースを割り当てることができない場合は、nullpointerが返されます。要求されたスペースのサイズがゼロの場合、動作は実装定義です。nullポインタが返されるか、動作はサイズがゼロ以外の値であるかのようになります。ただし、返されたポインタはオブジェクトへのアクセスに使用されません。

5

comp.lang.c FAQ には 以下 があります:

ANSI/ISO規格では、どちらでもよいとされています。動作は実装定義です(質問11.33を参照)。移植可能なコードは、malloc(0)を呼び出さないように注意するか、nullが返される可能性に備えなければなりません。

したがって、おそらくmalloc(0)の使用を避けるのが最善です。

5
unwind

C99のセクション7.20.3を参照してください。

要求されたスペースのサイズがゼロの場合、動作はimplementationdefinedです。nullポインターが返されるか、動作はサイズがゼロ以外の値であるかのようになりますが、返されるポインターはオブジェクトへのアクセスには使用されません。

これは、3つのすべての割り当て関数(つまり、calloc()malloc()realloc())に有効です。

3
Christoph

最初のプログラムでは、長さ0のreallocfreeと同じことです。

solaris manページから:

realloc()関数は、ptrが指すブロックのサイズをsizeバイトに変更し、(移動された可能性のある)ブロックへのポインターを返します。内容は、新しいサイズと古いサイズの小さい方まで変更されません。 ptrNULLの場合、realloc()は指定されたサイズに対してmalloc()のように動作します。 size0であり、ptrがNULLポインターでない場合、ポイントされたスペースは、システムに戻されませんが、アプリケーションによるさらなる割り振りに使用可能になります。メモリは、アプリケーションの終了時にのみシステムに返されます。

それが悪い驚きの源になりうることを知らない場合(私に起こりました)。

3

状況によると思います。 Visual Studio 2005のソースを確認し、_heap_alloc関数でこれを確認しました。

if (size == 0)
    size = 1;

多くの場合、ゼロバイトを要求する場合でも、有効なポインターが必要になると思います。これは、この一貫した動作により、ポインターを簡単に確認できるようになるためです。NULL以外のポインターがある場合は問題ありません。 NULLポインターがある場合は、おそらく問題があります。だからこそ、ほとんどの実装は、ゼロバイトを要求する場合でも、有効なポインターを返すと思います。

2
Patrick

Malloc(0)がダミーポインターを返す場合、次のように動作します。

void *ptr = malloc(0);

printf("%p\n", realloc(ptr, 1024));

「ダミーポインター」の意味がわかりません。 malloc(0)がNULL以外を返す場合、ptrはサイズ0のメモリブロックへの有効なポインタです。 malloc実装は、この情報を実装固有の方法で保存します。 reallocは、ptrがサイズ0のメモリブロックを指していることを理解する(実装固有の)方法を知っています。

(どのようにmalloc/realloc/freeがこれを行うかは実装固有です。1つの可能性は、要求より4バイト多くを割り当て、メモリブロックの直前にサイズを格納することです。その場合、((int *)ptr)[-1]は、メモリブロックサイズ、つまり0。コードからこれを行うことは絶対にしないでください。reallocおよびfreeでのみ使用します。

0
user9876