본 내용은 POCU COMP3200: C++ 언매니지드 프로그래밍 강의를 토대로 작성하였습니다.
1. 입력 스트림(Input Stream)
- 키보드에서 읽기
- scanf는 왜 위험한가?
- scanf()는 경계검사를 하지 않는다!
- 경계검사 : 내가 사용하는, 쓸 메모리가 실제 내가 가진 메모리 내부에 들어가니? 들지 않으면 안전하게 연산을 하겠다. exception 등을 던진다. C 스타일의 문자열은 Character Array, 바꿔 말하면 Character Pointer임. 그래서 어느 정도의 메모리가 할당되어 있는지 실행 중에는 알 수 없음. 그래서 string 제일 뒤에 특수한 Character을 넣어서 string이 끝나는 것을 표시함. 이게 NULL Character Stream.
- 위 예제에서 문자 끝에 NULL 캐릭터가 있어야 하는데 NULL 캐릭터를 넣으려 하니까 빨간색 부분이 우리가 소유하지 않은 메모리임. 따라서 우리가 소유하지 않은 메모리를 덮어 쓰는 문제가 생김.
- scanf는 char*를 받음. character array는 char pointer. char*를 받는데 그것의 길이를 알 수 없으니 무조건 읽음. 이걸 해결하려면? 5개로 잡아주면 됨. 하지만 이게 범용적인 솔루션은 아님. 다른 이름이 긴 글자가 들어간다면?
- cin은 같은 문제가 있을까?
- 똑같은 문제가 있음. 이유 ? char 배열과 char 포인터는 같음
- C++에서 쓸 수 있는 더 안전한 방법 - setw() 내가 가진 버퍼 사이즈가 4글자 밖에 없으니 알아서 읽어오라고 하면 세 글자만 읽어오고 NULL 캐릭터를 붙여줌
2. 스트림 상태 (Stream States)
- cin, cout은 스트림. 이 스트림에서 뭔가를 읽어 왔는데 가끔은 읽어올 때 실패할 때가 있을 것.
- 그럼 실패 했다는 것을 어떻게 확인? 성공, 실패 여부 찾기 위해 상태가 자동적으로 저장됨 file의 마지막(end-of-file)을 만나지 않았으면 진행해라 / NULL은 직관적이지 않음
1) 456까지 읽고 a에서 멈춤. 456까지 무사히 읽었기 때문에 eof는 아니고(a가 eof가 아니니까) 실제 숫자 읽었으니 failbit set가 안됨
2) 456 넣었을 때 제대로 읽고(failbit == unset) 커서가 6 다음에 와있는건데 set이 될 수도 있고 안될수도 있음
- 언제 set이 안돼?
- 콘솔에서 데이터 입력할 때 456하고 엔터 치면 뒤에 뉴라인 캐릭터가 있기 때문에 무사히 읽고 뉴라인 캐릭터는 eof가 아니기 때문에 unset.
- 언제 set이 됨?
- input을 콘솔에서 하는 게 아니라 텍스트파일로 저장해두고 콘솔에서 치는 것 처럼 리디렉션을 할 수 있음.
- 이렇게 하면 456뒤에 엔터 안치고 저장할 수 있어서 마지막 캐릭터가 eof가 되기 때문에 set이 됨
- 그래서 eof 처리하는 코드 쓸 때 이 두가지 경우를 모두 테스트 해봐야 함.
3) abc를 숫자로 읽을 방법은 없으니 failbit가 set이 되고 실패를 하고 아직도 포인터는 a를 가리키고 있음. 따라서 eofbit은 set이 안됨
4) eof를 넣었을 땐 eof니까 set 되고 숫자가 아니니까 failbit도 set
//알파벳 e o f가 아니라 eof 입력하는 방법 있음. 구글에 쳐보기
3. 입력 버리기(Discarding Input) : clear(), ignore()
- clear()
- 스트림을 좋은 상태(good state)로 돌려 줌
cin.clear();
- 언제 써?
- 스트림이 좋지 않은 상태가 되었을 때. failbit이 들어왔다거나 eof가 들어왔을 때 다시 스트림을 아무 문제 없는 상태(문제 있는 bit가 설정되었을 때 그걸 그냥 지워줄 때)로 만들어줌
- 보통 대응 다 하고 스트림 상태 좋게 만들고 시도해볼 때 씀
- ignore()
- 아래 예제들은 파일 끝에 도달하거나 지정한 수 만큼 문자를 버리면 멈춤
cin.ignore(); //문자 1개를 버림
cin.ignore(10); //문자 10개를 버림
-
- 언제 써?
- abc를 숫자로 읽으려 했는데 못 읽은 경우 포인터가 계속 a에 머무르니까 그걸 건너뛰고 싶을 때 씀.
- 언제 써?
- 문자 10개를 버림. 단, 그 전에 뉴라인(new line) 문자를 버리면 곧바로 멈춤
cin.ignore(10,'\n');
- 최대 문자 수를 버림. 단, 그 전에 뉴라인 문자를 버리면 곧바로 멈춤
cin.ignore(LLONG_MAX,'\n');
4. 입력 버리기 : get(), getline()
- 둘다 한줄 읽어오는데 입력 스트림을 남기냐 버리냐 차이
- get()
- 뉴라인 문자를 만나기 직전까지의 모든 문자를 가져옴
- 뉴라인 문자는 입력 스트림에 남아 있음
- 99개 문자를 가져오거나 뉴라인 문자가 나올 때 까지의 문자를 가져오고, 가져온 문자들을 char 배열(firstName)에 배치함
get(firstName, 100);
- 99개 문자를 가져오거나 '#' 문자가 나올 때 까지의 문자를 가져오고, 가져온 문자들을 char 배열(firstName)에 배치함
get(firstName, 100, '#');
- getline()
- 뉴라인 문자를 만나기 직전까지의 모든 문자를 가져옴
- 뉴라인 문자는 입력 스트림에서 버림
getline(firstname,100);
getline(firstname,100,'#');
코드 샘플 : 정수의 합 구하기
#include "AddIntegers.h"
#include <iostream>
using namespace std;
namespace samples
{
void AddIntegersExample()
{
cout << "+------------------------------+" << endl;
cout << "| Add Integers Example |" << endl;
cout << "+------------------------------+" << endl;
int number;
int sum = 0;
while (true)
{
cout << "Please enter an integer or EOF: ";
cin >> number;
if (cin.eof())
{
break;
}
if (cin.fail())
{
cout << "Invalid input" << endl;
cin.clear();
cin.ignore(LLONG_MAX, '\n');
continue;
}
sum += number;
}
cin.clear();
cout << "The sum is " << sum << endl;
}
}
코드 샘플 : getline() / 입력된 문자열 뒤집기 (면접 문제 많이 나옴 기본임)
#include "ReverseInputString.h"
#include <iostream>
using namespace std;
namespace samples
{
void ReverseInputStringExample()
{
cout << "+------------------------------+" << endl;
cout << "| Reverse String Example |" << endl;
cout << "+------------------------------+" << endl;
const int LINE_SIZE = 512;
char line[LINE_SIZE];
cout << "Please enter a string to reverse" << endl
<< "or EOF to quit: ";
cin.getline(line, LINE_SIZE);
if (cin.fail())
{
cin.clear();
return;
}
char* p = line;
char* q = line + strlen(line) - 1;
while (p < q)
{
char temp = *p;
*p = *q;
*q = temp;
++p; //포인터 증가
--q; //포인터 감소
}
cout << "Reversed string: " << line << endl;
}
}
'C++' 카테고리의 다른 글
[C++] 참조(Reference) (0) | 2022.01.22 |
---|---|
[C++] Bool 데이터형 (0) | 2022.01.21 |
[C++] C 스타일 배열과 std::array (0) | 2022.01.20 |
[C++] 출력(Output) (0) | 2022.01.04 |
Overriding, Virtual 함수 (0) | 2021.09.14 |
댓글