본문 바로가기

BackEnd/C

포인터의 const 선언

반응형

1. 한정자 - Type Qualifier


한정자는 ‘한정’과 ‘자’의 조합이다. 그리고 한정’은 ‘제한’의 의미를 지닌다. 즉 한정자는 제한을 


걸 때에 사용되는 키워드이다. C 언어에서 제공하는 한정자는 다음과 같이 총 3가지이다.


• const

• volatile 

• restrict


2. 포인터의 const 선언


기존의 const는 변수를 상수화하는 용도로 사용이 되는데, 이번에는 포인터와의 관계를 보자


다음 포인터 선언을 보자. 


int num = 10; 

int * ptr = #


포인터 ptr의 선언에서 const가 들어갈 수 있는 위치는 다음과 같다.



위 그림에서 보여주듯이 포인터 선언 앞 부분에 const가 삽입될 수도 있고,포인터 변수의 이름 


앞에 const가 삽입될 수도 있다. 물론 이 둘은 다른 의미를 지니며, 필요하다면 두 군데 모두에 


const를 삽입 할 수도 있다.


1) 포인터의 const 선언 1


앞 부분에 삽입되는 const의 의미는


int num = 10;

const int * ptr = #


이렇게 선언이 되면 포인터 ptr은 다음과 같이 가리키는 참조 대상에 대한 값의 변경이 불가하다. 


*ptr=20; // 컴파일 에러 발생!


즉 위의 const 선언은 포인터를 이용한 값의 변경을 허용하지 않겠다는 뜻이 된다.


예제를 보자


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

#include <stdio.h>
 
void ShowData(const int * p);
 
int main(void)
{
    int num1=10;
    int num2=20;
 
    const int * ptr=&num1;
 
    //(*ptr)++; // 컴파일 에러 발생
    num1++;   // 컴파일 성공!
 
    ShowData(&num1);
 
    ptr=&num2;
    ShowData(ptr);
 
    return 0;
}
 
void ShowData(const int * p)
{
    /* 
       이 안에서는 p가 가리키는 
       변수의 값을 바꿀 수 없다.
*p = 30; //컴파일 에러 발생
    */
 
    printf("%d \n"*p);
}
cs


실행결과


1
2
11
20
cs



10,12행: 포인터의 선언 앞에 const가 붙은 관계로 이 포인터를 이용해서는 값의 참조만 가능


할 뿐 변경은 불가능하다.


13행: 포인터 ptr이 가리키는 변수가 상수화 된 것이 아님을 보여준다. 포인터 만을 이용한         

 값의 변경이 불가능할 뿐,ptr이 가리키는 변수의 이름 num1을 이용해서는 얼마든지 


 값의 변경이 가능하다.


17행 : 포인터 ptr이 가리키는 변수에 저장된 값만 변경이 불가능하다고 하였다. 


  따라서 포인터 ptr을 변경하는 것은 전혀 문제되지 않는다. 즉 포인터 변수 ptr에 저장


  된값은 얼마든지 변경 가능하다.


23행:  이렇게 매개변수로 포인터가 선언 될 때 const 선언을 붙여주면, 함수 내에서는 포인터


  가 가리키는 변수에 저장된 값의 참조만 가능할 뿐, 변경은 불가능해진다. 그리고 이러


  한 형태의 선언은 함수를 보다 안정적으로 디자인한다는 측면에서 매우 의미 있는 선언

  이다.


2) 포인터의 const 선언 2


포인터 변수의 이름 앞에 선언


int num = 10;

int * const ptr = &num;


포인터 변수 ptr을 상수화시킨다는 의미이다. 즉 포인터 변수 ptr에 저장된 값의 변경이 불가 


능해지는 것이다. 즉 포인터 ptr은 끝까지 변수 num만 가리 킨다.


예제를 보자


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#include <stdio.h>
 
void ShowData(const int * p);
 
int main(void)
{
    int num1=10;
    int num2=20;
 
    int * const ptr1=&num1;
    int * const ptr2;  // 선언과 동시에 쓸모 없어짐!
 
    // ptr1=&num2;// 컴파일 에러 발생
  // ptr2=&num2;// 컴파일 에러 발생
    
    (*ptr1)++;
    ShowData(ptr1);
 
    return 0;
}
 
void ShowData(const int * p)
{
    /* 
       이 안에서는 p가 가리키는 
       변수의 값을 바꿀 수 없다.
    */
 
    printf("%d \n"*p);
}
cs


실행결과

1
11
cs
 


10,13행: 포인터 ptr1이 상수화되었으므로, 이후부터는 ptr1에 저장된 값을 변경하지 못한다.

           

그런데 13행에서는 ptr1에 저장된 값의 변경을 시도하고 있다.


11,14행: 포인터 ptr2를 선언과 동시에 초기화하지 않았으므로 쓰레기 값으로 초기화가 진행된다. 


그런데 이 포인터 변수 ptr2 역시 상수화되었으므로,한번 초기화 된 쓰레기 값의 변경


은 불가능하다. 


16행: 포인터 ptr1이 상수화되었을 뿐이다. 따라서 ptr1 포인터를 이용한 참조 대상에 대한 값의         

  변경이 가능하다.



3) 포인터의 const 선언 3


int num = 10;

const int * const ptr = &num;


이렇게 선언된 포인터 변수 ptr은 다음 두 가지 제약사항이 동시에 생기게 된다.


포인터 ptr을 이용해서는 ptr이 가리키는 변수에 저장된 값을 변경할 수 없다.


ptr이 상수화되었으니까 ptr은 끝까지 변수 num만 가리켜야 한다.



3. 포인터의 const 선언의 이점


const 선언은 중요하다. 왜냐하면 const 선언은 컴파일 에러보다 찾기 어려운, 프로그램 기능


상의 논리적 오류를 컴파일 오류로 바꿔 주기 때문이다.









반응형

'BackEnd > C' 카테고리의 다른 글

메모리 컨트롤 함수  (0) 2019.03.16
volatile 과 restict  (0) 2019.03.15
메모리 공간의 동적 할당  (1) 2019.03.14
자료형에 이름을 부여하는 typedef 키워드  (0) 2019.03.14
Call-By-Value vs Call-By-Reference  (0) 2019.03.14