Chapter 6. Brancing Statements and Logical Operators

지환·2022년 6월 17일
0

The if Statement

test-condition은 bool 값으로 변환

if-else문 전체는 하나의 statement로 간주됨
if-else가 여러개 이어지는 경우도 결국 첫번째 else 뒤로 모두 묶이는 것이기때문에,
아무리 크더라도 하나의 statement로 간주된다.

`if (3 == house) ~~` 식으로 변수와 숫자를 뒤집어서 작성하는 습관은 오류 발생시에 찾기 쉽다.
실수로 `if (3 = house) ~~`로 적으면 오류가 잘 뜨니까..

Logical Expressions

||&& operator는 sequence point (C++11에선, 왼쪽 subexpression이 오른쪽 subexprssion보다 먼저 sequenced되다고 함)
+short circuit (이 용어를 쓰진 않는데 뭐 어쨌든 같은 기능)

! operator는 보통 "bang"이라고 말한다고 하네. !x는 "bang-ex"

여러 조건이 쓰일때 굳이 괄호가 필요없더라도 쓰는게 나쁘진 않다.
이해하기도 좋고, 잠재적 error 줄일 수 있고, precedence rule 굳이 다 기억할 필요도 없고...

Alternative Representation

keyboard에서 ||&&를 입력하지 못할 수도 있다.
이런 상황을 대비해 C++에선 and, or, not을 예약해뒀고, 각각 대응하는 operator를 대체해 사용할 수 있도록 한다.

C에서도 <iso646.h> header file을 include하면 이용할 수 있지만 C++처럼 기본적으로 저 단어가 예약돼있진않고,
C++ 에선 header file 없이도 사용할 수 있다.


cctype Library

C의 ctype.h header의 C++버전,,
character 다루는 함수들 제공, isalpha()
여기 함수들의 반환 type은 int

if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
이런식으로 하는건 ASCII 코드처럼 연속된 code라는게 보장돼야만 가능하다.
if (isalpha(ch)) 이게 더 general한 형태


The switch Statement

switch (integer-expression) {
	case label1 : ~~
    case label2 : ~~
    . . .
    default     : ~~  //default는 선택
}

integer-expressioninteger value를 산출해야한다.
labelinteger constant expression이어야 한다.

label에 enumerator를 사용할 수 있다. (알아보기 편함)

선택지들이 integer constant로 정해지고, 3개 이상이라면
그 상황에 맞게 만들어진 switch가 if-else보다 좋다.
code size면에서도 그렇고, execution speed면에서도 그렇고

이번엔 숫자 input (Number-Reading)

(앞서 ch5에서 봤던 문자 입력 부분에선, 어차피 숫자가 문자에 포함되므로 크게 신경쓸 게 없었다. 근데 숫자를 입력받으려면 문자를 걸러줘야함
C로 비교하자면 cin은 scanf, 앞서배운 cin.get() 같은애들은 getc. scanf도 %c일땐 문자든 숫자든 상관없었지만, %d일땐 문자면 문제있었음.
cin은 어떻게 처리하는지 한번 보자.)

int n;
cin >> n;

여기서 숫자가 아니라 단어같은걸 입력하면? input 실패하면?
mismatched input은 input queue에 남고,
cin object의 error flag가 setting 된다.(== 그다음 input은 모두 거부)
n값은 변하지 않는다.

그리고 >> operator가 내부적으로는 cin method를 호출한 것이되는데(ch4 정리해둔거에 보면 있음), 이 cin method는 cin object를 반환한다. ch 5에서 봤다시피 cin object는 bool로 변환돼야 할 곳에서 자동으로 변환된다. 그래서 만약 input에 실패했을때 while이나 if의 condition check하는 곳에서 호출한다면 false가 된다.

그러므로

int i;
while (cin >> i) ; //숫자가 입력되는 동안 반복

혹은

int i;
cin >> i;
while (cin) {
	cin >> i;
}

와 같이 작성해서 입력 오류시(==문자입력시) 입력을 멈출 수 있다.

문자 입력받고 끝내는게 아니라 계속 input 받고 싶다면?
바로 위에서 말한 요인들을 다 해결해주면 된다.
1) input queue에 남은걸 다 없애주고
2) cin을 reset해서 flag 없애주고 (안그러면 다음 input들 모두 거부됨)
그 다음 다시 input을 받으면 된다.

2)의 경우,,,
cin.claer() 함수는 EOF condition과 마찬가지로 bad input flag도 reset한다.
이를 이용,,,

ex)

while (!(cin >> golf[i])) {
	cin.clear();
    while (cin.get() != '\n')
    	continue;
    cout << "Please enter a number: ";
}
cin이 stream인건가? C에선 모든 stream이 error/EOF indicator를 가졌는데,
cin도 그런 모양이네
뭐 더 배우면 자세히 알겠지

보면 알겠지만, cin으로 입력받을때 char 변수에 입력받는게 처리하긴 더 좋다.
int 변수에 입력받으면 character 들어왔을때 더 이상 처리되지 않을 가능성 있지만,
처음부터 char 변수에 입력받으면 모두 char로 처리될 수 있어서 그럴 걱정이 덜하다.
ex) p.300 8번


Simple File I/O

Ch17에서 자세히 알아보겠지만,, 일단 간단한 text I/O

keyboard input, screen output -> console I/O
file input, file output -> file I/O

cin, Text Files

cin을 사용하면 일단 1byte들로 해석해서 character로 읽어온다. 이후 변수 type에 맞게 변환해 저장

char이면 읽어온대로 저장
int이면 non-digit character 전까지 읽고 변환해 저장 (이후 남은 부분은 남겨둠)
double이면 floating point 숫자에 포함될 수 없는 부분 전까지 읽고 변환해 저장
char []이면 whitespace character 전까지 읽고, null character 끝에 추가해서 저장

cin.getline(str, 50); 을 사용하면, newline character 이전까지 읽고, 끝에 '\0'을 추가해 저장
newline character는 버림

cin을 왜 갑자기 정리?
: 결국 text로 모든게 처리된다는걸 상기시킴. 일단 character code에 맞게 읽어오고, 그 다음 변환을하든 뭘 하든 진행된다.
마찬가지로 file I/O를 할때도 text file을 사용해야한다.
숫자를 그냥 숫자형태 그대로 저장하는 등 꼭 모든 file이 text file인 것은 아니다.(그 중 한 종류가 text file)

Writing to Text File (Output)

  • fstream header file을 include해야한다.
    (cout을 쓰기위해 iostream header file 썼었다.)

  • fstream header file은 output을 다루는 ofstream class를 정의한다.
    (마찬가지, cout은 iostream에 정의된 ostream class의 object였다.)

  • ofstream object를 내가 declare해야한다.
    (ostream object인 cout은 predefined object)

  • 마찬가지로 std namespace이다. std::를 쓰던가 using directive/declaration하던가

  • 내가 만든 ofstream object와 특정 file을 연결해야한다. open() method를 이용
    (cout은 이미 standard stream과 연결돼있어서 이런 작업이 딱히 필요없었던거 같네)

  • 작업완료 후 close() method 이용해서 파일 닫아야한다.

  • ofstream object에도 cout에 했던 것처럼 << operator를 이용해서 다양한 type data output 가능

ex)

#include <fstream>
using namespace std;
. . .
ofstream oFile;
oFile.open("Dictionary.txt");

oFile << fixed;
oFile.precision(2);
oFile.setf(ios_base::showpoint);
oFile << "abc";

oFile.close();

cout에 했던 것 정확하게 똑같이 사용할 수 있다. cout에 가능한 모든 operatin이나 method는 똑같이 적용가능하다.
open()에는 C-style string만 올 수 있다.(char배열 or string literal)

파일 close 안하면, 프로그램이 정상적으로 종료된다면 자동으로 close된다.

파일 open하는데 없던 파일이라면? 알아서 자동 생성된다.
파일 open하는데 있던 파일이라면? 원래 있던 내용은 날아가고 덮어씌워진다.
(기본 설정이 이런거고 나중에 조작하는 법 배움)

정확한 정보는 아니긴한데,,,
java에선 객체(instance) 생성하려면 `Tv t = new Tv();` 식으로 쓰였는데,
이걸 C로 보자면 t가 마치 pointer 역할을 한다. 그래서 new를 통해 새 객체 공간만큼 할당해준다.
근데 C++에선 보니까 객체(object) 생성하려면 그냥 `Tv t;` 식으로 해주고 마네.
class로 선언된 type도 마치 일반 변수 선언하듯이 해주는게 그 차이인 것 같다.

Reading from a Text File

  • fstream header file을 include해야한다.
    (cin을 쓰기위해 iostream header file 썼었다.)

  • fstream header file은 output을 다루는 ifstream class를 정의한다.
    (마찬가지, cin은 iostream에 정의된 istream class의 object였다.)

  • ifstream object를 내가 declare해야한다.
    (istream object인 cin은 predefined object)

  • 마찬가지로 std namespace이다. std::를 쓰던가 using directive/declaration하던가

  • 내가 만든 ifstream object와 특정 file을 연결해야한다. open() method를 이용
    (cin은 이미 standard stream과 연결돼있어서 이런 작업이 딱히 필요없었던거 같네)

  • 작업완료 후 close() method 이용해서 파일 닫아야한다.

  • ifstream object에도 cin에 했던 것처럼 << operator를 이용해서 다양한 type data input 가능
    get()을 이용해서 한 문자씩 읽어오거나, getline()을 이용해서 한 line씩 읽어올 수 있다.
    eof()fail()을 이용해 input fail을 test할 수 있다.

  • ifstream object가 test condition에서 쓰이면, 마지막 reading 시도에 따라 true/false 반환
    (cin도 이럼)

사용
cin에 했던 것 정확하게 똑같이 사용할 수 있다. cin에 가능한 모든 operatin이나 method는 똑같이 적용가능하다.
또 위와 마찬가지로 open() 함수에는 C-style String만 올 수 있다.

Open 성공 여부
파일 open이 열렸는지 확인하려면 is_open() 함수를 이용
여는데 성공했으면 true, 실패했으면 false 반환

if (!inFile.is_open()) {  //inFile은 ifstream object
	exit(EXIT_FAILURE);   //exit 함수와 EXIT_FAILURE은 cstdlib header에 정의돼있다.
}

is_open()이 없다면 good()을 사용 (대신 is_open()만큼 잠재적 problem을 탐지하진못함)

C++ text mode에서는 C에서처럼 lineFeed+carriageReturn 같은건 알아서 변화해준다.

Input 중 오류 탐지
(앞에 관련 내용들 여기로 다 합쳐지는듯)

  • eof() : EOF을 만나고나면 true 반환 (eofbit 세팅되있겠지당연히)

  • fail() : 가장 최근 reading에서 type mismatch라면 true 반환 (eofbit과 failbit 모두 보기때문에 EOF여도 true반환함)

  • bad() : corrupted file이나 hardware failure의 경우 true 반환

  • good() : (위 3개 다 포함하는 놈) 가장 최근 reading에서 아무 이상 없으면 true 반환

그래서 보통 good()으로 판단한다.
bad도 flag가 있고, good은 위 3가지 bit flag를 모두 check

open 성공여부도 그렇고 만능이네 ㅋㅋ 뭐 그땐 is_open()을 보통 쓴다만은

good() 대신 cin할때 했던 것처럼 ifstream object가 test condition에서 bool로 변환되는거 이용해도 된다.
while (inFile >> value)
이렇게하면 괄호안의 식 값이 inFile로 된다.
그리고 inFileinFile.good()로 계산된다.
즉, good()처럼 위 오류 모두 잡아낸다.

object가 bool로 변환될때 `good()` 함수를 이용한다는 말이다.
즉, 이렇게 쓰나 good() 쓰나 그게 그거
good() 함수로 쓸때는 앞뒤로 input따로 받아줘야돼서 불편했는데,
그냥 제일 마지막 code처럼 쓰는게 best인듯
어차피 오류들 다 포괄해서 잡으니까

Summary

logical operators를 이용해 여러 relational expressoins 묶어서 더 정교한 식 표현 가능

cctype library의 함수들을 통해 character input을 분석하는 강력하고 간단한 툴을 제공

ifstream이나 ofstream object를 만들어서 file가 연결하고, cincout에 하듯이 똑같이 다룰 수 있다.


Reveiw

아래 code 전자와 후자 차이?

while (cin.get(ch)) {
	if (ch == ' ')
    	space++;
    if (ch == '\n')
    	newlines++;
}
while (cin.get(ch)) {
	if (ch == ' ')
    	space++;
    else if (ch == '\n')
    	newlines++;
}

후자는 else if가 쓰인게 차이인데, 이 경우(후자)에 첫번째 조건이 맞으면 뒤는 skip하므로 더 효율적이다.(근거: p.256)

아래 두 코드 차이는?
cout << ++ch;, cout << ch+1; (ch는 char type)
앞 코드는 char을 print, 뒤 코드는 연산하며 int로 변환돼서 int로 print된다.

!!xx인가?
x10(true)이면 0(false)로 변환되고 다시 1(true)로 변환된다.
x가 애초에 bool type이었거나 0이었다면 그렇겠지만 항상 그렇진 않다.

true, false나 1, 0이나 그게 그거라서 같이 적음

영단어

intact 온전한
parlance (특정 집단의) 말투
conceal 숨기다
reprehensible 부끄러운, 비난받을만한
parallel 평행한, 유사한
configured (컴퓨터의) 환경을 설정하다
configuration 배열, 배치, 환경설정

0개의 댓글