main 함수 해부하기 - 포인터 배열

main 함수의 두번째 전달인자와 관련해서 많은 이야기를 해왔어요. 배열을 의미하는 "[ ]"포인터를 의미하는 "*", 그리고 문자열의 특성에 대해서 공부했지요.
이제, 공부했던 것을 토대로, 두 번째 전달인자의 정체를 알아보고, 어떻게 사용이 되는지 자세히 들여다 볼게요.
이번 강의로 main 함수의 해부하기는 마무리 된답니다.



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




포인터 배열 (Array of Pointer) - 포인터를 요소로 갖는 배열

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

lec10_main.c
#include <stdio.h>

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

}

줄1에서 표준입출력 라이브러리의 헤더파일(stdio.h)을 포함시킨 것은 나중에 printf 함수를 이용하기 위한 것이라는 것, 이제는 익숙하지요?
줄3에서, main() 함수의 두번째 전달인자가 "char *argv[ ]"인 것을 그동안 공부해 온 것을 바탕으로 음미해볼까요?
지금까지 공부한 것들을 되새겨 보면, "char"는 문자형 데이터타입을 의미하고 "argv"는 그저 전달인자 변수 이름이고 "[ ]"는 배열을 의미하지요. 그리고, "*"는 "char"와 함께 쓰여 문자형 포인터(Pointer) 데이터타입(char *)을 의미하게 되는 것이죠.

그렇다면, 두번째 전달인자 "char *argv[ ]"는 정말 무엇을 의미하는 것일까요?
바로, argv라는 이름의 배열인데, 그 배열 요소(element)의 데이터타입이 문자형 포인터(char *) 데이터타입, 즉, 어떤 문자를 담고 있는 메모리의 주소를 저장하는 데이터타입, 인 것이죠. 고로, "char *argv[ ]"는 문자형 포인터를 요소로 갖는 배열 즉, 문자형 포인터(의) 배열 (Array of Pointer)인 것이랍니다. 다시 말해, main() 함수에 두번째 전달인자로 들어오는 것은 여러 개의 어떤 문자를 저장하고 있는 메모리 주소값들인 것이고, 이 주소값들은 argv 문자형 포인터 배열의 각 요소에 저장되는 것이지요.

그렇다면, 이어지는 질문은 "두번째 전달인자로 들어오는 메모리 주소들이 가리키는 각 메모리 공간에는 어떤 문자가 저장되어 있는가?"일 거예요. 그 답은 바로, 우리가 프로그램을 실행할 때 입력하는 명령에서 찾을 수 있답니다.
우리가 컴파일 후에 프로그램을 실행하고자 하면, 터미널에 아래와 같은 형태로 입력하고 실행을 했었지요?

.../my_folder$ ./실행파일명

하지만, 아래와 같이 "./실행파일명" 뒤에 main() 함수에 전달하고자 하는 것들을 붙여 쓰는 것도 가능하답니다. 단, 공백을 넣어서 구분해야 하지요.

.../my_folder$ ./실행파일명 전달값1 전달값2 ... 전달값N

그런데, 중요한 것은 위에서 전달값으로 쓰는 것들은, 종류에 관계없이 모두 "문자열"로서 main() 함수에 전달된다는 것이랍니다.
예를 들어, 아래와 같이, main() 함수에 123과 abc를 전달한다고 가정해 볼게요.

.../my_folder$ ./실행파일명 123 abc

그러면, 123과 abc는 문자열인 "123"과 "abc"로 메모리에 저장이 되고, 이 문자열들이 main() 함수에 전달되는 것이죠. 그런데, 이전 강의 main 함수 해부하기 - 문자와 문자열에서 문자열을 어떤 변수에 할당할 때 문자형 포인터(char *) 변수를 이용했고, 그 변수에는 문자열의 맨 처음 문자가 차지하는 메모리의 주소가 저장된다고 했던거 기억하지요?
그리고, 이 문자형 포인터(char *) 데이터타입은 main() 함수의 두번째 전달인자인 배열 argv가 갖는 각 요소의 데이터타입인 사실도 잊지 않았지요? 즉, 위의 예에서, main() 함수의 두번째 전달인자(char *argv[ ])로 들어오는 값들은 문자열 "123"과 "abc"의 맨 앞 문자인 '1'과 'a'의 메모리 주소들이 되는 것이랍니다. 전달되는 문자열이 "123"과 "abc" 두 개이니, 배열 argv의 크기는 2가 되겠군요.





두 번째 전달인자 출력하기

이제, main() 함수의 두번째 전달인자에 들어오는 정보들을 출력해 보는 코딩을 해 볼게요.
아래 줄4~줄6의 코드들을 추가해 보세요.

lec10_main.c
#include <stdio.h>

int main (int argc, char *argv[ ]) {
	printf("The number of arguments=%d\n", argc);
	printf("ptr_arg1=%p, ptr_arg2=%p, ptr_arg3=%p\n", argv[0], argv[1], argv[2]);
	printf("arg1=%s, arg2=%s, arg3=%s\n", argv[0], argv[1], argv[2]);
}

줄4에서는 첫번째 전달인자인 argc의 값을 출력하고 있어요. 정수형이라서 %d를 사용했지요. 강의 main 함수 안의 코드 처리 결과 출력하기에서도 언급한 적이 있는데, argc는 main 함수에 전달되는 전달값의 갯수를 저장하고 있지요.
줄5에서는, 두번째 전달인자인 argv배열의 각 요소들을 출력하고 있답니다. 배열 argv의 요소는 문자형 포인터 데이터타입이지요? 고로, argv의 각 요소는 어떤 문자를 담고 있는 메모리의 주소를 가지고 있겠지요. 그래서, 서식지정자로 %p를 사용하고 있답니다. 나중에 실행할 때, 3개의 전달인자를 입력할 것이라서, 3개의 배열 요소에 접근하는 "argv[0]", "argv[1]", "argv[2]"를 코딩하였답니다. 배열 요소에 접근하는 것에 대한 복습이 필요하면 여기로 가보세요.
줄6에서는, 앞에서 main 함수에 전달되는 정보들이 문자열로 변환된다고 했는데, 그 문자열들을 출력하고 있답니다. 그래서, %s 서식지정자를 사용한 것이죠. 이전 강의 main 함수 해부하기 - 문자와 문자열에서, 문자열을 출력할 때는, 문자열의 맨 앞 문자의 메모리 주소만 printf() 함수에 전달해 주면 된다고 했었죠? 배열 argv의 요소가 저장하고 있는 것이 사실은 전달된 문자열의 맨 앞 문자 메모리 주소들이기 때문에, 줄5에서와 같이 "argv[0]", "argv[1]", "argv[2]"를 똑같이 코딩했답니다. 하지만, 줄6에서는 서식지정자로 %s를 사용했기 때문에, 문자열들이 출력되는 것이지요.





컴파일 후 실행하기

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

.../my_folder$ gcc lec10_main.c
.../my_folder$ ls
a.out  lec10_main.c
.../my_folder$ ./a.out 123 abc
The number of arguments=3
ptr_arg1=0x7fff41693004, ptr_arg2=0x7fff4169300c, ptr_arg3=0x7fff41693010
arg1=./a.out, arg2=123, arg3=abc
.../my_folder$

컴파일이 잘 되었다면, 줄2에서처럼 터미널 명령어 ls를 실행하면, 줄3에서처럼, a.out이라는 실행파일이 생성된 것을 볼 수 있지요.
이제, 줄4처럼 "./a.out 123 abc"라고 실행파일명 다음에 전달하고자 하는 정보인 "123"과 "abc"를 붙여서 함께 실행하세요. 그러면, 줄5~줄7의 결과를 얻게 된답니다.

줄5를 보면, 전달되는 입력값의 갯수가 3개라고 하고 있네요. 분명, "123"과 "abc"만 입력했는데요... 이것은 잘못된 것이 아니지요? 강의 main 함수 안의 코드 처리 결과 출력하기에서도 설명했듯이, "./a.out" 자체도 하나의 정보로 주어지기 때문에 총 3개가 맞는 것이랍니다.
줄6에서는 "./a.out", "123", "abc"의 문자열이 저장되어 있는 메모리의 주소값들이 출력되고 있지요. 정확히 말하면, 각 문자열의 맨 앞 문자인 '.', '1', 'a'가 차지하는 메모리의 주소값들이 출력되고 있는 것이지요.
줄7에서는 main() 함수에 전달된 모든 정보들이 문자열로서 출력되고 있답니다. 강의 main 함수 해부하기 - 문자와 문자열에서 설명했지만, "./a.out", "123", "abc" 문자열들의 맨 마지막에는 사실 널문자(\0)가 삽입되어 있다고 했지요? 그리고, printf() 함수가 서식지정자 %s를 만나면, 각 문자열의 문자들을 널문자(\0)이전까지 읽어와서 출력하는 거라고 했던 것도 기억하길 바랍니다.

이로써, main() 함수와 관련된 거의 모든 내용을 공부해 보았어요. 이 자체만으로도 C/C++의 뼈대를 이루는 상당 부분을 공부한 것이랍니다. 사소한 이야기 몇 가지만 더 하면, main() 함수의 해부하기는 마무리가 된답니다.

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

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






발자취

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

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