22

C および C++ では、NULL ポインターを解放しても何も起こりません。

それでも、「メモリを 2 回解放する」とメモリ破損が発生する可能性があると言う人を見かけます。

これは本当ですか?メモリを 2 回解放すると、内部で何が起こっているのでしょうか?

4

9 に答える 9

24
int *p = malloc(sizeof(int));
//value of p is now lets say 0x12345678

*p = 2;
free(p); //memory pointer is freed, but still value of p is 0x12345678
         //now, if you free again, you get a crash or undefined behavior.

したがって、free最初に ing を実行した後は、 を実行する必要がp = NULLあるため、(万が一)free(p)が再度呼び出されても、何も起こりません。

メモリを 2 回解放することが定義されていない理由は次のとおりです。

于 2010-03-18T10:11:08.553 に答える
19

メモリを解放しても、ポインターは null に設定されません。ポインターは、所有していたメモリを指し続けますが、現在は所有権がヒープ マネージャーに戻されています。

ヒープ マネージャーは、古いポインターが指しているメモリを再割り当てした可能性があります。

再度解放することは、 と言うのと同じではなく、free(NULL)未定義の動作が発生します。

于 2010-03-18T10:12:05.290 に答える
9

これは未定義の動作であり、ヒープの破損やその他の重大な結果を招く可能性があります。

free()null ポインターの場合は、単に内部のポインター値をチェックして戻ります。このチェックは、ブロックを 2 回解放することに対しては役に立ちません。

ここでは、通常何が起こるかを示します。ヒープ実装はアドレスを取得し、独自のサービス データを変更して、そのアドレスにあるブロックの「所有権を取得」しようとします。ヒープの実装に応じて、何かが起こる可能性があります。機能しても何も起こらないかもしれません。サービス データが破損していて、ヒープが破損している可能性があります。

だからやらないでください。未定義の動作です。どんな悪いことでも起きます。

于 2010-03-18T10:03:12.703 に答える
4

はい、ほとんどの場合クラッシュにつながる「未定義の動作」です。(定義上、「未定義の動作」は「何でも」を意味しますが、さまざまな種類のエラーはしばしば非常に予測可能な方法で動作します。free() の場合、動作は常に segfault または OS に特有のそれぞれの「メモリ保護エラー」です。)

NULL または malloc したもの以外へのポインターを free() する場合も同様です。

char x; char* p=&x; free(p); // クラッシュ。

于 2010-03-18T10:05:03.367 に答える
4

フリー 2 回を回避するために、私は常にフリー メモリに MACRO を使用しています。

#ifdef FREEIF
# undef FREEIF
#endif
#define FREEIF( _p )  \
if( _p )              \
{                     \
        free( _p );   \
        _p = NULL;    \
}

このマクロは、ポインターのダングリングを避けるために p = NULL を設定します。

于 2010-03-18T12:43:15.073 に答える
3

ポインタでfreeを呼び出すと、ポインタはNULLに設定されません。空き領域はプールに戻されるだけで、再度割り当てに使用できます。テストする例を次に示します。

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

int main(){
    int* ptr = (int*)malloc(sizeof(int));
    printf("Address before free: %p\n", ptr);
    free(ptr);
    printf("Address after free: %p\n", ptr);
    return 0;
}

このプログラムは私のために出力します:

Address before free: 0x950a008
Address after free: 0x950a008

ご覧のとおり、freeはポインタに対して何もしませんでしたが、メモリが再利用可能であることをシステムに通知しただけです。

于 2010-03-18T10:20:37.720 に答える
2

free() は、ptr が指すメモリー空間を解放します。これは、以前の malloc()、calloc()、または realloc() への呼び出しによって返されたものでなければなりません。それ以外の場合、または free(ptr) が以前に呼び出された場合、未定義の動作が発生します。ptr が NULL の場合、何も実行されません。

したがって、未定義の動作が発生し、何かが起こる可能性があります。

于 2010-03-18T10:06:16.790 に答える
1

1) 動的メモリの処理はコンパイラによって行われません。これを処理するランタイム ライブラリがあります。たとえば。: glibc は、malloc や free などの API を提供します。これらは、ヒープ領域を処理するためのシステム コール (sys_brk) を内部的に作成します。

2) 同じメモリを 2 回解放するとは、次のような状態を指します。char *cptr; があるとします。

以下を使用してメモリを割り当てます: cptr = (char *) malloc (SIZE);

このメモリが不要になったら、次を使用して解放できます: free(cptr);

ここで、cptr が指すメモリが自由に使用できるようになります。

プログラムの後で free(cptr) を再度呼び出したとします。これは有効な条件ではありません。同じメモリを 2 回解放するこのシナリオは、「メモリを 2 回解放する」問題として知られています。

于 2010-03-18T10:11:34.047 に答える
0

メモリを複数回解放すると、悪い結果が生じる可能性があります。このコードを実行して、コンピューターで何が起こるかを確認できます。

#include <stdio.h>      /* printf, scanf, NULL */
#include <stdlib.h>     /* malloc, free, rand */

int main ()


  {
  int i,n;
  char * buffer;

  printf ("How long do you want the string? ");
  scanf ("%d", &i);

  buffer = (char*) malloc (i+1);
  if (buffer==NULL) exit (1);

  for (n=0; n<i; n++)
          buffer[n]=rand()%26+'a';
  buffer[i]='\0';

  printf ("Random string: %s\n",buffer);
  free (buffer);
  free (buffer);

  return 0;
}

CSparse などの多くの標準ライブラリは、メモリの問題を処理するラッパー関数を使用します。ここに関数をコピーしました:

 /* wrapper for free */
    void *cs_free (void *p)
    {
        if (p) free (p) ;       /* free p if it is not already NULL */
        return (NULL) ;         /* return NULL to simplify the use of    

    }

この関数は、メモリの問題を処理できます。場合によっては malloc が NULL を返す条件に注意する必要があることに注意してください。

于 2015-08-06T17:43:07.117 に答える