C언어

[C 언어] Dangling pointer

Teodore 2023. 1. 28. 16:47
728x90

오늘은 포인터를 사용할 때 마주칠 수 있는 dangling pointer라는 것에 대해 알아보려 한다. 

 

Dangling pointer : 유효하지 않은 메모리 영역의 주소를 가지고 있는 포인터

 

쉽게 말해서 포인터가 가르키는 메모리에 접근했을 때 에러가 발생하는 포인터를 말한다. 

 

1. 지역 변수 return시 발생

1
2
3
4
5
6
7
8
9
10
11
12
13
int* return_arr_pointer(void){
    int arr[10];
    for(int i = 0; i < 10; i++) arr[i] = i;
    return arr;
}
 
int main(void){
    int*  a = return_arr_pointer();
    for(int i = 0; i < 10; i++){
        printf("%d - %d\n", i, a[i]);
    }
    return 0;
}
cs

Error log

위의 코드에서는 return_arr_pointer에서 생성한 배열을 main에서 받아서 print하려고 한다. 

여기에서 a는 dangling pointer가 된다. (Error log : 지역 변수 또는 임시: arr의 주소를 반환하고 있습니다.)

그 이유는 return_arr_pointer에서 만든 arr 배열은 지역변수로서 함수가 종료되는 즉시 스택 메모리가 반환되기 때문에 해당 영역에 있는 값은 유효하지 않는다. 

 

2. 메모리 해제 이후 접근시 발생

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#define SIZE 10
void add_arr(int* arr, int size){
    for(int i = 0; i < size; i++) arr[i] += i;
    free(arr);
}
 
void print_arr(int* arr, int size){
    for(int i = 0; i < size; i++){
        printf("%d ", arr[i]);
    }
    printf("\n");
    free(arr);
}
 
int main(void){
    int* a = malloc(SIZE * sizeof(int));
    for(int i = 0; i < SIZE; i++){
        a[i] = i;
    }
    add_arr(a, SIZE);
    print_arr(a, SIZE);
    return 0;
}
cs
Error log

위의 코드에서는 main에서 동적 할당으로 a라는 배열을 생성하였고, 이를 add_arr에서 가공하고, print_arr에서 값을 출력하도록 만들어졌다. 여기에서는 print_arr에 들어간 arr가 Dangling pointer가 된다.(Error log : NULL 포인터 'a'을(를) 역참조하고 있습니다.)

add_arr에 들어간 arr은 정상적으로 메모리가 유지되어 처리되지만 free(arr)를 수행하면서 해당 메모리는 반환되어 유효하지 않은 상태가 된다. 

3. 해결 방법

그럼 위의 케이스에 대해서 어떻게 해결해야 할까? 답은 간단하다. 

 

첫 번째 케이스를 해결하기 위해서는 main에서 malloc 또는 배열 변수 선언으로 메모리를 할당하고 할당한 메모리 주소를 함수로 넘겨주어 가공하도록 하는 것이 좋다. 아래 코드를 보면 이해가 쉬울 것이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
void set_arr(int* arr){
    for(int i = 0; i < 10; i++) arr[i] = i;
}
 
int main(void){
    int a[10]; // or int* a = malloc(10 * sizeof(int));
    set_arr(a);
    for(int i = 0; i < 10; i++){
        printf("%d - %d\n", i, a[i]);
    }
    return 0;
}
 
cs

 

두 번째 케이스에 대한 해결은 가능한 malloc한 함수에서 free하도록 처리하는 것이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#define SIZE 10
void add_arr(int* arr, int size){
    for(int i = 0; i < size; i++) arr[i] += i;
}
 
void print_arr(int* arr, int size){
    for(int i = 0; i < size; i++){
        printf("%d ", arr[i]);
    }
    printf("\n");
}
 
int main(void){
    int* a = malloc(SIZE * sizeof(int));
    for(int i = 0; i < SIZE; i++){
        a[i] = i;
    }
    add_arr(a, SIZE);
    print_arr(a, SIZE);
    free(a);
    return 0;
}
 
cs

생각해보면 아주 간단하고 상식적인 문제인데, 실제 업무를 하다보면 정확한 규칙을 만들기 전에는 실수가 잦은 부분이니 가능하다면 같이 업무를 하거나 코드를 작성하는 동료나 팀 단위에서 코드 작성 규칙을 만들고 이에 따른 코드리뷰 문화를 정착시키는 것이 바람직하다. 

728x90