프린세스 다이어리

[C] 포인터 개념, 활용방법 정리 본문

C, C++

[C] 포인터 개념, 활용방법 정리

개발공주 2021. 9. 26. 12:00
728x90

1. 포인터의 개념

 

이전까지 공부한 변수는 그 자체로 자신의 자료형에 맞는 값을 저장한다. int, double, char 등이 그 예시다. 포인터는 메모리의 주소 값 자체를 저장한다. int형 변수를 만들었다고 하면, 컴퓨터 어딘가에 int가 저장된 공간이 있을 것이고, 그것의 메모리 주소를 가리키고 있는 포인터도 있다. 포인터는 메모리 주소의 값을 가지기 때문에 컴퓨터 메모리에 바로 접근할 수 있다. 

 

int a = 5;

int 5 값을 가지는 a 변수가 있고 이것의 메모리 주소는 0xAFB03912 라고 가정해 보자.

 

int *b = &a;

포인터는 int *b = &a; 처럼 선언할 때 * 연산자를 사용하여 포인터 변수임을 표현한다. 이 의미는 포인터 변수 b가 a의 메모리 주소를 가리키고 있다는 의미고, b의 값은 0xAFB03912이다. 포인터 b 또한 하나의 변수기 때문에, 메모리 주소를 또 다른 0xCA23AF29로 가진다. 선언 이후에 *b라고 쓰게 되면, 여기서는 *가 간접 참조 연산자로 포인터 변수 b가 가리키는 주소의 값, 즉 여기서는 a의 값인 5가 된다. 

 

정리하면, 

주소 연산자 (&) - 변수 앞에 붙어서 변수의 메모리 '시작' 주소값을 구한다.

포인터 (*) - 포인터 변수를 선언할 때 사용한다.

간접 참조 연산자 (*) - 선언된 포인터 변수가 가리키는 변수의 값을 구한다. 

 

이때까지 별 생각 없이 scanf(); 를 사용할 때, &a 이렇게 써서 특정한 변수가 메모리 내에 존재하는 주소의 값을 가져오고 있던 것이었다.

#include <stdio.h>

int main(void) {  
    int a = 5;
    int *b = &a;
    printf("%d\n", *b);
}

출력 결과는 5다. 포인터 변수 b가 가리키고 있는 주소 값을 잘 출력하고 있다.

 

2. 포인터 활용해보기

 

배열의 원소의 주소값 출력하기

#include <stdio.h>

int main(void) {  
    int a[] = {1,2,3,4,5,6,7,8,9,10};
    for (int i = 0; i < 10; i++)
    {
        printf("%d\n", &a[i]);
    }
    
}

결과는 다음과 같이 출력된다.

-421800320
-421800316
-421800312
-421800308
-421800304
-421800300
-421800296
-421800292
-421800288
-421800284

4씩 증가하면서 출력된다. 

 

344 345 346 347 348 349 350 351 352 353
... ... ... ... ... ...

실제로 int a = 5; 와 같이 변수를 할당하면, 메모리 주소 상에서는 위와 같이 기록된다. int형은 4 bytes를 차지하므로, 4칸을 차지한다. 배열을 이용하면 연속적인 공간에 값을 배치시킬 수 있기 때문에 위의 코드에서 배열의 메모리 주소가 4씩 증가하는 것이다. 

 

포인터는 특정한 메모리 주소를 가리키는 변수이기 때문에, 이 변수의 메모리 주소를 가리키는 또다른 포인터를 만들 수도 있다.

#include <stdio.h>

int main(void) {  
    int a = 5;
    int *b = &a;
    int **c = &b;
    printf("%d\n", **c);
}

이렇게 다중 포인터 또한 사용할 수 있다. 간혹 게임 등을 개발할 때 난독화 기법으로도 사용된다고 한다.

 

포인터는 컴퓨터 시스템의 특정한 메모리에 바로 접근할 수 있기 때문에, 기존에 존재하던 중요한 메모리 영역에 실수로 접근하지 않도록 해야 한다. 

int *a = 0x3344af09;
*a = 0;

위와 같은 코드처럼, 특정한 포인터 변수에 어떠한 메모리 주소를 넣고 0으로 재할당해버리면, 우리는 해당 주소가 어떤 역할을 하고 있는지 모르기 때문에 우리가 컨트롤할 수 없게 될 수가 있다. 

 

3. 배열과 포인터

 

배열과 포인터는 사실 동일하다. 배열을 선언한 이후에는, 배열의 이름 자체가 포인터 변수와 동일하다.

 

#include <stdio.h>

int main(void) {  
    int a[] = {1,2,3,4,5,6,7,8,9,10};
    int *b = a;
    printf("%d\n", b[2]);
}

변수 a에 배열을 할당하고 포인터 변수 b를 만들어서 &a가 아닌 a를 보게 만들면 3이 출력된다. 앞서 배열을 공부한 에서 문자 배열을 입력받을 때 왜 scanf()에 &a가 아닌 a를 써야 하는지 이해되지 않았는데, 이 때문이었다. 

 

 

728x90
Comments