C++ Chapter 18.4 : 흐름 상태와 입력 유효성의 검증

Date:     Updated:

카테고리:

태그:

인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!


chapter 18. 입력과 출력

흐름 상태와 입력 유효성의 검증

🔔 문자열 스트림의 현재 상태 확인하기

첫 번째 방법 👉 ios의 함수들 사용

std::ios : 가장 높은 조상 입출력 클래스다.

image

  • const std::ios & stream일 때
    • stream.good()
      • std::ios::good
      • 스트림의 현재 상태가 좋으면 true 안좋으면 false 리턴
      • 모든 error state flag가 0일 때 flag가 true가 된다.
  • stream.eof()
    • std::ios::eof
    • eof 즉 end of file 에 도달했다면 true 리턴 아니면 false 리턴
    • 파일을 끝까지 다 읽었는지
  • stream.fail()
    • std::ios::fail
    • 스트림 현재 상태가 실패면 true 성공이면 false 리턴.
    • good()의 반대
    • error state flag가 하나라도 1일 경우 flag가 true가 된다.
  • stream.bad()
    • std::ios::bad
    • 데이터를 읽거나 쓸 때 에러가 발생할 때 flag가 true가 된다.

#include <iostream>
#include <string>

using namespace std;

void printStates(const std::ios& stream)
{
	cout << std::boolalpha;		// boolalpha option ON
	cout << "Good() = " << stream.good() << '\n';	// 모든 error state flag가 0일 때 flag가 true가 된다.
	cout << "eof() = " << stream.eof() << '\n';		// stream의 end of file에 도달하면 flag가 true가 된다.
	cout << "fail() = " << stream.fail() << '\n';	// error state flag가 하나라도 1일 경우 flag가 true가 된다.
	cout << "bad() = " << stream.bad() << '\n';		// 데이터를 읽거나 쓸 때 에러가 발생할 때 flag가 true가 된다.
}

int main()
{
	while(true)
	{
	    int i;
	    cin >> i;
	    
	    printStates(cin);
	    
	    cin.clear();
	    cin.ignore(1024, '\n');
	    cout << endl;
	}

	return 0;
}
💎입력💎
123
abc
123.456

💎출력💎
good() = true
eof() = false
fail() = false
bad() = false

good() = false
eof() = false
fail() = true
bad() = false

good() = true
eof() = false
fail() = false
bad() = false
  • printStates(cin)
    • cin 스트림을 넘겨 줌. iostream의 부모클래스인 ios 타입의 참조 변수로 cin 객체를 참조
    • 123 입력
      • int i 에 123이 잘 들어갔다.
      • good() = true. 이상 없음
      • 버퍼가 비워지고 이제 다시 while 반복
    • abc 입력
      • abc는 문자열이므로 int i에 들어갈 수 없다.
      • 논리적 오류 fail() = true
      • good() = false
      • 버퍼가 지워지고 이제 다시 while 반복
    • 123.456 입력
      • 123.456은 double형인데 int i에 123으로 들어갈 수 있음
      • good() = true 이상 없음
      • 버퍼가 지워지고 이제 다시 while 반복


두 번째 방법 👉 bitmask와 rdstate을 사용하여 비트로 흐름 상태 확인

#include <bitset>

#include <iostream>
#include <string>
#include <bitset>

using namespace std;

int main()
{
	while (true)
	{
		int i;
		cin >> i;
													
		printStates(cin);    //   1️⃣ 스트림 상태를 알 수 있는 첫번째 방법  -> ios의 good(), bad(), fail(), eof() 사용 

		/* 2️⃣ 스트림 상태를 알 수 있는 두번째 방법 ->	직접 goodbit, failbit 등등 bit를 사용 */
		cout << boolalpha;
		cout << std::bitset<8>(cin.rdstate()) << endl;
		cout << std::bitset<8>(std::istream::goodbit) << endl;
		cout << std::bitset<8>(std::istream::failbit) << endl;
		cout << !bool((cin.rdstate() & std::istream::failbit) != 0) << endl;

		cin.clear();
		cin.ignore(1024, '\n');  // 버퍼에 남은거 지우기 
		cout << endl;
	}
}
  • 비트를 이용하므로 성능이 좋고 빠르지만 가독성이 떨어진다.
  • std::bitset<8>(cin.rdstate())
    • cin.rdstate()
      • ios의 함수이다.
      • 현재의 에러 상태의 flag 상태를 리턴한다.
        • 이 때의 flag 는 비트 마스크 방식 (bitmask)
  • std::bitset<8>(std::istream::goodbit) - good bitmask = 00000000
  • std::bitset<8>(std::istream::failbit) - fail bitmask = 00000010
  • !bool((cin.rdstate() & std::istream::failbit) != 0) - goodbit가 아닌 failbit로 & 연산 하는 이유 - goodbit는 00000000 이라서.. 에러가 난적이 없으므로 그냥 00000000이다. - rdstate가 fail비트를 가지고 있지 않다면 성공인 상태. - good 상태. - &연산 결과 0이 나올 것. - 0 = 0 이므로 cin.rdstate() & std::istream::failbit) != 0 결과는 false - 성공인 상태 즉 true로 리턴해주어야 하니까 앞에 ! 붙이는 것이다. - !bool((cin.rdstate() & std::istream::failbit) != 0) - rdstate가 fail비트를 가지고 있지 않다면 실패인 상태 - fail인 상태. - 0이 아닌 수가 나올 것. &연산 결과가 fail 비트로 나올 것이다. - 0 ≠ 0 이므로 결과는 true - 실패인 상태 즉 false로 리턴해주어야 하니까 앞에 ! 붙이기 - 이 비트 연산 결과를 bool로 형변환 - cin.rdstate() == std::istream::goodbit; 이렇게 하는 방법도 있음.


🔔 입력 유효성 검증

#include <cctype> 헤더 파일로부터 isalpha, isalnum, isblank 등드으이 함수를 사용하여 내가 원하는대로 입력이 잘 들어갔는지를 검증

  • #include <cctype>
    • isalpha, isalnum, isblank, 등등…
    • 리턴값이 integer 정수다.
      • 0이 아닌 정수면 true로 간주
      • 0이면 false로 간주

예제 1

void printCaracterClassification(const char& input)
{
	cout << std::boolalpha;
	cout << "isalpha = " << bool(std::isalpha(input)) << '\n';	// 입력받은 게 문자인지?
	cout << "isalnum = " << bool(std::isalnum(input)) << '\n';	// 입력받은 게 문자 또는 숫자인지?
	cout << "isblank = " << bool(std::isblank(input)) << '\n';	// 입력받은 게 공백인지?
	cout << "isdigit = " << bool(std::isdigit(input)) << '\n';	// 입력받은 게 숫자인지?
	cout << "islower = " << bool(std::islower(input)) << '\n';	// 입력받은 게 소문자인지?
	cout << "isupper = " << bool(std::isupper(input)) << '\n';	// 입력받은 게 대문자인지?
}
  • 결과를 정수로 리턴하므로 bool로 형변환 하여 출력하였다.

예제 2

bool isAllDigit(const string& str)
{
	bool ok_flag = true;

	for (auto e : str)
		if (!bool(std::isdigit(e)))
		{
			ok_flag = false;
			break;
		}
	return ok_flag;
}

int main()
{
	cout << std::boolalpha;
	cout << bool(isAllDigit("12345")) << '\n';   // true 출력
	cout << bool(isAllDigit("12a34")) << '\n';   // false 출력
}
  • isAlldigit 👉 입력 받은 문자열이 모두 숫자냐
  • bool isAllDigit(const string& str)
    • 입력받은 문자열 str을 한문자씩 다 뜯어서 문자인지 확인


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Cpp 카테고리 내 다른 글 보러가기

댓글 남기기