main 함수 해부하기 - 포인터란?

main 함수의 두번째 전달인자에 "*"라는 코드를 봤던것 기억하시나요?
이것은 포인터(Pointer)를 의미하는데요. 이제 포인터에 대해서 자세히 알아보지요.



강의들은 모두 무료입니다. 단, 저작권은 키클 코딩랩 에 있으며, 무단 복제 및 배포를 엄금합니다.
이를 어길 시, 본 사이트의 서버가 미국에 있으므로, 미국법에 의해 처벌될 수도 있습니다.




메모리 주소(Address)와 포인터(Pointer) 데이터타입

원하는 폴더/디렉토리를 만들고 gedit 문서 편집기를 이용하여 "lec8_main.c"라는 이름의 C 파일을 만들어 볼게요. 그리고, 아래 줄1처럼 stdio.h을 포함시키고, 이어서 main() 함수의 골격을 코딩해 보지요.

lec8_main.c
#include <stdio.h>

int main (int argc, char *argv[ ]) {

}

줄1에서 표준입출력 라이브러리의 헤더파일(stdio.h)을 포함시킨 것은 나중에 printf 함수를 이용하기 위함이랍니다.
줄3을 보면, main() 함수의 두번째 전달인자가 "char *argv[ ]"라고 되어 있지요? "char"가 문자형 데이터타입을 의미하고 "argv"는 전달인자 변수 이름이고 "[ ]"는 배열을 의미한다는 것 이제 알고 있지요? 이제 공부할 것은 "*"이 무엇인가에 대한 것인데요, 이것은 "char"와 함께 쓰여 "문자형 포인터(Pointer) 데이터타입", "char *", 을 의미하게 된답니다.

포인터(Pointer) 데이터타입에 대해서 알아보기 전에, 먼저 알아야 될 것이 하나 있어요. 바로, 컴퓨터 안에 설치되어 있는 메모리(Memory)들은 각 메모리 공간마다 주소(Address)를 갖고 있다는 것이랍니다. 그렇다면, 메모리 주소는 왜 있는 것인가에 대하여 생각해 봐야 겠지요? 그것은 컴퓨터가 어떤 작업이나 처리를 할 때 메모리의 주소를 이용하기 때문이예요.
예를 들어 설명해 볼게요. 문자형(char) 변수를 선언하고 특정 문자를 할당하면, 1 바이트(Byte)의 메모리 공간에 그 문자에 대응하는 ASCII Code 값이 저장된다고 했었죠? 그림으로 나타내어 보면 아래와 같겠죠. 아래 그림에서 한 칸은 1 비트(Bit)를 의미한답니다.

10101101

그런데, 어떤 처리를 위하여 컴퓨터가 위의 선언한 변수에 접근하려면 어떻게 해야 할까요? 우리의 변수가 차지하고 있는 메모리의 위치 혹은 주소(Address)를 알아야 되겠지요? 이는 마치 우리가 친구집에 놀러가기 위해서 친구집의 주소가 필요한 것과 똑같은 것이죠. 위와 같은 이유로, 모든 메모리에는 주소가 정해져 있답니다.

그런데, 컴퓨터가 메모리의 주소를 이용하여 특정 메모리 공간에 접근하고 그 안에 있는 내용을 읽고 하는 이러한 작업들을 우리도 할 수 있답니다! 즉, 우리가 어떤 변수를 선언하면, 그 변수가 차지하는 메모리 공간의 주소를 통해 여러가지 원하는 처리를 할 수 있는 것이지요. 이처럼 선언한 변수 자체만이 아니라, 더 깊이 들어가서 변수가 차지하는 메모리의 주소까지 접근하고 처리할 수 있는 것은 C/C++이 제공하는 아주 강력한 기능이지요. 이러한 이유로 C/C++를 이용하면, 아주 정교한 코딩이 가능하다고 강의 C/C++ 시작~!에서 언급했던 것이랍니다.

그렇다면, 우리가 선언한 변수의 메모리 주소를 통해 여러가지 원하는 처리를 하고 싶다면 무엇을 해야 할까요? 바로, 알아낸 메모리 주소를 저장하거나 간직하고 있어야 하는 것이죠? 이를 위해 존재하는 것이 바로 포인터(Pointer) 데이터타입이랍니다. 정수를 간직하기 위해서 정수형(int) 데이터타입이 필요했고, 문자를 간직하기 위해서 문자형(char) 데이터타입이 필요했듯이, 메모리 주소(Address)를 간직하기 위해서 포인터(pointer) 데이터 타입이 따로 존재하는 것이지요. 조금 더 자세히 알아볼까요?

[문법] 포인터(Pointer)와 포인터 연산자 &,*





메모리 주소(Address)를 통해 변수 내용 바꾸기

우리가 변수를 선언하면 그 변수가 차지하는 메모리의 주소를 알아낼 수 있고, 그 주소를 포인터라는 특별한 데이터타입에 저장할 수 있다는 사실. 이해가 되었지요?
그렇다면, 직접 코딩을 통해 어떤 변수의 메모리 주소를 출력해보고, 그 주소를 이용하여 메모리 공간의 내용을 바꾸어 볼까요? 아래 줄4~줄13처럼 main() 함수 안에 코드를 추가해 보세요.

lec8_main.c
#include <stdio.h>

int main (int argc, char *argv[ ]) {
	int myval1 = 11;
	int myval2;
	int* myptr1;

	myptr1 = &myval1;
	printf("Memory address of myval1= %p, myptr1=%p\n", &myval1, myptr1);
	
	myval2 = myval1;
	*myptr1 = *myptr1 + 1; 
	printf("myval1= %d, myval2=%d\n", myval1, myval2);
}

줄4는 myval1이라는 정수형 변수를 선언하고 값 11으로 초기화했어요.
줄5는 myval2라는 정수형 변수를 초기화없이 선언만 했지요.
줄6에서는 정수형 변수가 차지하는 메모리의 주소값을 저장할 수 있는 정수형 포인터 변수 myptr1을 선언했답니다.

줄8에서는, & 포인터 연산자를 이용하여 변수 myval1이 차지하고 있는 메모리(크기는 정수형이니 4바이트이지요)의 주소값을 알아내어, 그 주소값을 정수형 포인터 변수 myptr1에 할당하고 있답니다.
줄9에서는 "&myval1"을 통해 얻은 메모리의 주소와 myptr1에 저장된 주소를 출력하고 있지요. myptr1에 저장된 주소는 줄8에서 &myval1의 값을 할당받은 것이기 때문에 똑같은 값이 출력되어야 겠지요? 주목할 점 하나는 메모리 주소(Address)를 서식 문자열에 출력하고자 한다면, format specifier(서식 지정자)로 %p를 사용한다는 것이랍니다.

줄11에서는, myval1에 저장된 값 11을 myval2에 할당하고 있어요. 정확하게 말하면, myval1이 차지하고 있는 메모리에 있는 값 11을 myval2가 차지하고 있는 메모리에 복사하는 것이랍니다.
줄12에서는, * 포인터 연산자를 이용하여 myptr1에 있는 주소가 가리키는 메모리에 접근하고, 그 메모리가 담고 있는 값에 1을 더하여 그 결과값을 그 메모리 공간에 다시 할당하고 있지요. 그런데, myptr1에 있는 주소는 사실 myval1이 차지하고 있는 메모리의 주소이지요? 고로, 줄12의 코드가 실행되면, myval1이 가지고 있는 값 11이 12로 바뀌게 되는 것이랍니다.
줄13에서는, myval1과 myval2가 가지고 있는 값들을 출력하고 있는데요. myval1의 값은 줄12로 인해 11에서 12로 바뀌었고, myval2의 값은 줄11에서 11이 할당된 후에 아무런 처리가 없었으므로 여전히 11을 가지고 있겠지요.





컴파일 후 실행하기

이제, 강의 첫 대면..main 함수에서 했던 것처럼, 파일을 저장하고 gedit 편집기 닫기를 하세요.
그리고, 아래 줄1처럼 터미널에서 "gcc lec8_main.c"을 실행하여 컴파일하세요.

.../my_folder$ gcc lec8_main.c
.../my_folder$ ls
a.out  lec8_main.c
.../my_folder$

컴파일이 잘 되었다면, 줄2에서처럼 터미널 명령어 ls를 실행하면, 줄3에서처럼, a.out이라는 실행파일이 생성된 것을 볼 수 있지요.

이제, 아래 줄3처럼 "./a.out"라고 명령하여 프로그램을 실행하면, 줄4~줄5와 같은 출력 결과를 얻을 수 있답니다.
아래 줄4에서 출력된 메모리 주소값 0x7fffa3704098은 제 컴퓨터에서 실행된 결과이기 때문에 여러분의 것과 다를 것이니 놀라지 마세요.

.../my_folder$ ls
a.out  lec8_main.c
.../my_folder$ ./a.out
Memory address of myval1= 0x7fffa3704098, myptr1=0x7fffa3704098
myval1= 12, myval2=11
.../my_folder$

강의에서 작성된 소스 코드 (source code)를 다운받으려면, 다음 링크를 클릭하세요: lec8_main.c

혹시, 이해가 잘 안되는 부분에 대한 질문이 있거나 다루어 줬으면 하는 주제가 있으면, 화면 오른쪽 하단에 "질문하기" 버튼을 이용해 주세요.






발자취

2019-09-11 "키클 코딩랩 - 미국 공학박사 아빠의 코딩 연구소"로 이름 변경
2019-06-28 코딩 교실 공개
2019-03-18 코딩 교실 제작 시작

바로가기
Python 배움터
C/C++ 배움터
About
Contact
Privacy Policy
강의목록
질문하기
처음으로