포인터를 설명하기 위해서는 컴퓨터 메모리에 대하여 어느정도 이해가 필요하다.

 

힘들게 포인터 챕터까지 와서 C++을 접는 사람이 많은데 과거에는 컴퓨터 전공수업을 듣지 않고 배우기 힘들었던 것이 사실이다. 필자도 처음 C언어를 배우던 시절 구조체에서 더 이상 진도를 나가지 못했던 기억이 있다.

(구조체에서 포인터를 사용한다)

 

다행히 2020년 현재는 조금만 검색해봐도 포인터 대해 상세한 지식을 얻을 수 있다. 특히 유튜브에서 설명을 잘 해놓은 선생님들이많으니 한 두개 정도는 영상을 보는 것을 추천한다.

 

워낙 잘 설명한 영상이 많은데 얄팍한 코딩사전 체널의 설명이 가장 초보자 눈높이에 맞는 것 같다.

 

*링크 - 포인터가 뭐고 왜 쓰는건가요? - YouTube

 

영문 자료로 보면 인도의 IT교사들이 개념도를 잘 그려서 한번쯤 보는 것을 추천한다. 인도 영어의 발음은 한국사람에게도 잘 들리는 편이고 개념도로 설명하기 때문에 한번 정도 보면 좋다.

 

*링크 - Introduction to Pointers in C - YouTube 

 

이 블로그의 C언어와 알고리즘 메뉴에도 포인터에 대한 내용을 설명한 문서가 있으니 참고할 수 있다. 그런데 여기는 C++ 문서니까 굳이 포인터를 알기 위해서 C언어를 알아볼 필요는 없다. 포인터는 어떤 특정 언어에 종속되는 개념이라기 보다는 컴퓨터 구조 전반에 대한 내용이라서 어떤 언어를 사용하더라도 끓임없이 나오는 문제기도 하니까 처음에 정확한 개념을 잡고 가는게 좋다.

 

또 한가지는 포인터와 메모리에 대한 하나의 완벽한 해답이 있으면 좋겠지만 아쉽게도 그런 쉬운 길은 없는 것 같다. 이게 갈림길이 될 수 있는데 C++과 포인터를 배우지 않고도 다른 언어로도 충분히 프로그래밍이 가능하므로 포인터를 몰라서 프로그래밍을 포기하거나 하는 일은 이제 없을 것이다.

 

물론 다른 언어들도 어렵다. 요새는 프론트엔드라는 새로운 분야의 개발자들도 많이 늘어났는데 프레임워크를 다루는 정도까지는 그렇게 오래 걸리지 않는다고 하는데 프론트엔드도 제대로 트리를 밟으면 몇년이 걸린다고 한다. 풀스택 개발자들은 말할 것도 없이 오랜 인고와 수련의 시간이 걸린다.

 

포인터를 설명해야 하는데 잡설이 길어진다. 이 블로그는 이런 잡설을 섞어가며 기록해놓을 목적으로 만들어졌기 때문이다. 교과서 적인 내용도 포스팅을 하지만 교과서에 없는 내용을 다룰 수 있다는 것이 블로그의 좋은 점 이다.

 

특히 필자는 설명이 어렵다고 생각하는 주제에 대해서 주로 잡설을 많이 쓴다. 그 정도 설명 실력은 부족하니까 개인취향의 생각을 늘어놓으니 양해를 구한다.

 

(또 경어체를 생략하는 것도... 약간의 변명이지만 합니다 습니다를 적다 보면 글이 길어져서 정작 중요한 문장을 빼먹게 된다. 영어는 존댓말이 없다. 영어 내용을 참고하고 번역하다 보면 다 반말이다;;; 그것을 다시 한글어 존경어로 만드는 것도 일이다.) 


각설하고 이제 포인터에 대하여 알아보자.

 

* 포인터란 무엇인가?

 

-> 포인터는 기본자료형의 값이 저장된 메모리 상의 주소를 가지고 있는 변수다.

 

첫번째로 포인터는 변수라는 것을 인지하는게 중요하다. 이 변수에 메모리의 주소값을 저장한다.

 

아주 오래된 컴퓨터가 아니라면 현재 사용하는 운영체제는 32비트나 64비트 일 것이다. C언어를 빌드할 때도 32비트, 64비트를 선택할 수 있는데 어느 쪽을 선택하느냐에 따라 포인터의 크기가 달라진다.

 

예를 들어 아래의 포인터에 저장된 주소값은 32비트이다. 2의 32승 약 4기가의 메모리를 사용할 수 있다.

 

 

아래의 주소는 64비트이다. 2의 64승 이론상 16 EB 엑사바이트의 메모리를 사용할 수 있다. 16EB라는 것은 우리의 인지를 한창 벗어난 메모리 크기이고 그런 정도의 메모리를 가진 PC는 없을 것이다. 윈도우10에서 지원하는 64비트 메모리의 크기는 192기가바이트라고 한다. 192기가 SSD가 아니라 메모리를 말한다.

 

 

이 메모리의 공간에 개별적으로 접근할 수 있는 도구가 바로 포인터다. 메모리에 직접 액세스할 수 있다는 것은 컴퓨터안에서 하드웨어 레벨의 조작이 가능하다는 말이다. 물론 마음대로 접근할 수 있는 것은 아니고 운영체제가 허용한 범위내에서 접근할 수 있다. 하지만 여전히 잘못 사용하면 시스템을 한방에 다운시킬 수도 있으니 안심할 수가 없다.

 

포인터를 사용하다 보면 자바같은 매니지드 언어(managed language)에서 일어나지 않는 오류가 많이 생길 수 있다. 게다가 C++은 C언어와 다르게 객체지향언어이기 때문에 고려해야 할 사항도 많아서 난해하다. 여기까지만 이야기 해도 벌써 의욕이 떨어지는 것 같다.

 

그러나 그 모든 단점들을 커버할 정도의 장점이 있기 때문에 여전히 C++은 많이 사용되고 있다. MS윈도우도 C++로 작성되었다.

 

*다음의 코드를 실행시켜서 기본자료형의 메모리 주소를 출력해보자. 주소 출력 연산자는 & 이다. 변수에 &를 연산하면 그 변수의 메모리 주소값을 가져온다.

#include <iostream>
#include <iomanip>
#include <string>

using namespace std;

#define Line cout << "--------------------------------"\
                     "--------------------------\n"

int main()
{
	cout << "Welcome!\n";
	Line;

	short shortVar = 9;
	long longVar = 100000;

	cout << "shortVar: " << setw(7) << shortVar;
	cout << " | mem address : " << "0x" << &shortVar;
	cout << " | size : " << sizeof(shortVar) << endl;
	
	Line;
	cout << "longVar : " << setw(7) << longVar;
	cout << " | mem address : " << "0x" << &longVar;
	cout << " | size : " << sizeof(longVar) << endl;
	
	return 0;
}

mem address 는 16진수로 표기된다. short 형의 size는 2바이트이고 long 형의 size는 4바이트이다.

 

여기서 알 수 있는 것은

 

- short형 변수는 크기가 2바이트이고 9의 값을 저장하며 그 주소는 ...F6EC 에 위치한다.

 

- long형 변수는 크기가 4바이트이고 100000의 값을 저장하며 주소는 F6E0 에 위치한다.

 

- 디버거로 메모리를 열어보면 두 변수가 근접한 위치에 보인다. 변수를 연달아 선언했다고 해서 메모리상에 딱 붙어있지는 않다. 또 매번 실행할 때마다 주소는 달라질 수 있다. (09 00 -> 십진수 9의 2바이트 리틀엔디안) (a0 86 01 00은 100000이다)

 

변수는 선언한 자료형 크기의 값을 메모리주소에 저장한 것이다.

 

그러면 포인터는 뭐하는 것이냐? 변수가 저장되어 있는 주소값을 가진다.

 

포인터는 변수의 주소에 접근하여 직접 메모리의 값에 쓰거나 읽는 것이 가능하다.

 

포인터를 선언해보자. 포인터의 선언은 *이고 변수의 주소값을 대입한다.

 

 

아래 코드는 포인터에 대한 정보를 출력한다.

 

 

주소를 보면 포인터 값과 변수의 주소값이 같다는 것을 알 수 있다.

 

size를 보면 포인터는 4바이트이다. 32비트 주소에는 4바이트가 필요하고 64비트 주소에는 8바이트가 필요하다.

 


여기까지 포인터 기초 포스팅을 마친다. 다소 장황한 설명이다. 다음에 여력이 되면 좀 더 쉬운 내용으로 업데이트 하겠다.

공유하기

facebook twitter kakaoTalk kakaostory naver band