메모리를 비우면 해당 메모리를 가리키는 포인터는 어떻게됩니까? 즉시 유효하지 않게됩니까? 후에 나중에 다시 유효하게되면 어떻게됩니까?realloc() 매달린 포인터 및 정의되지 않은 동작
틀림없이 포인터가 유효하지 않게되고 "유효"하게되는 일반적인 경우는 이전에 사용 된 메모리에 할당되는 다른 객체가 될 것이며 포인터를 사용하여 메모리에 액세스하면 분명히 정의되지 않은 동작입니다. 매달린 포인터 메모리는 수업 1을 거의 덮어 씁니다.
그러나 동일한 할당에 대해 메모리가 다시 유효하게되면 어떻게됩니까? 그 일이 일어날 수있는 유일한 표준 방법은 realloc()
입니다. malloc()
'메모리 블록 오프셋 (offset) > 1
에 포인터가있는 경우, realloc()
을 사용하여 블록을 오프셋보다 작게 축소하면 포인터가 유효하지 않게됩니다. 그런 다음 realloc()
을 다시 사용하여 적어도 매달려있는 포인터가 가리키는 객체 유형을 덮어 씌우려면 다시 블럭을 확장하십시오. 어느 경우에도 realloc()
은 메모리 블록을 이동시키지 않았고 다시 매달린 포인터가 유효합니까?
이것은 C 또는 C++ 표준을 이해하는 방법을 실제로 어떻게 해석해야하는지 모를 정도입니다. 아래는 그것을 보여주는 프로그램입니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
static const char s_message[] = "hello there";
static const char s_kitty[] = "kitty";
char *string = malloc(sizeof(s_message));
if (!string)
{
fprintf(stderr, "malloc failed\n");
return 1;
}
memcpy(string, s_message, sizeof(s_message));
printf("%p %s\n", string, string);
char *overwrite = string + 6;
*overwrite = '\0';
printf("%p %s\n", string, string);
string[4] = '\0';
char *new_string = realloc(string, 5);
if (new_string != string)
{
fprintf(stderr, "realloC#1 failed or moved the string\n");
free(new_string ? new_string : string);
return 1;
}
string = new_string;
printf("%p %s\n", string, string);
new_string = realloc(string, 6 + sizeof(s_kitty));
if (new_string != string)
{
fprintf(stderr, "realloC#2 failed or moved the string\n");
free(new_string ? new_string : string);
return 1;
}
// Is this defined behavior, even though at one point,
// "overwrite" was a dangling pointer?
memcpy(overwrite, s_kitty, sizeof(s_kitty));
string[4] = s_message[4];
printf("%p %s\n", string, string);
free(string);
return 0;
}
글쎄, 내 프로그램에 버그를 작성하면 어떻게되는지 물어볼 수 있습니다. 동일한 메모리 블록이 다른 malloc 후에 다시 할당 된 경우에도 포인터는 유효하지 않지만 역 참조는 UB입니다. –
free'ed 메모리에 대한 포인터가 유효하지 않을 수도 있지만 여전히 작동 할 수 있습니다. 이것은 메모리가 변경되었는지 여부에 달려 있습니다. "free'ed"이지만 여전히 동일한 값 (대개의 경우)이 포함되어 있으면 해당 메모리가 변경 될 때까지 코드가 작동합니다.이 경우 프로그램이 충돌합니다 ... 그렇지 않기 때문에 버그 추적이 어려워집니다 결정 론적이다. 프로그램을 실행하면 X를 다시 실행할 때 충돌이 발생하며 포인터가 업데이트되지 않았기 때문에 충돌이 발생하지 않습니다. – AbstractDissonance