C++ input

mohadang·2022년 9월 17일
0

C++

목록 보기
2/48
post-thumbnail

Input 스타일

C

안전하지 않음

scanf("%s", buf);

C++

어느정도 대체함 그러나 cin 도 scanf 처럼 메모리 경계를 검사하지 않아서 여전히 위험한 코드이다, 데이터를 주는대로 받고 메모리를 벗어나서 기록한다.

cin >> buf;
char buf[5];
cin >> buf;//"123456789" 입력
cout << buf << endl;//"123456789" 출력, 이미 메모리는 벗어남.

해결책

c 에서는 fgets나 sscanf같은 경계 검사 함수를 사용한다

char line[512];
char temp[512];
char firstName[4];

if (fgets(line, 512, stdin) != NULL) {
    if(sscanf(line, "%s", temp) == 1 && strlen(temp) < 4) {
        strcpy(firstName, temp);
    }
}

C++ 은 다음과 같이 해결한다

//이렇게 하면 3글자만 받아오고 끝에 NULL을 채워준다.
char buf[4];
cin >> setw(4) >> buf;//1234567890 입력
cout << buf << endl;//123 출력
//한번만 적용 되기 때문에 주의...
//4567890 출력 하려는데 Exception
cin >> buf;
cout << buf << endl;
//에러를 막기 위해서는 역시 setw로 길이 설정
//cin >> setw(4) >> buf;//456, 에러 발생하지 않음

데이터 구분

c 와 c++은 데이터 구분을 공백으로 하여 데이터를 읽어 들인다.

"Hello             123     "

C

//firstdata -> Hello
//seconddata -> 123
scanf("%s%d", firstdata, &seconddata);

C++

//firstdata -> Hello
//seconddata -> 123
cin >> firstdata >> seconddata >> endl;

스트림 상태 파악

C

//NULL은 직관적이지 않다, 무슨 의미일까?? 다 읽었다는 것일까?? 아니면 실패??
if (fgets(line, 10, stdin) != NULL) {

}

C++

//End Of File(EOF) char를 읽을때 true
//console에서 입력 받을때 백날 엔터 입력해보았자 eof 플래그를 set 못하고 
//ctrl + z 같이 eof 문자를 입력 시켜야 함
cin >> line;
if (!cin.eof()) {

}

input stream 상태 확인

input stream 상태 확인 api(ios_base)(비트 플래그 / 확인 메서드)

  • goodbit / good() : 스트림이 좋은 상태, 동작 할 수 있는 준비 되어 있음.
  • eofbit / eof() : 파일 포인터가 파일 끝 지점에 있는 eof 문자에 도달
  • failbit / fail() : 읽는것 실패(한번이라도 못 읽으면 실패)
  • badbit / bad()

EX

int number = 10;
cin >> number;
  • 입력 : 456abc // 456까지 읽고 멈춤
    • eofbit : unset(0) // 456까지만 읽었음으로
    • failbit : unset(0) // 456을 정상적으로 읽었음으로
    • 파일 포인터는 'a' 지점에 위치
  • 입력 : 456
    • eofbit unset(0) 되는 경우
      • 456\n
      • console로 입력 받으면 끝이 \n이기 때문에 unset
    • eofbit set(1) 되는 경우
      • 456[eof]
      • a.txt > main.exe
      • 파일로 부터 읽어 들이면 파일 끝에 eof 있으니 set
    • failbit : unset(0)
    • 파일 포인터는 '6' 뒤에 \n 또는 eof
  • 입력 : abc
    • eofbit : unset(0)
    • failbit : set(1)
    • 파일 포인터는 'a' 지점에 위치
  • 입력 : eof
    • eofbit : set(1)
    • failbit : set(1) // set을 숫자로 바꿀 수 없으니

입력 버리기(Discarding input)

clear()

스트림을 좋은 상태(good state) 로 바꿈, fail bit 를 정리(fail bit => 0)

Ex

cin.clear()

ignore()

인자로 넘긴 숫자만큼 버리면 멈춤 또는 파일 끝(eof)에 도달하면 멈춤

cin.ignore();// 문자 한개 버림
cin.ignore(10);// 문자 10개 버림
/*
10개 문자를 버리는데 그전에 '\n' 만나면 멈춤, 
끝나는 문자가 eof가 아니라 '\n'으로 지정
*/
cin.ignore(10, '\n');
cin.ignore(LLONG_MAX, '\n');// 최대 문자수를 버리는데 그전에 \n을 만나면 멈춤
/*
한 단어씩 읽는 도중 잘못된 단어를 입력받고 걸릴때.
한줄을 다 버리는 일반적인 방법
*/
cin.ignore(LLONG_MAX, ' ');

get()

/*
한 문자를 읽는 것 처럼 보이는데 사실은 한 줄을 읽는 것이다. 한문자를 읽을 수 도 있다
Input 1234567, get(buf, 5)
  failbit 설정되지 않음, 다시 get 호출하면 남은 스트림들 다시 읽을 수 있음.
*/
cin.get();
/*
99개의 문자(나머지 하나는 null)를 가져오거나 '\n'을 만나기 전까지 문자를 읽어서 buff에 저장
'\n' 전 까지 모든 문자를 가져오는데 \n은 스트림에 남긴다.
*/
cin.get(buf, 100);
cin.get(buff, 100, '#');// 위와 똑같은데 '\n'대신 #

Ex

char buf[5];
while (true) {
    cin.get(buf, 5);
    cout << buf << endl;
    cout << setfill('-') << setw(6) << "" << endl << setfill(' ');
}
  • 입력 : abc\n
    • \n 전인 'abc' 읽고 출력
    • 계속 무한루프 돈다, 이유는 스트림에는 계속 \n이 남아 있기 때문이다.
  • 입력 : 1234ab\n
    • 4개만 읽는다, 1234 출력
    • \n 전인 'ab' 읽고 출력
    • 계속 무한루프 돈다, 이유는 스트림에는 \n이 있기 때문

Ex

char buf[5];
while (true) {
    cin.get(buf, 5);
    if (cin.fail()) {
      cout << "FAIL" << endl;
    }
    cout << buf << endl;
    cout << setfill('-') << setw(6) << "" << endl << setfill(' ');
}
/*
입력 : 1234567890\n
출력 :
    1234
    ------
    5678
    ------
    90
    ------
    FAIL
Text를 읽을 동안은 Fail bit 설정 안됨
*/

getline()

  • "get과 똑같은데... \n 전 까지 모든 문자를 가져오는데 \n은 스트림에서 버린다."
// failbit 설정됨. 다시 getline 해보았자 스트림에 있는 남은 문자열 못 읽음
// 대신 clear하면 failbit 초기화 되면서 다시 getline 호출하면 읽을 수 있음.
cin.getline(buf, 5);// Input 1234567

Ex

char buf[5];
while (true) {
  cin.getline(buf, 5);
  if (cin.fail()) {
    cout << "FAIL" << endl;
  }
  cout << buf << endl;
  cout << setfill('-') << setw(6) << "" << endl << setfill(' ');
  //cin.clear();
}
/*
입력 : abc\n
  - \n 전인 abc 출력
  - 무한루프 돌지 않는다. 스트림에 남은 \n은 버리기에...
입력 : 1234ab\n
  - 4개만 읽는다, 1234 출력
  - 계속 무한루프 돈다, 이유는 fail비트 설정 되어서 getline이 계속 실패, 스트림에는 ab\n이 남아 있음
  - 루프 끝자락에 clear 해주면 남은 스트림 다시 읽을 수 있음.
*/

get, getline 차이

buffer를 넘어서 입력을 할 때 대처가 다르다.

Ex

  • buffer 길이가 5인데 "abcdefg" 6개의 문자열을 입력 하였을 때

get

char buf[5] = "";
cin.get(buf, 5);
if (cin.fail()) {
  cout << "Fail" << endl;
}
cout << buf << endl;

/*
출력
-> abcd\0

범위를 넘어서는 입력 받아도 fail 아님, 
다시 한번 get 하면 스트림에 남은 데이터를 읽음
*/

getline

char buf[5] = "";
cin.getline(buf, 5);
if (cin.fail()) {
  cout << "Fail" << endl;
}
cout << buf << endl;
/*
출력
-> abcd\0
-> Fail
  :

범위를 넘어서는 입력 받으면 fail임
*/

차이점이 존재하는 이유

  • get은 특정 길이의 문자열을 하나의 포맷으로서 읽어들이는 용도로 만든것 같다.
  • getline은 파일 전체를 끝까지 읽기 위한 용도로 만든 것 같다.

Ex

  • 반복적으로 받을 때
    • "abc" 정상 입력

get

char buf[5] = "";
while (true) {
  cin.get(buf, 5);
  cout << buf << endl;
}
/*
-> abc
->  :
->  :

무한 루프에 빠짐, get이 \n은 스트림에 남기니 get을 호출하면서 
계속 읽을것이 없는 상태로 실패함.
*/

getline

char buf[5] = "";
while (true) {
  cin.getline(buf, 5);
  cout << buf << endl;
}

/*
-> abc
-> 다음 입력 대기
*/

cin

알아서 문자들을 잘 읽는 것 같다.

#include<iomanip>

while (true) {
  cin >> setw(5) >> buf;
  cout << buf << endl;
}
/*
-> abc
  -> 잘 읽고 다음 입력 대기
-> abcdefg
  -> abcd
  -> efg
  -> 잘 읽고 다음 입력 대기
*/
  • 주의할 점 : setw 지정 안하면 범위를 벗어나는 데이터를 받아도 한번에 입력 받아 오버플로우 하면서 까지 버퍼에 값을 넣는다.

Ex

char buf[5];
while (true) {
    cin >> buf;
    if (cin.fail()) {
      cout << "FAIL" << endl;
    }
    cout << buf << endl;
    cout << setfill('-') << setw(6) << "" << endl << setfill(' ');
}
/*
입력 : abc\n
  정상 입력
입력 : 1234ab\n
  buf끝에 NULL을 안 넣고 오버플로우 되어서 값을 넣는다. 
  그래서 결과로는 1234ab가 정상적으로 출력 되는것 같지만
  메모리 범위 넘어서 1234ab가 적히기 때문에 위험.
  그리고 fail bit도 설정이 안된다.
*/

파일로 부터의 입력

  • 파일로 부터의 입력을 받을 때는 어떤 경우라도 eof를 검사해서 루프를 끝마처야 한다. 그렇지 않고 계속 get,getline, >> 으로 읽어들이면 스트림 상태가 fail이 되서 계속 실패하게 된다.
profile
mohadang

0개의 댓글