0

最近、プログラマーがif/else条件に応じて 1 つの無限ループ内で変数を宣言しているソース コードを見つけました。私が奇妙だと思ったのは、コードが実行され、メモリ リークが発生していないことです。最初は、おそらくアーキテクチャ固有のもの (コードは ARM 用) だと思っていましたが、いくつかのテストを実行したところ、GCC でコンパイルされた IA32 のバイナリが同じように動作することがわかりました。

私のアプローチは次のようなものでした: 2 つの小さなプログラム foo.c と bar.c を作成しました。

Foo.c:

#include <stdio.h>

int main(void)
{
   int i;

   for(i=0; i<10; i++) {
      char buf[10];
      buf[i] = 0;
      printf("buf[%d] (@ %#x) == %d\n", i, &buf, buf[i]);
   }

   return(0);
}

Bar.c:

#include <stdio.h>

int main(void)
{
   int i;

   for(i=0; i<10; i++) {
      char *ptr;
      ptr = (char *) malloc(10);
      ptr[i] = 0;
      printf("buf[%d] (@ %#x) == %d\n", i, &ptr, ptr[i]);
   }

   return(0);
}

Foo.c で配列を宣言することと Bar.cメモリを割り当てることを明示的に区別する理由は、コンパイラが自動的にそれが同じ変数であることを自動的に検出し、イニシャルの後の宣言を単に無視して反復するのではないかと最初に考えたからです。メモリを明示的に割り当てるため、 Bar.cではそうではありません。

両方の例で、配列と割り当てられたメモリの両方のアドレスが、反復の初期化後に同じままであることは、私にとって本当に奇妙でした。

私はそれを完全には理解していませんし、私はK&Rのコピーを持っていないので、説明に感謝します. (また、私の推論に間違いがあれば、それを指摘していただければ幸いです。)

4

2 に答える 2

2

ポインターのアドレスを出力しないでくださいptr(これはループ内の定数です。これはptr、現在の呼び出しフレームではローカル変数であるためです)。ただし、ポインター自体は出力します。

 printf ("buf[%d] == %d, ptr == %p\n", i, ptr[i], (void*) ptr);

(aが配列である場合&a == a、それらの型には互換性がありpますが、 がポインターである場合、通常は がなく&p == p、それらの型に互換性がないことに注意してください)

もちろん、mallocループ内に何らかのポインターがある場合、通常はfreeループの本体の最後にそのポインターが必要です。

を使用してコンパイルする方法gcc -Wall -g(Linux の場合、おそらく を使用する場合も-Wextraある) と、デバッガーを使用する方法gdb(Linux の場合) を学ぶ必要があります。

valgrindは、Linux でメモリ リークを検出するための便利なツールです。Boehm の保守的なガベージ コレクターを使用して、それらを「回避」することができます(GC_malloc代わりに を使用し、メモリを明示的に指定mallocする必要はありません)。free

于 2012-06-24T15:37:44.513 に答える