C(およびDebian GNU /LinuxではGCC4.3.3)のメモリ管理について質問があります。
K&RによるCプログラミング言語の本(7.8.5章)によると、ポインタを解放してから逆参照すると、エラーになります。しかし、以下に貼り付けたソースのように、コンパイラ(?)が明確に定義された原則に従って動作しているように見えることがあることに気付いたので、疑問があります。
動的に割り当てられた配列を返す方法を示す、このような簡単なプログラムがあります。
#include <stdio.h>
#include <stdlib.h>
int * ret_array(int n)
{
int * arr = (int *) malloc(10 * sizeof(int));
int i;
for (i = 0; i < n; i++)
{
arr[i] = i*2;
}
printf("Address pointer in ret_array: %p\n", (void *) arr);
return arr;
}
int * ret_oth_array(int n)
{
int * arr = (int *) malloc(10 * sizeof(int));
int i;
for (i = 0; i < n; i++)
{
arr[i] = i+n;
}
printf("Address pointer in ret_oth_array: %p\n", (void *) arr);
return arr;
}
int main(void)
{
int *p = NULL;
int *x = NULL;
p = ret_array(5);
x = ret_oth_array(6);
printf("Address contained in p: %p\nValue of *p: %d\n", (void *) p, *p);
free(x);
free(p);
printf("Memory freed.\n");
printf("*(p+4) = %d\n", *(p+4));
printf("*x = %d\n", *x);
return 0;
}
いくつかの引数を使用してコンパイルしようとすると、-ansi -Wall -pedantic-errors
エラーや警告は発生しません。だけでなく、また、正常に動作します。
Address pointer in ret_array: 0x8269008
Address pointer in ret_oth_array: 0x8269038
Address contained in p: 0x8269008
Value of *p: 0
Memory freed.
*p+4 = 8
*x = 0
*(p + 4)は8、* xは0です。なぜこれが発生するのですか?*(p + 4)が8の場合、x配列の最初の要素は6なので、* xを6にすべきではありませんか?
呼び出しの順序をfreeに変更しようとすると、別の奇妙なことが起こります。例えば:
int main(int argc, char * argv[])
{
/* ... code ... */
free(p);
free(x);
printf("Memory freed.\n");
printf("*(p+4) = %d\n", *(p+4));
printf("*x = %d\n", *x);
return 0;
}
実際、この場合、(私のマシンでの)出力は次のようになります。
*p+4 = 8
*x = 142106624
xポインターが実際に「解放」されているのに、pポインターが「異なって」解放されているのはなぜですか?わかりました。メモリを解放した後、ポインタをNULLを指すようにする必要があることはわかっていますが、興味があったのは:P