C언어 (14-2) 함수와 포인터 ex
책에는 있는데 알면 좋고 중요한 것도 맞긴 한데
이해하기 어렵기도 하고 C언어를 배우는 과정에서 꼭 알아야하는 건 아닌 것 같아서 간단히 정리만 했다.
main() 함수에 인자를 넣을 수 있다?
여태까지 본 main() 함수는 인자가 없는 main(void) 형태였다.
그런데 다른 형태의 main()함수도 있다.
1
int main(int argc, char* argv[])
이렇게 인자가 2개를 받을 수 있는 main 함수가 있다.
1
2
3
4
5
6
7
8
9
10
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(int argc, char* argv[]) {
printf("문자열의 수 : %d\n", argc);
for (int i = 0; i < argc; i++) {
printf("%d번째 문자열 : %s\n", i+1, argv[i]);
}
return 0;
}
실행 결과는 인자로 받은 문자열의 수와 그 문자열을 출력한다. 실행 파일의 경로가 출력된다.
visual studio가 아닌 WSL(우분투 리눅스) 환경에서 위의 코드를 실행해보자.
argc.c라는 파일로 코드를 저장하고 gcc 컴파일 해서 실행파일 argc를 만들었다.
그 다음 ./argc로 실행 파일을 실행했다.
역시 ./argc라는 실행 파일의 경로가 출력된다.
이번에는 실행 명령 ./argc 뒤에 여러 문자열을 붙여서 실행해보았다.
문자열의 개수가 argc, 문자열 하나하나가 argv[i]에 들어있는 모습을 확인할 수 있다.
이 인자들은 실행할 때 동적으로 파일의 이름이나 값을 전달해줄 때 유용하게 사용할 수 있다.
위처럼 여러 파일들을 main()함수에 사용해야 할 때 argv[]를 통해서 쉽게 사용할 수 있다.
void형 포인터?
void란 ‘아무것도 없는’이라는 의미이다.
그러면 void형 포인터는 자료형이 없는 포인터 변수라는 의미다.
포인터에 자료형이 필요한 이유는 주소에 접근했을 때 포인터 변수가 얼마만큼의 데이터를 읽어야할지
(int형이면 4바이트, double형이면 8바이트 등)를 알려주기 위해서였다.
그런데 자료형에 제약을 받지 않고 아무 자료형의 주소나 저장할 수 있는 포인터 변수가 있다.
그것을 void형 포인터라고 부르고, 주소만 저장할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main() {
char a='a';
int b=1;
double c=3.14;
void* p;
p = &a;
printf("a의 주소 %p = %p\n", &a, p);
p = &b;
printf("b의 주소 %p = %p\n", &b, p);
p = &c;
printf("c의 주소 %p = %p\n", &c, p);
return 0;
}
1
2
3
a의 주소 00000095D0B6F900 = 00000095D0B6F900
b의 주소 00000095D0B6F904 = 00000095D0B6F904
c의 주소 00000095D0B6F908 = 00000095D0B6F908
사용 방법은 다른 포인터와 같다. 하지만 포인터 변수가 주소에서부터 읽을 데이터의 크기를 모른다.
그렇기에 오류가 발생한다.
그러면 void형 포인터는 왜 있을까? 주소만 저장하는 기능만이 있는 것을 굳이 쓸리가 없다.
void형 포인터에 강제 형변환을 이용해주면 원하는 자료형의 포인터로 바꿀 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
int main() {
char a='a';
int b=1;
double c=3.14;
void* p;
p = &a;
printf("a의 주소 %p = %p\n", &a, p);
printf("%c\n", *(char*)p);
p = &b;
printf("b의 주소 %p = %p\n", &b, p);
printf("%d\n", *(int*)p);
p = &c;
printf("c의 주소 %p = %p\n", &c, p);
printf("%lf\n", *(double*)p);
return 0;
}
이렇게 각각의 자료형에 맞춰 (자료형*)로 형변환을 해주면 값을 출력할 수 있다.
void형 포인터는 타입애 구애받지 않고 주소를 저장하고, 형변환을 통해 값을 출력해 범용적으로 사용 가능하다.
void형 포인터 크기도 포인터니까 당연히 64bit 환경에선 8바이트, 32bit 환경에선 4바이트이다.
1
2
3
4
5
6
#include <stdio.h>
int main() {
void* p;
printf("%d", sizeof(p));
return 0;
}
C언어 프로그램에서 유연하고 안전하게 데이터를 관리하기 위해 void형 포인터를 사용한다.
함수와 포인터는 진짜 진짜 끝
다음은 구조체부터 천천히 알아보자.