Programing

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

lottogame 2020. 10. 27. 07:48
반응형

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


이 코드를 사용하는 데 사용 된 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매개 변수가 필요한 이유는 무엇 입니까?


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


당신은 입력

if (!(cin >> input_var))

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

cin.clear();

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

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

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


우리가 사용하는 이유 :

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'이 충족 될 때까지 (Enter) 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를 반환하여 이에 대해 알려줍니다.

So we can use conditional statement to check if the user put wrong type on the stream

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";

All right so we can fix our initial problem like for example that:

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;
}

Of course this can be improved by for example doing what you did in question using loop while.

BONUS:

You might be wondering. What about if I wanted to get name and surname in the same line from the user? Is it even possible using cin if cin interprets each value separated by "space" as different variable?

Sure, you can do it two ways:

1)

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

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

2) or by using getline function.

getline(cin, nameOfStringVariable);

and that's how to do it:

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

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

The second option might backfire you in case you use it after you use 'cin' before the getline.

Let's check it out:

a)

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;

If you put "20" as age you won't be asked for nameAndSurname.

But if you do it that way:

b)

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

everything is fine.

WHAT?!

Every time you put something on input (stream) you leave at the end white character which is ENTER ('\n') You have to somehow enter values to console. So it must happen if the data comes from user.

b) cin characteristics is that it ignores whitespace, so when you are reading in information from cin, the newline character '\n' doesn't matter. It gets ignored.

a) getline function gets the entire line up to the newline character ('\n'), and when the newline char is the first thing the getline function gets '\n', and that's all to get. You extract newline character that was left on stream by user who put "20" on stream in line 3.

So in order to fix it is to always invoke cin.ignore(); each time you use cin to get any value if you are ever going to use getline() inside your program.

So the proper code would be:

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;

I hope streams are more clear to you know.

Hah silence me please! :-)


use cin.ignore(1000,'\n') to clear all of chars of the previous cin.get() in the buffer and it will choose to stop when it meet '\n' or 1000 chars first.

참고URL : https://stackoverflow.com/questions/5131647/why-would-we-call-cin-clear-and-cin-ignore-after-reading-input

반응형