앞서 만든 성적 관리 프로그램에서 성적을 한번만 구하는 경우는 대부분 없다. 많은 경우에 동일한 작업을 반복하는 경우가 많다. 그럴 때마다 동일한 코드를 계속 작성 하는 것 보다 우리가 하는 작업을 정의해서 이름을 붙이고, 이 이름을 부를 때마다 그 작업을 해주는 것을 "함수" 라고 한다.
아래의 코드를 보자 두개의 변수에 있는 수를 더하고, 이를 반환하는 동작이 있다. 그리고 이 동작을 정리하면 오른쪽 그림과 같다.
이를 통해 우리는 작업을 정의할 때 뭐가 필요한지 알 수 있다.

이를 함수로 만들면 아래 그림과 같다.

함수의 이름은 add이고 반환타입은 int, 함수가 외부로부터 받는 정수형 변수 num1,num2그리고 동작은 num1 + num2 값을 반환해준다는
함수이다.
#include <iostream>
using namespace std;
// 1. 변수 값을 변경하는 함수 (값 전달)
void changeValue(int x) {
x = 10;
}
int main() {
// 변수 예제
int num = 5;
cout << "Before changeValue: num = " << num << endl;
changeValue(num); // 값 전달, num의 원본은 변경되지 않음
cout << "After changeValue: num = " << num << endl;
return 0;
}

일반적으로 변수의 복사해서 함수로 전달하므로, 함수 내부에서 값을 변경해도 원본은 영향을 받지않는다.
#include <iostream>
using namespace std;
// 배열 값을 변경하는 함수
void changeArray(int arr[], int size) {
// 첫 번째 요소를 변경
arr[0] = 42;
}
int main() {
// 배열 예제
int arr[3] = {1, 2, 3};
cout << "Before changeArray: arr[0] = " << arr[0] << endl;
changeArray(arr, 3); // 배열은 참조처럼 전달되므로 원본이 변경됨
cout << "After changeArray: arr[0] = " << arr[0] << endl;
return 0;
}

배열의 경우 내부적으로 메모리 상 배열의 위치가 전달된다. 따라서 함수내에서 값 수정시 실제 값이 수정 된다.
#include <iostream>
using namespace std;
// 변수 값을 변경하는 함수 (참조 전달)
void changeValueByReference(int &x) {
// x의 값을 변경 (원본 변수 변경됨)
x = 10;
}
int main() {
int num = 3;
cout << "Before changeValueByReference: num = " << num << endl;
changeValueByReference(num); // 참조 전달, num의 원본이 변경됨
cout << "After changeValueByReference: num = " << num << endl;
return 0;
}

배열 인자에 참조자를 사용하면 함수에서 인자의 값 변경시 실제 변수의 값이 변경된다.
#include <iostream>
using namespace std;
/**
* @brief 반지름을 입력받아 원의 넓이를 계산하는 함수
* @param radius 원의 반지름
* @return double 원의 넓이
*/
double calculateCircleArea(double radius) {
return 3.14 * radius * radius;
}
int main() {
double radius;
cout << "원의 반지름을 입력하시오 : ";
cin >> radius;
cout << "원의 넓이: " << calculateCircleArea(radius) << endl;
return 0;
}

#include <iostream>
using namespace std;
/**
* @brief 4개의 점수를 입력받아 평균 점수를 계산하는 함수
* @param score1 첫 번째 점수
* @param score2 두 번째 점수
* @param score3 세 번째 점수
* @param score4 네 번째 점수
* @return int 평균 점수 (소수점 제외)
*/
int calculateAverage(int score1, int score2, int score3, int score4) {
int sum = score1 + score2 + score3 + score4;
return sum / 4; // 정수 나눗셈으로 소수점 없이 계산
}
int main() {
int score1, score2, score3, score4;
cout << "점수 4개 입력 : ";
cin >> score1 >> score2 >> score3 >> score4;
cout << "평균 점수: " << calculateAverage(score1, score2, score3, score4) << endl;
return 0;
}

#include <iostream>
#include <string>
using namespace std;
/**
* @brief 이름과 성을 입력받아 "성 이름" 형식으로 변환하는 함수
* @param firstName 이름
* @param lastName 성
* @return string 변환된 이름
*/
string formatName(string firstName, string lastName) {
return lastName + " " + firstName; // 문자열 결합
}
int main() {
string firstName, lastName;
cout << "firstName을 입력하세요 : ";
cin >> firstName;
cout << " lastName을 입력하세요 : ";
cin >> lastName;
cout << "이름 형식 변환: " << formatName(firstName, lastName) << endl;
return 0;
}

잠시 cin과 getline의 차이에 대해 알아보고 이로인한 어떤 문제가 발생하는지 잠시 알아보겠다.
cin과 getline(string의 getline이다.)은 C++에서 사용자로부터 값을 입력받을 때 사용할 수 있는 함수이다. 두 함수 모두 입력 스트림에서 문자를 읽다가 구분자(delim)를 만나게 되면, 구분자를 버리고 입력 스트림에서 문자 읽기를 중단하게 된다.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string a;
// Hello,World 입력
getline(cin, a, ',');
// Hello
cout << a << endl;
return 0;
}
구분자로 ,를 사용했기 때문에 Hello,World에서 , 부터는 a에 저장되지 않는다. 따라서 결과값은 Hello이다. getline의 경우 함수의 세 번째 인자로 사용자가 구분자를 지정할 수도 있지만, 세 번째 인자를 사용하지 않는 경우(getline(cin, a);)에는 디폴트로 개행 문자(\n)가 구분자로 지정된다. 따라서 띄어쓰기가 포함된 값을 입력할 때는 getline을 사용해주면 값을 정상적으로 값을 입력받을 수 있게 된다.
반면, cin의 경우에는 공백 문자(whitespace character)를 구분자로 사용한다. 공백 문자는 스페이스(space), 탭(tab), 개행(newline), 캐리지 리턴(carriage return) 등을 포함한다. 따라서 cin에서 Hello World와 같이 공백 문자가 포함된 문자열을 입력하면 Hello 까지만 값을 입력받고 World는 무시하게 된다.
cin과 getline에서 구분자에 의해 입력값이 짤리는 경우, 구분자 뒤에 오는 문자들은 프로그램 상에서 사라진 것처럼 보이지만, 뒤에 있는 문자들은 입력 버퍼에 그대로 남아있게 된다.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string a, b;
getline(cin, a, ',');
getline(cin, b);
cout << a << endl;
cout << b << endl;
return 0;
}
이 경우 첫 번째 사용한 getline에서는 ,을 구분자로 사용을 하고, 두 번째로 사용한 getline에서는 디폴트 구분자인 개행 문자를 사용하고 있다. 여기서 Hello,World를 입력하는 경우를 살펴보자.
• 사용자로부터 Hello,World를 입력받는다.
• 첫 번째 getline의 구분자는 ,이므로, a에는 Hello가 저장된다.(값을 입력 받을 때에는 구분자까지 전부 받고, 구분자를 자름)
• 입력 버퍼에는 World가 남아있다.
• 두 번째 getline에서는 입력 버퍼에 남아있는 World를 그대로 읽고 개행 문자를 만나 입력 스트림을 닫는다.
• a에는 Hello가 b에는 World가 저장된다.
입력 버퍼에 문자가 남아 있으니 getline에서 사용자가 별도의 입력을 주지 않아도 바로 값을 입력받은 것을 볼 수 있다. cin에서도 동일한 현상을 관창할 수 있다.(Hello World로 실험해보면 된다.)
이처럼 입력 버퍼에 아직 처리하지 않은 문자가 남아있는 경우에는 다음 입력에 영향을 주기 때문에 문제가 되는 경우가 발생할 수 있다. 이 경우에는 cin.ignore를 사용해서 입력 버퍼에 남아있는 문자들을 버퍼에서 처리(제거)하고 다시 값을 입력받으면 된다.
• cin과 getline의 경우 구분자를 처리할 때 조금 다른 방식으로 처리한다. cin의 경우 구분자 만나면 이를 무시한다. 따라서 cin에서는 버퍼에 구분자가 그대로 남아있게 된다. 반면, getline은 구분자도 모두 포함하여 값을 입력 받기 때문에 버퍼에서 구분자가 제거된다.(입력 받은 값에서 구분자는 제거된다.)
• 또한, getline은 입력 버퍼에서 공백 문자만을 입력 받으면 그대로 입력이 종료되는 특징을 가지고 있다. 그래서 cin 다음에 getline을 사용하려면 cin.ignore를 사용해서 공백 문자를 지워줘야 한다.
• cin 다음에 getline으로 값을 입력받는 경우, getline 다음에 getline으로 값을 입력받는 경우를 각각 테스트하면 알 수 있다.
#include <iostream>
using namespace std;
/**
* @brief 네 개의 점수를 받아 합계를 계산하고 출력하는 함수
* @param score1 첫 번째 점수
* @param score2 두 번째 점수
* @param score3 세 번째 점수
* @param score4 네 번째 점수
*/
void printTotalScore(int score1, int score2, int score3, int score4) {
int total = score1 + score2 + score3 + score4; // 점수 합계 계산
cout << "점수 합계: " << total << endl;
}
int main() {
int score1, score2, score3, score4;
cout << "점수 4개를 입력하세요 : ";
cin >> score1 >> score2 >> score3 >> score4;
printTotalScore(score1, score2, score3, score4); // 합계 출력
return 0;
}

게임을 만들 때나 뭐 프로그램을 만들 때든 ~~를 하는 경우엔? ~~를 한다면 이렇게 생각해야 하는 부분이 많다. 예를 들어서
1. 비행기 슈팅게임에서 비행기가 적군의 미사일을 맞는 경우는?
2. 게임 캐릭터가 특정 아이템을 흭득한 경우엔?
이런 상황을 구현하기 위해 조건문을 제공한다.
조건문 문법
#include <iostream>
using namespace std;
int main() {
int age;
cout << "Enter your age: ";
cin >> age;
// if 문: 조건이 true일 때만 실행됩니다.
if (age >= 18) {
cout << "You are eligible to vote." << endl;
}
// 조건이 false인 경우 아무것도 실행되지 않습니다.
cout << "Program finished." << endl;
return 0;
}


이 코드의 조건문을 그림으로 나타내면 아래와 같다.

#include <iostream>
using namespace std;
int main() {
int number;
cout << "Enter a number: ";
cin >> number;
// if/else 문: 조건이 true일 때와 false일 때 다른 작업을 수행합니다.
if (number % 2 == 0) { // 입력값이 짝수인지 확인합니다.
cout << "The number is even." << endl;
} else { // 위 조건이 false라면 (즉, 홀수라면) 실행됩니다.
cout << "The number is odd." << endl;
}
cout << "Program finished." << endl;
return 0;
}


이 코드의 조건문을 그림으로 나타내면 아래와 같다.
if가 아닌 경우는 모두 else에 해당된다고 보면 된다.

#include <iostream>
using namespace std;
int main() {
int score;
cout << "Enter your score (0-100): ";
cin >> score;
// if/else if/else 문: 여러 조건을 순차적으로 검사합니다.
if (score >= 90) { // 90 이상인 경우
cout << "Grade: A" << endl;
} else if (score >= 80) { // 80 이상 90 미만인 경우
cout << "Grade: B" << endl;
} else if (score >= 70) { // 70 이상 80 미만인 경우
cout << "Grade: C" << endl;
} else if (score >= 60) { // 60 이상 70 미만인 경우
cout << "Grade: D" << endl;
} else { // 60 미만인 경우
cout << "Grade: F" << endl;
}
cout << "Program finished." << endl;
return 0;
}

이 코드의 조건문을 그림으로 그리면 아래와 같다.
연달아서 else-if가 작성되는 경우 기존의 영역은 포함되지 않음을 알 수 있다.

저번에 만들었던 계산기는 덧셈밖에못하는 뭔가 하자있는 계산기였다 이번에는 사칙 연산을 할 수 있는 계산기를 한번 만들어보자.
주의해야할 사항으로는 나누기를 할 때 0으로 나눌려고 하면 에러문자를 출력해야한다.
#include <iostream>
using namespace std;
int main() {
char op;
double num1, num2;
cout << "Enter first number: ";
cin >> num1;
cout << "Enter an operator (+, -, *, /): ";
cin >> op;
cout << "Enter second number: ";
cin >> num2;
if (op == '+') {
cout << "Result: " << num1 + num2 << endl;
} else {
if (op == '-') {
cout << "Result: " << num1 - num2 << endl;
} else {
if (op == '*') {
cout << "Result: " << num1 * num2 << endl;
} else {
if (op == '/') {
if (num2 == 0) {
cout << "Division by zero is not allowed." << endl;
} else {
cout << "Result: " << num1 / num2 << endl;
}
} else {
cout << "Invalid operator." << endl;
}
}
}
}
return 0;
}
#include <iostream>
using namespace std;
int main() {
char op;
double num1, num2;
cout << "Enter first number: ";
cin >> num1;
cout << "Enter an operator (+, -, *, /): ";
cin >> op;
cout << "Enter second number: ";
cin >> num2;
if (op == '+') {
cout << "Result: " << num1 + num2 << endl;
}
if (op == '-') {
cout << "Result: " << num1 - num2 << endl;
}
if (op == '*') {
cout << "Result: " << num1 * num2 << endl;
}
if (op == '/') {
if (num2 == 0) {
cout << "Division by zero is not allowed." << endl;
} else {
cout << "Result: " << num1 / num2 << endl;
}
}
if (op != '+' && op != '-' && op != '*' && op != '/') {
cout << "Invalid operator." << endl;
}
return 0;
}
두 코드의 차이가 보이는가?
첫 번째 코드는 중첩된 if-else구조를 사용하여 코드가 복잡하고 가독성이 안좋다. 두 번째 코드는 여러 개의 독립된 if문을 사용하여 논리적으로 이해하기도쉽고 가독성도 좋다. 물론 프로그램 효율면으로 들어가서 연산자가 많아지거나 특정 조건의 발생 빈도가 높아지면 첫 번째 코드가 더 효율적일 순 있다.
#include <iostream>
using namespace std;
int main() {
char op; // 사용자로부터 입력받을 연산자
double num1, num2; // 사용자로부터 입력받을 두 숫자
// 사용자 입력 받기
cout << "Enter first number: ";
cin >> num1;
cout << "Enter an operator (+, -, *, /): ";
cin >> op;
cout << "Enter second number: ";
cin >> num2;
// switch문을 사용하여 연산 수행
switch (op) {
case '+':
// 덧셈 연산
cout << "Result: " << num1 + num2 << endl;
break;
case '-':
// 뺄셈 연산
cout << "Result: " << num1 - num2 << endl;
break;
case '*':
// 곱셈 연산
cout << "Result: " << num1 * num2 << endl;
break;
case '/':
// 나눗셈 연산
if (num2 == 0) {
// 0으로 나누기 방지
cout << "Division by zero is not allowed." << endl;
}
else {
cout << "Result: " << num1 / num2 << endl;
}
break;
default:
// 잘못된 연산자 처리
cout << "Invalid operator." << endl;
break;
}
return 0;
}
위 코드와 같이 switch문으로 구현한 코드이다.
&&는 A&&B와 같이 사용하며 A,B에는 조건이 온다. 모든 조건이 참이어야 참이된다. 아래와 같이 두 개의 스위치가 모두 닫아져야 전류가 흐르는것에 비유한다.
||는 A||B와 같이 사용하며 A,B에는 조건이 온다. 둘 중 하나만 참이어도 참이 된다.
실제 코드로 한번 확인해보자.
#include <iostream>
using namespace std;
int main() {
int score;
cout << "Enter your score: ";
cin >> score;
// 조건: 0 <= score <= 100
if (score >= 0 && score <= 100) {
if (score >= 90) {
cout << "Grade: A\n";
} else if (score >= 80) {
cout << "Grade: B\n";
} else if (score >= 70) {
cout << "Grade: C\n";
} else if (score >= 60) {
cout << "Grade: D\n";
} else {
cout << "Grade: F\n";
}
} else {
cout << "Invalid score. Please enter a value between 0 and 100.\n";
}
return 0;
}
score >= 0 && score <= 100을 사용하였다.
그래서 0과 100사이의 값이 아닌 값을 입력하면

이렇게 나온다.
다음 코드도 확인해보자.
#include <iostream>
using namespace std;
int main() {
string weather;
int temperature;
cout << "Enter weather (sunny/rainy): ";
cin >> weather;
cout << "Enter temperature: ";
cin >> temperature;
// 조건: 맑은 날씨(sunny)이고 온도가 20도 이상일 때 외출
if (weather == "sunny" && temperature >= 20) {
cout << "It's a nice day to go out!\n";
}
// 조건: 비가 오거나 너무 추운 날씨
else if (weather == "rainy" || temperature < 10) {
cout << "Better stay indoors.\n";
}
// 나머지 경우
else {
cout << "You can go out, but dress appropriately.\n";
}
return 0;
}
이 프로그램에서는 날씨가 rainy 거나 온도가 10도 아래이면 나가지 말라고 출력문이나오고 날씨가 sunny이고 온도가 20도 이상일때는 날씨가 좋다고 출력한다. 그외인 경우는 나가도 되지만 옷을 적절하게 입으라고 출력된다.
학생 1명의 성적을 입력하는 것은 쉽다.
하지만 학생 1000, 10000명의 성적을 차례대로 입력해야 하는 경우 하드코딩으로 하는 것은 상당한 시간이 걸린다. 열심히 만들어도 학생인원이 늘면 사용하지 못하는 프로그램이 된다.
반복문은 이런 문제를 해결해 줄 수 있다.
반복문의 종류는 크게 for문과 while문이 있다 하나씩 알아보자.
반복의 범위가 명확하게 주어지는 상황이 있다.
예를 들어, 5번 반복해라 혹은 i라는 변수를 선언하고 i가 0부터 시작해서 5가 되기 전까지 반복하는 경우가 있다. 이때 for문을 사용한다.
전체적인 동작을 보면 아래와 같다.
초기화 과정은 한번만 하고, 이후에 종료 조건 확인 -> 동작 -> 사후 동작 -> 종료 조건 확인을 반복한다. 반복은 종료 조건이 될 때까지 반복 한다.
#include <iostream>
using namespace std;
int main() {
int sum = 0; // 합을 저장할 변수 초기화
for (int i = 1; i <= 10; i++) { // 초기화: i = 1
// 종료 조건: i <= 10
// 사후 동작: i++
sum += i; // 실제 동작: sum에 i를 더함
}
cout << "Sum: " << sum << endl; // 출력: 합계 출력
// 출력값: Sum: 55
return 0;
}

#include <iostream>
using namespace std;
int main() {
for (int i = 5; i >= 1; i--) { // 초기화: i = 5
// 종료 조건: i >= 1
// 사후 동작: i--
cout << i << " "; // 실제 동작: i를 출력
}
cout << endl; // 줄 바꿈
// 출력값: 5 4 3 2 1
return 0;
}

#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 20; i++) { // 초기화: i = 1
// 종료 조건: i <= 20
// 사후 동작: i++
if (i % 3 == 0) { // 조건: i가 3의 배수인지 확인
cout << i << " "; // 3의 배수일 때 i를 출력
}
}
cout << endl; // 줄 바꿈
// 출력값: 3 6 9 12 15 18
return 0;
}

#include <iostream>
using namespace std;
int main() {
int n = 5; // 삼각형의 높이
for (int i = 1; i <= n; i++) { // 초기화: i = 1
// 종료 조건: i <= n
// 사후 조건: i++
for (int j = 1; j <= n - i; j++) { // 초기화: j = 1
// 종료 조건: j <= n - i
// 사후 동작: j++
cout << " "; // 실제 동작: 공백 출력
}
for (int j = 1; j <= i; j++) { // 초기화: j = 1
// 종료 조건: j <= i
// 사후 조건: j++
cout << "*"; // 실제 동작: 별 출력
}
cout << endl; // 줄 바꿈
}
// 출력값:
// *
// **
// ***
// ****
// *****
return 0;
}
반복의 범위가 명확하다 기보단, 특정 조건만 체크해서 반복하는 경우가 있다. 이럴 때는 while문을 사용하면 코드가 깔끔해진다.
#include <iostream>
using namespace std;
int main() {
int number; // 사용자 입력값을 저장할 변수
cout << "Enter numbers (negative number to stop): ";
cin >> number; // 초기 동작: 첫 번째 입력 받기
while (number >= 0) { // 종료 조건: 입력값이 음수가 아니면 반복
cout << "You entered: " << number << endl; // 실제 동작: 입력값 출력
cin >> number; // 사후 동작: 다음 입력 받기
}
cout << "Program terminated." << endl;
// 출력 예시:
// Enter numbers (negative number to stop): 5
// You entered: 5
// 10
// You entered: 10
// -1
// Program terminated.
return 0;
}

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
srand(time(0)); // 랜덤 시드 초기화
int secretNumber = rand() % 100 + 1; // 1부터 100 사이의 랜덤 숫자
int guess;
cout << "Guess the number (1 to 100): ";
cin >> guess; // 초기 동작: 첫 번째 추측 입력 받기
while (guess != secretNumber) { // 종료 조건: 추측이 정답과 다를 경우 반복
if (guess < secretNumber) {
cout << "Too low! Try again: ";
} else {
cout << "Too high! Try again: ";
}
cin >> guess; // 사후 동작: 새로운 추측 입력 받기
}
cout << "Congratulations! You guessed the number!" << endl;
// 출력 예시:
// Guess the number (1 to 100): 50
// Too low! Try again: 75
// Too high! Try again: 60
// Congratulations! You guessed the number!
return 0;
}

사용자로부터 정수를 입력받아, 해당 크기에 맞는 다이아몬드 모양을 *로 출력하는 프로그램을 작성하시오.
# 예시 1
입력:
4
출력:
*
***
*****
*******
*****
***
*
# 예시 2
입력:
2
출력:
*
***
*
# 예시 3
입력:
5
출력:
*
***
*****
*******
*********
*******
*****
***
*
정답 코드
#include <iostream>
using namespace std;
int main() {
int num;
cout << "입력:" << endl;
cin >> num;
// 다이아몬드 상단부터 가운데까지
for (int i = 1; i <= num; i++) {
for (int j = 1; j <= num - i; j++) {
cout << " ";
}
for (int k = 1; k <= i * 2 - 1; k++) {
cout << "*";
}
cout << endl;
}
// 다이아몬드 하단
for (int i = num - 1; i >= 1; i--) {
for (int j = i; j <= num - 1; j++){
cout << " ";
}
for (int k = 1; k <= i * 2 - 1; k++){
cout << "*";
}
cout << endl;
}
return 0;
}

잘 실행된다. 해설과 비교해보았는데 입력검증 부분빼고는 똑같이 코드를 짜서 놀랐다.
이로써 C++ 프로그래밍 기초 부분은 끝났고 다음 수업부터는 클래스개념 진도를 나간다. 오랜만에 C++을 하는데 그래도 아직 안잊어버렸구나 라는 생각이 드는 하루였다. JAVA C Python C++이런 언어들을 많이 다루다보니 반복문이라던지 조건문이라던지 변수선언이라던지 항상 헷갈리는 것 같다..... 오늘은 함수부터 시작해서 조건문 반복문까지 공부를 했다. 아직 시작도 안한 수준이지만 고수 개발자가 되기위해서는 이런 기초개념이 튼튼해야하기때문에 복습도 꾸준히 해야겠다.