[C/C++] Dangling Pointer란 무엇일까?



댕글링 포인터(Dangling Pointer) 란 무엇일까?
막상 이름만 들었을 땐 귀엽지만, 잘못하면 문제를 발생시키기 쉬운 녀석이다. 
원인은 다음과 같다.<br />
<br />
1. 동적 할당(힙에 할당) 된 메모리가 존재.<br />
2. free or delete를 통해 삭제<br />
3. 삭제된 메모리를 가르키고 있는 상태.<br />
<br />
코드 상 예를 들자면 다음과 같다.<br />
<br />

<pre class="brush:c++"
class="brush:plain; gutter:true">
/* 할당 */
char *str = (char)malloc(sizeof(char) * 4);
strcpy(str, "test");

/* str 작업...*/
printf("str[%s]\n", str);

/* 해제 */ 
free(str);

/* str 재사용 */
if ( str ) 
{
  printf("%p str %p is Not Null [%s]\n", &str, *str, str);
} 
</pre>

/* 기대값으로, str이 가르키는 값은 해제되었기에 if문을 타지 않겠지? */
/* 허나 수행해버리고 종료되어버린다. */

<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgob3HIT48EDSYpZlfYgaxkRpT-mNDrgzcdBLVszJZD5m9aO9LBL5-2tSrBSBKRQzizBUk_B4OEBda1D415TgmZ_YVXH5sf0hEcYRS5MxXphMd-jJSqcdQImU1XRaxiGfAwPT3BKNJVIg/s1600/dangling.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="62" data-original-width="508" loading="lazy" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgob3HIT48EDSYpZlfYgaxkRpT-mNDrgzcdBLVszJZD5m9aO9LBL5-2tSrBSBKRQzizBUk_B4OEBda1D415TgmZ_YVXH5sf0hEcYRS5MxXphMd-jJSqcdQImU1XRaxiGfAwPT3BKNJVIg/s1600-rw/dangling.JPG" /></a></div><br />
<br />
<br />
<br />
<br />

---

무슨 말인고...?<br />
<br />
1. A 할당 <br />
<br />
= A에 대한 문자열 첫번째에 대한 주소값을 가진다. <br />
<br />
2. A 해제<br />
= A에 대해 주소값을 여전히 가진다.<br />
<br />
<br />
이 과정에서 NULL로 초기화 해주는 소스코드가 들어가야한다. <br />
<br />
<pre class="brush:c++"
class="brush:plain; gutter:true">/* 할당 */
char *str = (char)malloc(sizeof(char) * 4);
char *ptr = str;

/* str 작업...*/

/* 해제 */ 
free(str);
str = NULL; 

/* 해제 후엔 꼭 가르키는 주소값(포인터)을 Null로 초기화를 하자 */

/* 재사용 */
if ( str ) 
{
  printf("%p str %p is Not Null [%s]\n", &str, *str, str);
} 
</pre><br />
<br />
<br />
댕글링 포인터가 많아지면 디버깅이 어려워지기에 잘 확인하여야한다. <br />
다음은 다른 포인터 변수에 넣는 경우이다. <br />
<br />
<br />
---

<pre class="brush:c++"
class="brush:plain; gutter:true">
int main(void)
{
    char *str = (char*)malloc(sizeof(char)*5);
    memset(str, '\0', sizeof(char) * 5);

    strcpy(str, "test");
    printf("%s\n", str);

    /* 1. 초기화 전 할당 */ 
    char* ptr = str;
    free(str);

    /* 2. Null로 초기화 */ 
    str = NULL;

    /* 3. ptr 주소값의 Null 검사 */
    if ( ptr ) // ptr은 값을 가짐. *ptr로 검사시 타지 않는다. 
    {
        printf("%p ptr %p is Not Null [%s]\n",&ptr, *ptr, ptr);
    }

     
    if ( str )
    {
        printf("%p str %p is Not Null [%s]\n", &str, *str, str);
    }

    /* 4. 출력 ? */
    printf("%p str %p is Not Null [%s]\n", &str, *str, str);

    return 0;
}


</pre><br />
단계 별로 풀어서 해보자...<br />
<br />
1. 초기화 전 할당. <br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUWhRn-Zcwhh1XwHYcoVFnc9Vw63QlhiF6oc_x-TNN4fWS1XomKtqMm1yyhk-OrazFnaRd0WuPKItWWgtdcLHc9A-22iG7GQ590x-lljUE_wiq99KJ93Ae7Awmbri5QUbCflZOq2Y70Q/s1600/step1.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="243" data-original-width="802" loading="lazy" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUWhRn-Zcwhh1XwHYcoVFnc9Vw63QlhiF6oc_x-TNN4fWS1XomKtqMm1yyhk-OrazFnaRd0WuPKItWWgtdcLHc9A-22iG7GQ590x-lljUE_wiq99KJ93Ae7Awmbri5QUbCflZOq2Y70Q/s1600-rw/step1.JPG" /></a></div><br />
<br />
<br />

---

2. Null 로 초기화<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0nVtDNYbM3mJYZZS8rZH3-lclB2SMf4uKCCUrWA933uLrFPpVwCR6USnRwVJPE7SzUxhiMnns_uZBn0sIGOHwd61gGGcR9TZ-CCqm_N6f4Sj-CslvJ62WxpVitVimoTcPd16HyRqCQA/s1600/step2.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="300" data-original-width="805" loading="lazy" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0nVtDNYbM3mJYZZS8rZH3-lclB2SMf4uKCCUrWA933uLrFPpVwCR6USnRwVJPE7SzUxhiMnns_uZBn0sIGOHwd61gGGcR9TZ-CCqm_N6f4Sj-CslvJ62WxpVitVimoTcPd16HyRqCQA/s1600-rw/step2.jpg" /></a></div><br />
<br />
<br />

---

3. str, ptr 주소값의 Null 검사<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhV-L_xq-_j7OKP32aNfhbnqGMquIvFACAMt4xG_zadSeiwlNkMtKhRh8g0DtQA-7VQfWCukkhU2tT-8SqDlQ69kVk4W2K0vcXW-K3BJac237waSnKU5dhD9d8t5qNcsIABN9r-zhsxDA/s1600/step3.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="308" data-original-width="784" loading="lazy" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhV-L_xq-_j7OKP32aNfhbnqGMquIvFACAMt4xG_zadSeiwlNkMtKhRh8g0DtQA-7VQfWCukkhU2tT-8SqDlQ69kVk4W2K0vcXW-K3BJac237waSnKU5dhD9d8t5qNcsIABN9r-zhsxDA/s1600-rw/step3.jpg" /></a></div><br />
<br />
<br />

---

<pre class="brush:c++"
class="brush:plain; gutter:true">

    /* 4. 출력 ? */
    printf("%p str %p is Not Null [%s]\n", &str, *str, str);

    return 0;
}
</pre>

4. 4. 출력의 경우 해제되었고, 주소 값도 Null로 바뀌었기에 세그멘테이션 폴트로 종료되어버린다. <br />

항상 초기화 및 포인터 검사에 대해 생각하지 않으면, <br />
디버깅시 굉장히 헷갈리게 될 거 같다. <br />

<br />

---


추가로 읽으면 좋을 것

댓글

이 블로그의 인기 게시물

윤석열 계엄령 선포! 방산주 대폭발? 관련주 투자 전략 완벽 분석

대통령 퇴진운동 관련주: 방송·통신·촛불수혜주 완벽 분석

키움 OPEN API MFC 개발 (1)