C & C++ 기초 개념 정리(2) - Flow Control/File I/O
Flow Control
프로그래밍에서 Flow of Control은 프로그램이 특정한 순서로 실행되도록 하는 것입니다. 이를 위해 조건문과 반복문을 사용하며, C++에서는 if-else
, switch
, while
, do-while
, for
등의 구조를 활용합니다
불리언 표현식(Boolean Expressions)
프로그래밍에서 조건을 평가할 때 Boolean Expression을 사용합니다. true
(참) 또는 false
(거짓)를 반환하는 표현식입니다.
비교 연산자
연산자 | 의미 |
---|---|
== | 같음 |
!= | 다름 |
< | 작음 |
> | 큼 |
<= | 작거나 같음 |
>= | 크거나 같음 |
논리 연산자
연산자 | 의미 |
---|---|
&& | 논리 AND (둘 다 참일 때만 참) |
|| | 논리 OR (하나라도 참이면 참) |
! | 논리 NOT (참이면 거짓, 거짓이면 참) |
1
2
3
bool result = (5 > 3) && (10 < 20); // true
bool isEqual = (4 == 4); // true
bool isNotEqual = (7 != 8); // true
이때 &&
의 우선순위가 ||
보다 높기 때문에 이를 유의해야 합니다. 이로 인해 실행 결과가 완전히 달라질 수 있습니다.
1
2
bool result1 = true || false && false; // true
bool result2 = (true || false) && false; // false
위의 예에서 result1
은 &&
가 먼저 평가되어 false && false
가 false
가 되고, 이후 true || false
가 true
가 됩니다. 반면, result2
는 괄호로 인해 true || false
가 먼저 평가되어 true
가 되고, 이후 true && false
가 false
가 됩니다.
연산자 우선순위 (Operator Precedence)
C++에서 연산자는 특정한 우선순위를 가지며, 이는 표현식이 평가되는 순서를 결정합니다. 연산자 우선순위를 이해하면 코드의 동작을 예측하고 오류를 방지할 수 있습니다.
우선순위 | 연산자 | 설명 | 결합 방향 |
---|---|---|---|
1 | () | 괄호 | 좌에서 우 |
2 | ++ , -- | 전위 증가/감소 | 우에서 좌 |
3 | * , / , % | 곱셈, 나눗셈, 나머지 | 좌에서 우 |
4 | + , - | 덧셈, 뺄셈 | 좌에서 우 |
5 | < , <= , > , >= | 비교 연산자 | 좌에서 우 |
6 | == , != | 동등성 비교 | 좌에서 우 |
7 | && | 논리 AND | 좌에서 우 |
8 | \|\| | 논리 OR | 좌에서 우 |
9 | = | 대입 연산자 | 우에서 좌 |
일반적으로 연산 $\rightarrow$ 논리 $\rightarrow$ 대입의 순서대로 우선순위를 갖습니다.
조건문 (Branching Mechanisms)
조건문은 특정 조건이 참인지 거짓인지에 따라 코드의 실행 흐름을 결정합니다.
if-else 문
if-else
문을 사용하여 조건을 평가하고 실행할 코드를 결정할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
int hrs = 45;
double rate = 10.0;
double grossPay;
if (hrs > 40) {
grossPay = rate * 40 + 1.5 * rate * (hrs - 40);
} else {
grossPay = rate * hrs;
}
// grossPay == rate * 40 + 1.5 * rate * 5 == 475.0
중첩된 if-else
if
문 안에 또 다른 if-else
문을 포함할 수 있습니다.
1
2
3
4
5
6
7
if (speed > 110) {
if (speed > 130) {
cout << "You're really speeding!";
} else {
cout << "You're speeding.";
}
}
switch 문
switch
문은 여러 개의 선택지를 가지는 조건문으로, if-else
보다 더 직관적인 구조를 제공합니다.
1
2
3
4
5
6
7
8
9
10
switch (변수) {
case 값1:
// 값1일 때 실행되는 코드
break;
case 값2:
// 값2일 때 실행되는 코드
break;
default:
// 어떤 값에도 해당되지 않을 때 실행되는 코드
}
이때 break;
를 작성해주지 않으면 다음 case로 실행이 넘어가게 됩니다. 이를 fall-through라고 하며, 의도적으로 사용하는 경우도 있지만, 대부분의 경우에는 break;
를 명시적으로 작성하여 이를 방지해야 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
char grade = 'B';
switch (grade) {
case 'A':
cout << "Excellent!";
break;
case 'B':
cout << "Good Job!";
// break;가 없으면 아래 default로 넘어감
default:
cout << "Try harder!";
}
// Good Job!Try harder!
위 코드에서 grade
가 'B'
일 경우, Good Job!
출력 후 Try harder!
도 출력됩니다. 이를 방지하려면 case 'B':
에 break;
를 추가해야 합니다.
반복문 (Loops)
반복문은 특정 조건이 만족될 때까지 코드 블록을 반복 실행합니다.
while 문
while
문은 조건이 참인 동안 반복 실행됩니다.
1
2
3
4
5
int count = 0;
while (count < 3) {
cout << "Hello! ";
count++;
}
do-while 문
do-while
문은 최소 한 번 실행된 후 조건을 평가합니다.
1
2
3
4
5
int count = 0;
do {
cout << "Hello! ";
count++;
} while (count < 3);
while
문과 do-while
문은 반복문으로 사용되지만, 실행 흐름에서 차이점이 있습니다.
구분 | while 문 | do-while 문 |
---|---|---|
실행 조건 | 조건이 참일 때만 실행 | 최소 한 번은 실행된 후 조건을 평가 |
조건 평가 시점 | 반복문 실행 전에 조건을 평가 | 반복문 실행 후에 조건을 평가 |
문법 | 조건 뒤에 세미콜론; 이 필요 없음 | 조건 뒤에 세미콜론; 이 필요함 |
for 문
- 기본 문법
1 2
for (Init_Action; Bool_Exp; Update_Action) Body_Statement
Init_Action
반복문이 실행될 때 초기화되며 실행되는 코드. 주로 반복 변수를 초기화합니다.Bool_Exp
반복문이 실행될 조건을 평가하는 표현식. 조건이 참일 경우 반복문이 실행됩니다.Update_Action
반복문이 실행된 후 수행되는 코드로, 주로 반복 변수의 값을 변경합니다. 생략하더라도 실행이 가능합니다.Body_Statement
조건이 참일 때 실행되는 코드 블록입니다.1 2 3 4
for (int i = 0; i < 3; i++) { cout << "Hello! "; } // Output: Hello! Hello! Hello!
Loop 사용시 주의사항
무한 루프 (Infinite Loops)
반복문을 사용할 때, 종료 조건이 잘못 설정되거나 누락되면 무한 루프가 발생할 수 있습니다. 이는 프로그램이 종료되지 않고 계속 실행되는 상태를 의미합니다.
1
2
3
4
5
int i = 0;
while (i < 5) {
cout << i << " ";
// i++; // 주석 처리로 인해 무한 루프 발생
}
위 코드에서 i++
가 누락되어 i
의 값이 계속 0으로 유지되므로 무한 루프가 발생합니다. 이를 방지하려면 반복문 내에서 조건을 변경하는 코드를 반드시 포함해야 합니다.
조건 변경에 대한 코드가 있더라도 무한루프에 빠지는 오류를 범할 수도 있습니다.
1
2
3
4
5
int i = 0;
while (i < 5);/* ; 로 인해 Body_Statement 실행불가! */ {
cout << i << " ";
// i++; // 주석 처리로 인해 무한 루프 발생
}
위와 같이 조건 표현식 바로 뒤에 ;
를 사용하게 되면 해당 지점에서 반복이 일어나게 되고, Body_Statement가 실행되지 않아 무한루프에 빠지게 됩니다.
임베디드 시스템 등에서는 무한루프를 의도적으로 사용할 수도 있습니다.
break와 continue
break
반복문을 즉시 종료하고 반복문 이후의 코드로 실행 흐름을 이동시킵니다.1 2 3 4 5
for (int i = 0; i < 10; i++) { if (i == 5) break; cout << i << " "; } // Output: 0 1 2 3 4
continue
현재 반복을 건너뛰고 다음 반복을 실행합니다.1 2 3 4 5
for (int i = 0; i < 10; i++) { if (i % 2 == 0) continue; cout << i << " "; } // Output: 1 3 5 7 9
반복문 중첩 (Nested Loops)
반복문 안에 또 다른 반복문을 포함할 수 있습니다. 이때, 내부 반복문이 종료된 후 외부 반복문이 실행됩니다.
1
2
3
4
5
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 2; j++) {
cout << "i: " << i << ", j: " << j << endl;
}
}
위 코드의 출력은 다음과 같습니다:
1
2
3
4
5
6
i: 1, j: 1
i: 1, j: 2
i: 2, j: 1
i: 2, j: 2
i: 3, j: 1
i: 3, j: 2
중첩된 반복문은 복잡한 데이터 구조를 처리하거나 다차원 배열을 순회할 때 유용하게 사용됩니다.
중괄호를 생략한 경우
C++에서는 조건문이나 반복문에서 실행할 코드가 한 줄일 경우 중괄호 {}
를 생략할 수 있습니다. 하지만 이는 코드의 가독성을 떨어뜨리거나 의도하지 않은 동작을 유발할 수 있으므로 주의가 필요합니다.
1
2
3
if (x > 0)
cout << "Positive number";
cout << "This line is always executed.";
위 코드에서 if
조건문에 중괄호를 생략했기 때문에 cout << "This line is always executed.";
는 조건과 상관없이 항상 실행됩니다. 이를 방지하려면 중괄호를 명시적으로 작성해야 합니다.
1
2
3
4
if (x > 0) {
cout << "Positive number";
cout << "This line is always executed.";
}
1
2
3
while (x > 0)
cout << x;
cout << x--;
바로 위 예시에선, 들여쓰기 때문에 마치 두 줄이 while 루프 안에 있는 것처럼 보이지만, 실제로는 한 줄만 루프에 포함됩니다. 따라서 x는 루프 내에서 줄어들지 않아서 무한 루프가 발생 가능합니다. 반복문에서도 중괄호를 명시해야합니다.
1
2
3
4
while (x > 0){
cout << x;
cout << x--;
}
파일 입출력
파일 입출력 (File Input/Output)
C++에서는 파일을 읽고 쓰기 위해 <fstream>
헤더를 사용합니다. 주요 클래스는 다음과 같습니다:
ofstream
: 파일에 데이터를 쓰기 위한 클래스ifstream
: 파일에서 데이터를 읽기 위한 클래스fstream
: 파일 읽기와 쓰기를 모두 지원하는 클래스
파일 쓰기 (Writing to a File)
파일에 데이터를 쓰기 위해 ofstream
객체를 사용합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ofstream outFile("example.txt");
if (outFile.is_open()) {
outFile << "Hello, File!" << endl;
outFile << "This is a test." << endl;
outFile.close();
} else {
cout << "Unable to open file for writing." << endl;
}
return 0;
}
위 코드는 example.txt
파일에 데이터를 작성합니다. 파일이 성공적으로 열리지 않으면 오류 메시지를 출력합니다.
파일 읽기 (Reading from a File)
파일에서 데이터를 읽기 위해 ifstream
객체를 사용합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
ifstream inFile("example.txt");
string line;
if (inFile.is_open()) {
while (getline(inFile, line)) {
cout << line << endl;
}
inFile.close();
} else {
cout << "Unable to open file for reading." << endl;
}
return 0;
}
위 코드는 example.txt
파일의 내용을 한 줄씩 읽어와 출력합니다.
파일 읽기와 쓰기 (Reading and Writing)
fstream
객체를 사용하면 파일 읽기와 쓰기를 동시에 수행할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <fstream>
#include <iostream>
using namespace std;
int main() {
fstream file("example.txt", ios::in | ios::out | ios::app);
if (file.is_open()) {
file << "Appending this line to the file." << endl;
file.seekg(0); // 파일의 시작으로 이동
string line;
while (getline(file, line)) {
cout << line << endl;
}
file.close();
} else {
cout << "Unable to open file." << endl;
}
return 0;
}
위 코드는 파일에 데이터를 추가한 후, 파일의 내용을 읽어 출력합니다.
파일 열기 모드 (File Open Modes)
파일을 열 때 사용할 수 있는 모드는 다음과 같습니다:
모드 | 설명 |
---|---|
ios::in | 읽기 모드로 파일 열기 |
ios::out | 쓰기 모드로 파일 열기 |
ios::app | 파일 끝에 데이터를 추가 |
ios::trunc | 파일 내용을 열 때 삭제 |
ios::binary | 바이너리 모드로 파일 열기 |
여러 모드를 조합하여 사용할 수 있습니다. 예를 들어, ios::in | ios::out
은 읽기와 쓰기를 동시에 수행합니다.
파일 스트림 상태 확인
파일 스트림의 상태를 확인하기 위해 다음 멤버 함수를 사용할 수 있습니다:
is_open()
: 파일이 성공적으로 열렸는지 확인eof()
: 파일의 끝에 도달했는지 확인fail()
: 파일 스트림에 오류가 발생했는지 확인bad()
: 심각한 오류가 발생했는지 확인
1
2
3
4
5
6
ifstream file("example.txt");
if (!file.is_open()) {
cout << "Error opening file." << endl;
} else if (file.fail()) {
cout << "File stream failed." << endl;
}
파일 입출력은 데이터를 영구적으로 저장하거나 외부 데이터를 처리할 때 매우 유용합니다.
해당 포스트는 서울대학교 전기정보공학부 정교민 교수님의 프로그래밍방법론 25-1학기 강의를 정리한 내용입니다.