juuuding

CH 19 함수 포인터와 void 포인터 본문

C언어/윤성우의 열혈 C

CH 19 함수 포인터와 void 포인터

jiuuu 2023. 3. 20. 11:16

 1. 함수 포인터와 void 포인터

 

1. 함수 포인터이 이해

 함수는 매모리 상에 저장된 함수의 주소 값을 의미한다. 배열의 이름이 배열의 시작주소 값을 의미하듯, 함수의 이름도 함수가 저장된 메모리 공간의 주소 값을 의미한다. 배열의 이름과 마찬가지로 함수의 이름도 그 형태가 상수이다. 함수 이름의 포인터 형은 반환형과 매개변수의 선언을 통해서 결정짓도록 약속되어 있다. 

int SimpleFunc (int num){}의 포인터 형을 말하자면 "반환형이 int이고 매개변수로 int형 변수가 하나 선언된 포인터 형이다," 

 

 

2. 적절한 함수 포인터 변수의 선언

 함수의 포인터 변수에는 반환형 정보와 매개변수 선언의 정보가 모두 표현되어 있어야한다. 따라서 다음과 같이 작성하여 함수 포인터 변수를 선언한다. "int (*fptr) (int)" . 

int SoSimple(int num1, int num2){} 함수를 대상으로 예를 들어보자. 이 함수의 주소 값을 저장하기 위한 함수 포인터 변수는 int (*fptr) (int, int);로 선언하면 된다. 

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

void SimpleAdder(int n1, int n2) {
	printf("%d + %d = %d\n", n1, n2, n1 + n2);
}

void ShowString(char* str) {
	printf("%s", str);
}

int main(void) {
	char* str = "Function Pointer";
	int num1 = 10, num2 = 20;

	void(*fptr1)(int, int) = SimpleAdder;
	void(*fptr2)(char *) = ShowString;

	fptr1(num1, num2);
	fptr2(str);

    // 10 + 20 =30
    // Function Pointer
	return 0;
}

 

이번에는 매개변수의 선언으로 함수 포인터 변수가 올 수 있음을 보이고, 더불어 전달되는 인자에 따라서 달리 동작하는 함수의 정의도 가능함을 보인다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int WhoisFirst(int age1, int age2, int(*cmp)(int n1, int n2)) {
	return cmp(age1, age2);
}

int OlderFirst(int age1, int age2) {
	if (age1 > age2) return age1;
	else if (age1 < age2) return age2;
	else return 0;

}
int YoungerFirst(int age1, int age2) {
	if (age1 > age2) return age2;
	else if (age1 < age2) return age1;
	else return 0;

}

int main(void) {
	int age1 = 20;
	int age2 = 30;
	int first;

	printf("입장순서 1 \n");
	first = WhoisFirst(age1, age2, OlderFirst);
	printf("%d세와 %d세 중 %d세가 먼저 입장!\n\n", age1, age2, first);
	
	printf("입장순서 2 \n");
	first = WhoisFirst(age1, age2, YoungerFirst);
	printf("%d세와 %d세 중 %d세가 먼저 입장!", age1, age2, first);
}

 

3. '형(Type)'이 존재하지 않는 void 포인터

 void * ptr; 와 같이 선언되는 포인터 변수를 가리켜 'void형 포인터 변수'라 한다.void형 포인터 변수에는 어떠한 변수의 주소 값이든 담을 수 있다. 심지어 함수의 주소 값도 담을 수 있다. 하지만 void형 포인터 변수를 가지고는 아무런 포인터 연산을 하지 못한다. 값의 변경이나 참조도 하지 못한다. 따라서 void형 포인터는 다음 상황과 같은 경우에 유용하게 사용된다.

"일단 주소 값에만 의미를 두고, 포인터 형은 나중에 결정한다." 참고로 이 상황은 이후에 '메모리 동적 할당'과 매우 깊은 관계가 있다. 

 

 

 

 2. main 함수로의 전달

 

1. main 함수를 통한 인자의 전달

 아래의 코드는명령프롬프트에서 .exe 파일을 찾고, 원하는 문자열을 입력하면 결과를 얻을 수 있다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(int argc, char* argv[]) {
	int i = 0;
	pritnf("전달된 문자열의 수: %d\n", argc);

	while (argv[i] != NULL) {
		printf("%d번째 문자열: %s\n", i + 1, argv[i]);
		i++;
	}
	return 0;
}

입력: ArgEndNull "I love you"

출력: 전달된 문자열의 수: 2

         1번째 문자열: ArgEndNull

         2번째 문자열: I love you

 

 이 실행 결과에서 말해주듯이 큰 따옴표로 묶으면 공백을 포함하는 문자열을 생성해서 main함수의 인자로 전달하는 것이 가능하다.