본문 바로가기
프로그래밍 언어/C언어

알면 알수록 헷갈리는 포인터 뽀개기

by seongjko 2023. 6. 25.
728x90

1. 컴퓨터는 메모리 안에 저장된 데이터에 어떻게 접근하는가?

메모리 안에 10이라는 정수형 숫자를 저장해놓았다고 치자. 그렇다면 용량은 끽해봐야 8byte(long long형을 쓸 경우). 몇 백기가가 넘어가는 주메모리에는 수없이 많은 데이터들이 있을 텐데 이걸 어떻게 찾을 수 있을까?

택배기사가 수없이 많은 집 중 배달을 시킨 집 딱 하나만 골라내기 위해 주소를 사용하듯 컴퓨터도 드넓은 메모리 안에서 원하는 데이터를 찾아내기 위해 주소(address)를 사용한다.

데이터마다 서로 다른 주소값을 부여해 구분하고 해당 데이터가 필요할 때마다 그 데이터만 정확히 콕 찝어서 데려간다.

<핵심 point>

컴퓨터는 주소를 통해 메모리에 저장된 데이터에 접근한다.

 

 

2. 사용자는 메모리 안에 저장된 데이터에 어떻게 접근하는가?

포인터에 관심을 가질 정도로 c언어를 어느 정도 학습했다면 이미 익숙한 변수를 쓰면 된다.

int형 변수 a를 선언하고 10으로 초기화하면 데이터를 저장할 수 있는데,

데이터가 필요한 경우 a라는 변수명을 사용하면 간단히 호출할 수 있다.

<핵심 point>

사용자는 변수를 통해 메모리에 저장된 데이터에 접근한다.

 

 

3. 포인터를 사용하는 이유 

앞에서 컴퓨터는 주소를 통해 데이터에 접근하고 사용자는 변수를 통해 데이터에 접근한다고 했다.

그런데 사용자가 컴퓨터의 접근법을 이용해야 할 경우가 발생한다. 

main함수에서 선언된 변수 a 안의 값을 다른 함수에서 바꾸고 싶다고 가정하자. 

그런데 변수명을 함수에 전달해주면 변수 a 안의 값은 바뀌지 않는다. 

call by value 방식으로 데이터를 전달했기 때문인데 이럴 경우 데이터의 복사본을 전달했기 때문에 

변수 a 안의 값은 바뀌지 않는다.

결국, 데이터의 복사본이 아닌 데이터가 실제로 위치하고 있는 곳에 대한 정보를 전달해야 한든 이야기인데 

이때 사용되는 것이 바로 포인터이다.

<핵심 포인트>

포인터를 사용하면 사용자가 컴퓨터의 방식대로 저장된 데이터에 접근할 수 있고, 따라서 그 원본 데이터를 바꿀 수 있다.

 

 

4, 그래서 결론은?

int 변수의 자료형은 무엇인가? int형이다.

char 변수의 자료형은 무엇인가? char형이다.

pointer 변수의 자료형은 무엇인가? 그렇다. pointer형이다.

int형 변수를 통해 int형 데이터를 다룰 수 있고 char형 변수를 통해 char형 데이터를 다룰 수 있는 것처럼,

pointer형 변수를 이용해 pointer형 데이터 즉, 데이터의 주소를 다룰 수 있다.

<핵심 point>

포인터는 데이터 타입이다.

 

 

5. 포인터를 실제로 사용해보자.

int *p;
char *p;

포인터를 선언할 때는 위와 같은 방식으로 선언하게 된다.

그런데 애스터리스크(*) 앞에 자료형이 붙어있다.

int형과 char형 이것들은 포인터 이해하기에도 벅차 죽겠는데 도대체 왜 붙어 있는 것일까?

포인터형 변수를 사용해 특정 데이터의 변수에 접근하여 간접 참조 연산으로 해당 데이터를 불러올 때

그 데이터는 당연하지만 '오로지' 0과 1로만 이뤄져있다.

그래서 이 0과 1의 조합을 과연 char형이라고 치고 1byte 단위로 연산을 해줘야 할지,

int형이라고 치고 4byte 단위로 연산을 해줘야 할지 딜레마에 빠지는 상황이 발생한다.

그런 상황을 막기 위해 미리 지시를 해주는 것이다.

int가 앞에 붙어있다면 간접 참조 연산으로 데이터를 불러오면 그 데이터는 int형으로 간주하고 계산하고,

char가 앞에 붙어있다면 간접 참조 연산으로 데이터를 불러오면 그 데이터는 char형으로 간주하고 계산하라고

미리 지시를 해주는 것이다.

만약에 아래와 같이 코딩한다면 어떨까?

int a = 10;
  int *ip;
  float *fp; 

/*-----------------------------------*/

  ip = &a;
  fp = ip;

출처: https://newstars.cloud/23 [HelloJany:티스토리]

상단에는 int형 변수 a에 int형 10이 저장되어 있고 데이터를 불러올 때 int형으로 간주하라는 명령을 받은 포인터형 변수 ip와 데이터를 불러올 때 float형으로 간주하라는 명령을 받은 포인터형 변수 fp가 선언되어 있다.

하단에는 int형으로 데이터를 해석하는 pointer형 변수 ip에 a의 주소를 저장하고 그 ip를 다시 float형으로 데이터를 해석하는 pointer형 변수 fp에 저장했다.

어떻게 될까?

이 상황을 요약하면 간접 참조 연산으로 데이터를 가져올 때 그 데이터를 float형으로 간주하는 포인터형 변수 fp에 int형 데이터 10을 저장하고 있는 변수 a의 주소를 대입한 것이다.

즉, fp를 사용한다면 int형 데이터를 float형으로 해석하게 되는 참사가 발생하는데 그 결과는 안 봐도 뻔하다.(사실 잘 모른다 나중에 이거 보면 공부해라)

<핵심 point>

간접 참조 연산으로 불러오고자 하는 데이터의 자료형과 포인터형 변수의 자료형은 반드시 일치해야 한다.

 

 

6. 포인터를 쓰면 어떤 이점이 있을까?

일단 두 변수의 값을 바꾸는 함수를 통해 알아보자 

#include <stdio.h>

void swap(int* pa, int* pb);

int main(void)
{
    int a = 10, b = 20;

    swap(&a, &b);
    printf("a:%d, b:%d\n", a, b);

    return 0;
}

void swap(int *pa, int *pb)
{
    int temp;

    temp = *pa;
    *pa = *pb;
    *pb = temp;
}

main 함수에서 선언된 a와 b는 전형적인 지역변수이다. 그 말은 즉슨, a와 b에 저장된 10과 20이라는 data는 main함수의 중괄호 밖으로 나가는 순간 소멸되어버린다는 이야기다.

그렇다면 swap함수에서 a와 b 안에 저장되어 있는 데이터를 쓸 수 있는 방법이 있는가?

swap함수의 매개변수로 포인터를 선언해주고 인수로 a와 b의 주소를 받아온다면 가능하다. 그런데 애초에 처음부터 전역변수로 설정하면 되지 않을까?

한푼두푼 알뜰살뜰 메모리를 아껴야 할 판에 편하다고 무작정 전역변수로 설정해 버리면 프로그램이 끝날 때까지 계속 메모리를 차지하고 있기 때문에 공간의 낭비가 심할 수 있다.

이때 지역변수를 설정하고 지역변수의 단점을 보완해 줄 포인터형 변수를 함께 곁들여 사용한다면 훌륭한 콤비가 된다.

 

 

반응형

'프로그래밍 언어 > C언어' 카테고리의 다른 글

가변 인자에 대하여  (0) 2023.07.04
유효 숫자  (0) 2023.06.26