C++ C-string과 고급 재귀함수
C-string 라이브러리
C-string의 개념과 중요성
문장을 비교 할 때 기존의 방법은 반복문을 사용해 두 배열의 글자가 다른지 확인해주는 작업을 거쳐야 했었다. 이제 여러 문자열을 처리 하기 위해서 직접 로직을 작성하지 않고 이미 만들어진 로직을 가져다 사용할수 있다.
기존 문자열 비교 방법 (수동)
#include <iostream>
using namespace std;
int flag = 0;
for (size_t i = 0; i < 10; i++)
{
if (nameA[i] != nameB[i])
{
flag = 1;
break;
}
}
if (flag == 0)
{
//같다
}
else
{
//다르다
}
C++
복사
기존 방법의 단점:
•
매번 반복문을 작성해야 함
•
문자열 길이를 미리 알아야 함
•
코드가 길고 복잡함
•
실수할 가능성이 높음
C-string 라이브러리 사용
이제는 cstring 라이브러리를 사용해서 두 문장이 같은지 비교해주면 된다.
#include <iostream>
#include <cstring> // C-string 라이브러리 포함
using namespace std;
int main()
{
char strA[256] = "Hello";
char strB[256] = "Hello";
if (strcmp(strA, strB) == 0)
{
cout << "문자열이 같습니다." << endl;
}
else
{
cout << "문자열이 다릅니다." << endl;
}
return 0;
}
C++
복사
주요 C-string 함수들
1. 문자열 길이 구하는 함수
// 문자열 길이 구하는 함수
int len = strlen(nameA);
C++
복사
2. 문자열 복사 함수 (복사할 위치, 복사할 소스)
// 문자열 복사 함수 (복사할 위치, 복사할 소스)
strcpy_s(nameC, nameA);
C++
복사
주요 C-string 함수 정리:
함수 | 기능 | 사용법 |
strlen(str) | 문자열 길이 반환 | int len = strlen(str); |
strcmp(str1, str2) | 문자열 비교 | if (strcmp(str1, str2) == 0) |
strcpy(dest, src) | 문자열 복사 | strcpy(dest, src); |
strcpy_s(dest, size, src) | 안전한 문자열 복사 | strcpy_s(dest, 256, src); |
strcat(dest, src) | 문자열 연결 | strcat(dest, src); |
strcat_s(dest, size, src) | 안전한 문자열 연결 | strcat_s(dest, 256, src); |
strcmp 함수 반환값:
•
0: 두 문자열이 같음
•
양수: 첫 번째 문자열이 사전순으로 뒤에 옴
•
음수: 첫 번째 문자열이 사전순으로 앞에 옴
재귀함수의 깊이와 너비
재귀함수 호출 빈도(깊이)를 조절하는 방법
우리는 이전에 재귀함수의 호출 빈도(깊이)를 조절하는 방법을 배웠었다.
#include <iostream>
using namespace std;
void BBQ(int level)
{
if (level == 3) // 종료 조건
{
return;
}
BBQ(level + 1); // 재귀 호출
}
int main()
{
BBQ(0); // level 0부터 시작
return 0;
}
C++
복사
재귀 호출 과정:
Main → BBQ(0) → BBQ(1) → BBQ(2) → BBQ(3) → return
Plain Text
복사
레벨별 스택 프레임:
•
Level 0: BBQ(0) 호출, level=0
•
Level 1: BBQ(1) 호출, level=1
•
Level 2: BBQ(2) 호출, level=2
•
Level 3: BBQ(3) 호출, level=3, return 실행
재귀함수 실행 과정 시각화
이번 재귀함수 함번이 아닌 두번을 호출한다면 어떻게 되는지 저장보자
트리 구조 재귀 호출
#include <iostream>
using namespace std;
void BBQ(int level)
{
if (level == 2) // 깊이 2에서 종료
{
return;
}
BBQ(level + 1); // 첫 번째 재귀 호출
BBQ(level + 1); // 두 번째 재귀 호출
cout << "BBQ" << endl;
//트리 형태로는 다음과 같이
//for문으로도 표현 가능하다
//for (size_t i = 0; i < 2; i++)
//{
// BBQ(level + 1);
//}
}
int main()
{
BBQ(0);
return 0;
}
C++
복사
트리 구조 호출 과정 시각화
시작
BBQ(0)
/ \
BBQ(1) BBQ(1)
/ \ / \
BBQ(2) BBQ(2) BBQ(2) BBQ(2)
| | | |
return return return return
Plain Text
복사
호출 순서와 실행 흐름:
1.
BBQ(0) 시작
2.
첫 번째 BBQ(1) 호출
3.
첫 번째 BBQ(2) 호출 → return
4.
두 번째 BBQ(2) 호출 → return
5.
첫 번째 BBQ(1) 완료, "BBQ" 출력
6.
두 번째 BBQ(1) 호출
7.
세 번째 BBQ(2) 호출 → return
8.
네 번째 BBQ(2) 호출 → return
9.
두 번째 BBQ(1) 완료, "BBQ" 출력
10.
BBQ(0) 완료, "BBQ" 출력
최종 출력: "BBQ" 3번 출력
재귀 함수를 여러번 호출하게 되면 위와같은 형태로 출력되게 된다.
이를 잘 활용해서 여러가지 문제를 풀어보도록 하자.
만약 재귀함수 호출이 3개라면?
3개의 재귀 호출
#include <iostream>
using namespace std;
void BBQ(int level)
{
if (level == 2)
{
return;
}
//BBQ(level + 1);
//BBQ(level + 1);
//BBQ(level + 1);
for (size_t i = 0; i < 3; i++)
{
BBQ(level + 1);
}
cout << "BBQ" << endl;
}
int main()
{
BBQ(0);
return 0;
}
C++
복사
3개 호출의 트리 구조
BBQ(0)
/ | \
BBQ(1) BBQ(1) BBQ(1)
/ | \ / | \ / | \
BBQ(2)BBQ(2)BBQ(2)BBQ(2)BBQ(2)BBQ(2)BBQ(2)BBQ(2)BBQ(2)
Plain Text
복사
호출 횟수 계산:
•
Level 0: 1회 (BBQ(0))
•
Level 1: 3회 (BBQ(0)에서 3번 호출)
•
Level 2: 9회 (각 BBQ(1)에서 3번씩 호출)
•
총 호출 횟수: 1 + 3 + 9 = 13회
•
"BBQ" 출력 횟수: 4회 (3개의 BBQ(1) + 1개의 BBQ(0))
재귀함수 활용 예제
1. 팩토리얼 계산
int factorial(int n)
{
if (n <= 1)
{
return 1;
}
return n * factorial(n - 1);
}
// factorial(5) = 5 * 4 * 3 * 2 * 1 = 120
C++
복사
2. 피보나치 수열 (이진 트리 재귀)
int fibonacci(int n)
{
if (n <= 1)
{
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2); // 2개의 재귀 호출
}
// fibonacci(4) 호출 트리:
// fib(4)
// / \
// fib(3) fib(2)
// / \ / \
// fib(2) fib(1) fib(1) fib(0)
// / \
//fib(1) fib(0)
C++
복사
3. 하노이의 탑
void hanoi(int n, char from, char to, char aux)
{
if (n == 1)
{
cout << from << "에서 " << to << "로 이동" << endl;
return;
}
hanoi(n - 1, from, aux, to); // 첫 번째 재귀
cout << from << "에서 " << to << "로 이동" << endl;
hanoi(n - 1, aux, to, from); // 두 번째 재귀
}
C++
복사
재귀함수 최적화와 주의사항
메모이제이션 (Memoization)
#include <iostream>
using namespace std;
int memo[100] = {0}; // 메모 배열
int fibonacci_memo(int n)
{
if (n <= 1) return n;
if (memo[n] != 0) // 이미 계산된 값이 있으면
{
return memo[n];
}
memo[n] = fibonacci_memo(n - 1) + fibonacci_memo(n - 2);
return memo[n];
}
C++
복사
실무에서의 재귀 활용
파일 시스템 탐색
void listDirectory(const string& path, int depth = 0)
{
// 들여쓰기 출력
for (int i = 0; i < depth; i++) cout << " ";
cout << path << endl;
// 하위 디렉토리들에 대해 재귀 호출
// for (각 하위 디렉토리)
// {
// listDirectory(하위디렉토리, depth + 1);
// }
}
C++
복사
JSON 파싱
void parseJSON(JSONNode node, int depth = 0)
{
if (node.isObject())
{
for (auto& child : node.children)
{
parseJSON(child, depth + 1); // 재귀적으로 파싱
}
}
}
C++
복사
C-string 라이브러리는 문자열 처리를 간편하게 해주며, 다중 재귀는 복잡한 구조를 표현하는 데 유용합니다. 하지만 성능과 메모리 사용량을 항상 고려해야 하며, 필요에 따라 메모이제이션이나 반복문으로 최적화하는 것이 중요합니다.
“강의는 많은데, 왜 나는 아직도 코드를 못 짤까?”
혼자 공부하다 보면 누구나 이런 고민을 하게 됩니다.
•
강의는 다 들었지만 막상 손이 안 움직이고,
•
복습을 하려 해도 무엇을 다시 봐야 할지 모르겠고,
•
질문할 곳도 없고,
•
유튜브는 결국 정답을 따라 치는 것밖에 안 되는 것 같고.
문제는 ‘연습’이 빠졌기 때문입니다.
단순히 강의를 듣는 것만으로는 실력이 늘지 않습니다.
실제 문제를 풀고, 고민하고, 직접 구현해보는 시간이 반드시 필요합니다.
그래서, 얌얌코딩 코칭은 다릅니다.
그냥 가르치지 않습니다.
스스로 설계하고, 코딩할 수 있게 만듭니다.
얌얌코딩 코칭에서는 단순한 예제가 아닌,
스스로 문제를 분석하고 구현해야 하는 연습문제를 제공합니다.
이 연습문제들은 다음과 같은 역량을 키우기 위해 설계되어 있습니다:
•
문제를 스스로 쪼개고 설계하는 힘
•
다양한 조건을 만족시키는 실제 구현 능력
•
기능 단위가 아닌, 프로그램 단위로 사고하는 습관
•
마침내 자신의 힘으로 코드를 끝까지 작성하는 경험
지금 필요한 건 더 많은 강의가 아닙니다.
코드를 스스로 완성해 나가는 훈련,
그것이 지금 실력을 끌어올릴 가장 현실적인 방법입니다.