Topic 4: 함수 포인터 🎯⚡
🎯 학습 목표
- 함수 포인터의 개념과 필요성을 이해할 수 있다
- 함수 포인터 선언과 사용법을 익힐 수 있다
- 콜백 함수의 원리를 이해하고 구현할 수 있다
- 함수 포인터를 활용한 유연한 프로그래밍을 할 수 있다
📖 함수 포인터란?
함수 포인터는 함수의 주소를 저장하는 특별한 포인터입니다. 변수가 메모리에 저장되듯이, 함수도 메모리에 저장되며 고유한 주소를 가집니다.
아날로지: 전화번호부와 같습니다.
- 함수 이름: 연락처 이름 (김철수, 이영희)
- 함수 포인터: 전화번호 - 실제 통화할 때 사용
- 함수 호출: 전화 걸기
🔍 함수 포인터 기본 문법
#include <iostream>
using namespace std;
// 간단한 함수들
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
int main() {
cout << "=== 함수 포인터 기초 ===" << endl;
// 함수 포인터 선언과 초기화
int (*operation)(int, int) = add; // add 함수의 주소 저장
// 함수 포인터를 통한 함수 호출
int result = operation(5, 3); // add(5, 3)과 동일
cout << "5 + 3 = " << result << endl;
// 다른 함수로 변경
operation = multiply; // multiply 함수의 주소로 변경
result = operation(5, 3); // multiply(5, 3)과 동일
cout << "5 * 3 = " << result << endl;
return 0;
}
🎮 실습: 계산기 만들기
#include <iostream>
using namespace std;
// 계산 함수들
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) {
return (b != 0) ? a / b : 0;
}
// 함수 포인터를 매개변수로 받는 함수
void calculate(int x, int y, int (*operation)(int, int), const char* symbol) {
int result = operation(x, y);
cout << x << " " << symbol << " " << y << " = " << result << endl;
}
int main() {
cout << "=== 함수 포인터 계산기 ===" << endl;
int a = 10, b = 3;
// 각 연산을 함수 포인터로 실행
calculate(a, b, add, "+");
calculate(a, b, subtract, "-");
calculate(a, b, multiply, "*");
calculate(a, b, divide, "/");
return 0;
}
📞 콜백 함수 (Callback Functions)
콜백 함수는 다른 함수에 인자로 전달되어 특정 상황에서 호출되는 함수입니다.
🔄 콜백 함수 예제
#include <iostream>
using namespace std;
// 콜백 함수들
void onSuccess() {
cout << "✅ 작업이 성공적으로 완료되었습니다!" << endl;
}
void onError() {
cout << "❌ 작업 중 오류가 발생했습니다!" << endl;
}
// 작업을 수행하고 결과에 따라 콜백 호출
void doWork(bool willSucceed, void (*successCallback)(), void (*errorCallback)()) {
cout << "작업을 시작합니다..." << endl;
// 가상의 작업 수행
if(willSucceed) {
cout << "작업 진행 중..." << endl;
successCallback(); // 성공 콜백 호출
} else {
cout << "문제가 발생했습니다..." << endl;
errorCallback(); // 오류 콜백 호출
}
}
int main() {
cout << "=== 콜백 함수 예제 ===" << endl;
// 성공 케이스
cout << "\n--- 성공 케이스 ---" << endl;
doWork(true, onSuccess, onError);
// 실패 케이스
cout << "\n--- 실패 케이스 ---" << endl;
doWork(false, onSuccess, onError);
return 0;
}
🔧 함수 포인터 배열
여러 함수를 배열에 저장하여 필요할 때 선택적으로 호출할 수 있습니다.
#include <iostream>
using namespace std;
// 다양한 인사 함수들
void sayHello() { cout << "안녕하세요!" << endl; }
void sayGoodbye() { cout << "안녕히 가세요!" << endl; }
void sayWelcome() { cout << "환영합니다!" << endl; }
int main() {
cout << "=== 함수 포인터 배열 ===" << endl;
// 함수 포인터 배열 선언
void (*greetings[3])() = {sayHello, sayGoodbye, sayWelcome};
// 메뉴 출력
cout << "\n선택하세요:" << endl;
cout << "0: 인사하기" << endl;
cout << "1: 작별하기" << endl;
cout << "2: 환영하기" << endl;
int choice;
cout << "선택 (0-2): ";
cin >> choice;
// 선택에 따라 함수 호출
if(choice >= 0 && choice <= 2) {
greetings[choice](); // 함수 포인터 배열로 호출
} else {
cout << "잘못된 선택입니다!" << endl;
}
return 0;
}
🎯 실습: 배열 처리 함수들
#include <iostream>
using namespace std;
// 배열 처리 함수들
void printArray(int* arr, int size, const char* title) {
cout << title << ": ";
for(int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void doubleValues(int* arr, int size) {
for(int i = 0; i < size; i++) {
arr[i] *= 2;
}
}
void addTen(int* arr, int size) {
for(int i = 0; i < size; i++) {
arr[i] += 10;
}
}
void resetToZero(int* arr, int size) {
for(int i = 0; i < size; i++) {
arr[i] = 0;
}
}
// 배열 처리 함수를 실행하는 함수
void processArray(int* arr, int size, void (*processor)(int*, int), const char* description) {
cout << description << endl;
processor(arr, size);
}
int main() {
cout << "=== 함수 포인터로 배열 처리 ===" << endl;
int numbers[5] = {1, 2, 3, 4, 5};
printArray(numbers, 5, "초기 배열");
// 함수 포인터를 사용한 배열 처리
processArray(numbers, 5, doubleValues, "값들을 2배로 만듭니다...");
printArray(numbers, 5, "2배 후");
processArray(numbers, 5, addTen, "모든 값에 10을 더합니다...");
printArray(numbers, 5, "10 추가 후");
processArray(numbers, 5, resetToZero, "배열을 초기화합니다...");
printArray(numbers, 5, "초기화 후");
return 0;
}
💡 함수 포인터 활용 팁
✅ 언제 사용하면 좋을까?
- 메뉴 시스템: 사용자 선택에 따른 다른 함수 실행
- 이벤트 처리: 특정 상황에서 호출할 함수 지정
- 정렬 알고리즘: 다양한 비교 조건으로 정렬
- 콜백 시스템: 작업 완료 후 호출할 함수
🔍 간단한 활용 예제
#include <iostream>
using namespace std;
// 배열 출력 함수
void showArray(int* arr, int size) {
for(int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
// 배열에서 조건에 맞는 요소 찾기
int findFirst(int* arr, int size, bool (*condition)(int)) {
for(int i = 0; i < size; i++) {
if(condition(arr[i])) {
return i; // 인덱스 반환
}
}
return -1; // 찾지 못함
}
// 조건 함수들
bool isEven(int n) { return n % 2 == 0; }
bool isLarge(int n) { return n > 50; }
int main() {
cout << "=== 조건부 검색 예제 ===" << endl;
int data[6] = {15, 30, 45, 60, 75, 90};
cout << "배열: ";
showArray(data, 6);
// 첫 번째 짝수 찾기
int evenIndex = findFirst(data, 6, isEven);
if(evenIndex != -1) {
cout << "첫 번째 짝수: " << data[evenIndex] << " (인덱스 " << evenIndex << ")" << endl;
}
// 50보다 큰 첫 번째 수 찾기
int largeIndex = findFirst(data, 6, isLarge);
if(largeIndex != -1) {
cout << "50보다 큰 첫 번째 수: " << data[largeIndex] << " (인덱스 " << largeIndex << ")" << endl;
}
return 0;
}
⚠️ 주의사항
❌ 피해야 할 실수
-
초기화되지 않은 함수 포인터
int (*ptr)(int, int); // 초기화되지 않음 // int result = ptr(1, 2); // 위험!
-
잘못된 함수 시그니처
int add(int a, int b) { return a + b; } void (*wrongPtr)(int, int) = add; // 반환형이 다름!
✅ 안전한 사용법
#include <iostream>
using namespace std;
int add(int a, int b) { return a + b; }
int main() {
// 안전한 초기화
int (*safePtr)(int, int) = add;
// nullptr 체크
if(safePtr != nullptr) {
cout << "결과: " << safePtr(5, 3) << endl;
}
return 0;
}
🧪 퀴즈 타임!
🤔 퀴즈 1: 함수 포인터 선언
다음 중 올바른 함수 포인터 선언은?
int square(int x) { return x * x; }
int* ptr = square;
int (*ptr)(int) = square;
int ptr(int) = square;
(*ptr)(int) = square;
정답: 2번
함수 포인터는 반환형 (*포인터명)(매개변수)
형태로 선언합니다.
🤔 퀴즈 2: 콜백 함수
다음 코드의 출력 결과는?
void callback() { cout << "콜백 실행!" << endl; }
void process(void (*cb)()) { cb(); }
process(callback);
정답: “콜백 실행!”
함수 포인터를 통해 callback 함수가 호출됩니다.
🎯 연습 문제
연습 1: 간단한 메뉴 시스템
함수 포인터 배열을 사용해서 사용자가 선택한 메뉴에 따라 다른 함수를 실행하는 프로그램을 만들어 보세요.
💡 힌트
void menu1() { cout << "메뉴 1 실행" << endl; }
void menu2() { cout << "메뉴 2 실행" << endl; }
void (*menus[])() = {menu1, menu2};
연습 2: 배열 정렬하기
함수 포인터를 사용해서 오름차순/내림차순으로 정렬할 수 있는 프로그램을 만들어 보세요.
💡 힌트
bool ascending(int a, int b) { return a > b; }
bool descending(int a, int b) { return a < b; }
void bubbleSort(int* arr, int size, bool (*compare)(int, int));
🎉 마무리
함수 포인터는 프로그램을 더 유연하고 재사용 가능하게 만드는 강력한 도구입니다!
오늘 배운 내용:
- 🎯 함수 포인터의 개념과 기본 문법
- 📞 콜백 함수의 원리와 활용
- 🔧 함수 포인터 배열을 통한 선택적 실행
- 💡 실전 활용 방법과 주의사항
다음 단계:
- Unit 9에서는 참조(Reference)를 학습합니다
- 포인터보다 안전하고 간편한 참조의 사용법을 배우게 됩니다
- 함수 매개변수에서의 참조 활용도 다루게 됩니다
함수 포인터를 잘 활용하면 더 유연하고 확장 가능한 프로그램을 만들 수 있습니다! 💪
Last updated on