입력을 읽은 후 cin.clear () 및 cin.ignore ()를 호출하는 이유는 무엇입니까?


86

이 코드를 사용하는 데 사용 된 Google Code University의 C ++ 자습서 :

// Description: Illustrate the use of cin to get input
// and how to recover from errors.

#include <iostream>
using namespace std;

int main()
{
  int input_var = 0;
  // Enter the do while loop and stay there until either
  // a non-numeric is entered, or -1 is entered.  Note that
  // cin will accept any integer, 4, 40, 400, etc.
  do {
    cout << "Enter a number (-1 = quit): ";
    // The following line accepts input from the keyboard into
    // variable input_var.
    // cin returns false if an input operation fails, that is, if
    // something other than an int (the type of input_var) is entered.
    if (!(cin >> input_var)) {
      cout << "Please enter numbers only." << endl;
      cin.clear();
      cin.ignore(10000,'\n');
    }
    if (input_var != -1) {
      cout << "You entered " << input_var << endl;
    }
  }
  while (input_var != -1);
  cout << "All done." << endl;

  return 0;
}

의 중요성 무엇 cin.clear()cin.ignore()? 10000\n매개 변수가 필요한 이유는 무엇 입니까?


2
이것은 지금까지 가장 많이 투표 한 게시물입니다. 나는 고등학교에서 정점에 도달했을 것입니다.
JacKeown 2010 년

답변:


104

(가) cin.clear()에 오류 플래그를 지 웁니다 cin(즉 미래의 I / O 작업이 제대로 작동 할 수 있도록), 다음 cin.ignore(10000, '\n')다음 줄 바꿈으로 건너 뜁니다 (비 번호와 같은 줄에 다른 것을 무시하기 때문에 다른 구문 분석 오류가 발생하지 않습니다 것을) . 최대 10000 자까지만 건너 뛰므로 코드는 사용자가 매우 길고 잘못된 줄에 입력하지 않는다고 가정합니다.


59
+1. 최대 10000 문자를 무시하는 대신을 사용하는 것이 좋습니다 cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');.
Dennis

31
사용 std::numeric_limits하려면 #include <limits>.
gbmhunter 2014

1
누군가 구문을 설명 할 수 있습니까 std::numeric_limits<std::streamsize>::max()?
민 트란

4
@Minh Tran : std :: streamsize는 전송 된 I / O 문자 수 또는 I / O 버퍼 크기를 제공하는 부호있는 정수입니다. 여기서는 "numeric_limits"템플릿 클래스를 사용하여 I / O 버퍼 또는 전송되는 문자의 최대 제한을 알고 싶었습니다.
Pankaj

1
@Minh Tran : 하나의 사소한 수정 "streamsize"는 클래스가 아니라 정수 유형입니다. 우리는 다른 사람의 한계도 얻을 수 있습니다. int, char 등 .. [link]에서 확인하십시오 ( en.cppreference.com/w/cpp/types/numeric_limits )
Pankaj

47

당신은 입력

if (!(cin >> input_var))

cin에서 입력을 가져올 때 오류가 발생하면 명령문. 오류가 발생하면 오류 플래그가 설정되고 향후 입력 시도가 실패합니다. 그래서 당신은

cin.clear();

오류 플래그를 제거합니다. 또한 실패한 입력은 일종의 버퍼라고 가정합니다. 다시 입력을 시도하면 버퍼에서 동일한 입력을 읽고 다시 실패합니다. 그래서 당신은

cin.ignore(10000,'\n');

버퍼에서 10000자를 꺼내지 만 개행 문자 (\ n)를 만나면 중지됩니다. 10000은 일반적인 큰 값입니다.


11
무시의 기본값은 단일 문자를 건너 뛰는 것이므로 전체 행을 건너 뛰려면 더 큰 숫자가 필요합니다.
Bo Persson

25

우리가 사용하는 이유 :

1) cin.ignore

2) cin.clear

?

간단히:

1) 스트림에서 원하지 않는 값을 무시 (추출 및 삭제)

2) 스트림의 내부 상태를 삭제합니다. cin.clear를 사용한 후 내부 상태는 다시 goodbit로 설정되어 '오류'가 없음을 의미합니다.

긴 버전 :

무언가가 'stream'(cin)에 있으면 거기에서 가져와야합니다. 'taken'은 스트림에서 '사용됨', '제거됨', '추출 됨'을 의미합니다. 스트림에는 흐름이 있습니다. 데이터는 하천의 물처럼 cin에 흐르고 있습니다. 당신은 단순히 물의 흐름을 멈출 수 없습니다.)

예를보십시오.

string name; //line 1
cout << "Give me your name and surname:"<<endl;//line 2
cin >> name;//line 3
int age;//line 4
cout << "Give me your age:" <<endl;//line 5
cin >> age;//line 6

사용자가 첫 번째 질문에 "Arkadiusz Wlodarczyk"라고 대답하면 어떻게됩니까?

프로그램을 실행하여 직접 확인하십시오.

콘솔 "Arkadiusz"에 표시되지만 프로그램은 '나이'를 묻지 않습니다. "Arkadiusz"를 인쇄 한 직후에 완료됩니다.

그리고 "Wlodarczyk"는 표시되지 않습니다. 사라진 것 같다 (?) *

어떻게 된 거예요? ;-)

"Arkadiusz"와 "Wlodarczyk"사이에 공백이 있기 때문입니다.

이름과 성 사이의 "공백"문자는 '입력'스트림에서 추출되기를 기다리는 두 개의 변수가 있음을 나타내는 컴퓨터의 표시입니다.

컴퓨터는 당신이 하나 이상의 변수를 입력하기 위해 묶고 있다고 생각합니다. 그 "공백"표시는 그가 그것을 그렇게 해석하는 표시입니다.

따라서 컴퓨터는 "Arkadiusz"를 '이름'(2)에 할당하고 스트림 (입력)에 둘 이상의 문자열을 입력하기 때문에 컴퓨터는 변수 'age'(!)에 "Wlodarczyk"값을 할당하려고 시도합니다. 사용자는 해당 명령이 이미 실행 (!) 되었기 때문에 6 행의 'cin'에 아무것도 넣을 기회가 없습니다. 왜? 스트림에 아직 뭔가가 남아 있었기 때문입니다. 그리고 앞서 말했듯이 스트림은 흐름에 있으므로 가능한 한 빨리 모든 것을 제거해야합니다. 그리고 가능성은 컴퓨터가 cin >> age 명령을 보았을 때 나타났습니다.

컴퓨터는 누군가의 나이를 저장하는 변수를 생성했음을 알지 못합니다 (4 행). '연령'은 단순한 레이블입니다. 컴퓨터의 경우 '연령'은 'afsfasgfsagasggas'라고도 할 수 있으며 동일합니다. 그를 위해 그것은 단지 "Wlodarczyk"를 할당하려고 시도하는 변수 일뿐입니다. 당신이 (6) 줄에서 그렇게하도록 컴퓨터를 지시 / 지시했기 때문입니다.

그렇게하는 것은 잘못이지만, 해낸 건 당신이에요! 당신 잘못이에요! 글쎄, 아마도 사용자이지만 여전히 ...


좋아요. 그러나 그것을 고치는 방법?!

몇 가지 더 흥미로운 것들을 배우기 위해 적절하게 수정하기 전에 그 예제를 조금 가지고 놀아 봅시다 :-)

나는 우리가 사물을 이해하는 접근 방식을 선호합니다. 우리가 어떻게했는지 알지 못하는 사이에 무언가를 고치는 것은 만족스럽지 않습니다. :)

string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate(); //new line is here :-)

위의 코드를 호출하면 스트림의 상태 (cin)가 4 (7 행)임을 알 수 있습니다. 이는 내부 상태가 더 이상 goodbit와 같지 않음을 의미합니다. 뭔가 엉망이되었습니다. 꽤 명백하지 않나요? 문자열 유형 값 ( "Wlodarczyk")을 int 유형 변수 'age'에 할당하려고했습니다. 유형이 일치하지 않습니다. 뭔가 잘못되었음을 알릴 때입니다. 그리고 컴퓨터는 스트림의 내부 상태를 변경하여이를 수행합니다. 그것은 "당신은 망할 남자, 제발 나를 고쳐주세요. 나는 당신에게 '친절하게'라고 알려줍니다 ;-)"와 같습니다.

더 이상 'cin'(스트림)을 사용할 수 없습니다. 막혔어요. 마치 큰 나무 통나무를 물줄기에 놓은 것처럼. 사용하기 전에 수정해야합니다. 나무의 통나무 (내부 상태)가 그렇게하는 것을 허용하지 않기 때문에 데이터 (물)는 더 이상 그 흐름 (cin)에서 얻을 수 없습니다.

오 그렇다면 장애물 (나무 통나무)이 있으면 그렇게 만든 도구를 사용하여 제거 할 수 있습니까?

예!

4로 설정된 cin의 내부 상태는 울부 짖고 소리를내는 경보와 같습니다.

cin.clear는 상태를 정상으로 되돌립니다 (goodbit). 마치 당신이 와서 알람을 끄는 것과 같습니다. 그냥 미루세요. 어떤 일이 일어났다는 것을 알고 있으므로 "소음을 그만 두어도 괜찮습니다. 이미 문제가 있다는 것을 알고 있습니다. 닥쳐 (명확하게)"라고 말합니다.

좋아, 그렇게하자! cin.clear ()를 사용합시다.

"Arkadiusz Wlodarczyk"를 첫 번째 입력으로 사용하여 아래 코드를 호출하십시오.

string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl; 
cin.clear(); //new line is here :-)
cout << cin.rdstate()<< endl;  //new line is here :-)

위의 코드를 실행하면 상태가 goodbit와 같다는 것을 확실히 알 수 있습니다.

문제가 해결 되었나요?

"Arkadiusz Wlodarczyk"를 첫 번째 입력으로 사용하여 아래 코드를 호출하십시오.

string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;; 
cin.clear(); 
cout << cin.rdstate() << endl; 
cin >> age;//new line is here :-)

9 행 이후에도 상태가 goodbit로 설정되어 있어도 사용자에게 "연령"을 묻지 않습니다. 프로그램이 중지됩니다.

왜?!

오 이런 ... 방금 경보를 끄 셨군요. 물 속의 나무 통나무는 어떻습니까? * "Wlodarczyk"이 어떻게 사라 졌는지에 대해 이야기했던 텍스트로 돌아가십시오.

개울에서 나무 조각 "Wlodarczyk"를 제거해야합니다. 알람을 꺼도 문제가 전혀 해결되지 않습니다. 당신은 그것을 침묵시키고 문제가 사라 졌다고 생각합니까? ;)

이제 다른 도구가 필요합니다.

cin.ignore는 로프가 달린 특수 트럭에 비유 할 수 있습니다. 프로그램 사용자가 만든 문제를 해결합니다.

알람이 울리기도 전에 사용할 수 있을까요?

예:

string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;

"Wlodarczyk"는 7 번 라인에서 소음을 내기 전에 제거됩니다.

10000과 '\ n'은 무엇입니까?

'\ n'이 충족 될 때까지 (입력) 10000 문자를 제거합니다 (만약 경우). BTW numeric_limits를 사용하면 더 잘 할 수 있지만이 답변의 주제는 아닙니다.


그래서 문제의 주요 원인은 소음이 발생하기 전에 사라졌습니다.

그렇다면 왜 '명확'이 필요합니까?

누군가가 6 행에서 '당신의 나이를주세요'라는 질문을했다면, 예를 들어 20을 쓰는 대신 "20 세"라는 질문을했을까요?

유형이 다시 일치하지 않습니다. 컴퓨터는 int에 문자열을 할당하려고합니다. 그리고 알람이 시작됩니다. 그런 상황에 반응 할 기회조차 없습니다. cin.ignore는 그런 경우에 도움이되지 않습니다.

따라서 다음과 같은 경우에는 clear를 사용해야합니다.

string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow

그러나 '경우에 따라'상태를 삭제해야합니까?

당연히 아니지.

무언가 잘못되면 (cin >> age;) 지시는 false를 반환하여 이에 대해 알려줍니다.

따라서 조건문을 사용하여 사용자가 스트림에 잘못된 유형을 입력했는지 확인할 수 있습니다.

int age;
if (cin >> age) //it's gonna return false if types doesn't match
    cout << "You put integer";
else
    cout << "You bad boy! it was supposed to be int";

좋습니다. 예를 들어 다음과 같이 초기 문제를 해결할 수 있습니다.

string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow

int age;
cout << "Give me your age:" << endl;
if (cin >> age)
  cout << "Your age is equal to:" << endl;
else
{
 cin.clear();
 cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
 cout << "Give me your age name as string I dare you";
 cin >> age;
}

물론 이것은 예를 들어 loop while을 사용하여 문제에서했던 작업을 수행함으로써 개선 될 수 있습니다.

보너스:

궁금 할 것입니다. 사용자로부터 같은 줄에 이름과 성을 얻고 싶다면 어떻게해야합니까? cin이 "공백"으로 구분 된 각 값을 다른 변수로 해석하면 cin을 사용할 수도 있습니까?

물론 두 가지 방법으로 수행 할 수 있습니다.

1)

string name, surname;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin >> surname;

cout << "Hello, " << name << " " << surname << endl;

2) 또는 getline 함수를 사용합니다.

getline(cin, nameOfStringVariable);

그 방법은 다음과 같습니다.

string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);

cout << "Hello, " << nameAndSurname << endl;

두 번째 옵션은 getline 앞에 'cin'을 사용한 후 사용하는 경우 역효과를 낼 수 있습니다.

확인 해보자:

ㅏ)

int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endl;

string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);

cout << "Hello, " << nameAndSurname << endl;

나이로 "20"을 입력하면 nameAndSurname을 묻지 않습니다.

하지만 그렇게하면 :

비)

string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);

cout << "Hello, " << nameAndSurname << endl;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endll

모든 것이 좋습니다.

뭐?!

입력 (스트림)에 무언가를 넣을 때마다 엔터 ( '\ n') 인 흰색 문자를 마지막에 남겨 둡니다. 어떻게 든 콘솔에 값을 입력해야합니다. 따라서 데이터가 사용자로부터 온다면 반드시 발생해야합니다.

b) cin 특성은 공백을 무시한다는 것이므로 cin에서 정보를 읽을 때 개행 문자 '\ n'은 중요하지 않습니다. 무시됩니다.

a) getline 함수는 줄 바꿈 문자 ( '\ n')까지 전체 줄을 가져오고, 줄 바꿈 문자가 첫 번째 일 때 getline 함수는 '\ n'을 얻습니다. 그게 전부입니다. 3 행 스트림에 "20"을 입력 한 사용자가 스트림에 남긴 개행 문자를 추출합니다.

따라서이를 수정하려면 항상 cin.ignore (); 프로그램 내에서 getline ()을 사용하려는 경우 cin을 사용하여 값을 얻을 때마다.

따라서 적절한 코드는 다음과 같습니다.

int age;
cout << "Give me your age:" <<endl;
cin >> age;
cin.ignore(); // it ignores just enter without arguments being sent. it's same as cin.ignore(1, '\n') 
cout << "Your age is" << age << endl;


string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);

cout << "Hello, " << nameAndSurname << endl;

스트림이 더 명확하기를 바랍니다.

제발 조용히 해주세요! :-)


1

버퍼 cin.ignore(1000,'\n')에서 이전의 모든 문자를 지우는 데 사용 하며 cin.get()'\ n'또는 1000 chars처음 만나면 중지하도록 선택합니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.