Por que usamos:
1) cin.ignore
2) cin.clear
?
Simplesmente:
1) Para ignorar (extrair e descartar) valores que não queremos no fluxo
2) Para limpar o estado interno do fluxo. Depois de usar cin.clear, o estado interno é definido novamente como goodbit, o que significa que não há 'erros'.
Versão longa:
Se algo for colocado em 'stream' (cin), então deve ser retirado de lá. Por 'levado' queremos dizer 'usado', 'removido', 'extraído' do fluxo. O fluxo tem um fluxo. Os dados estão fluindo como água no fluxo. Você simplesmente não pode parar o fluxo de água;)
Olhe para o exemplo:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
O que acontece se o usuário responder: "Arkadiusz Wlodarczyk" para a primeira pergunta?
Execute o programa para ver por si mesmo.
Você verá no console "Arkadiusz", mas o programa não pedirá 'idade'. Ele vai terminar imediatamente após a impressão de "Arkadiusz".
E "Wlodarczyk" não é mostrado. Parece que foi embora (?) *
O que aconteceu? ;-)
Porque há um espaço entre "Arkadiusz" e "Wlodarczyk".
O caractere de "espaço" entre o nome e o sobrenome é um sinal para o computador de que há duas variáveis esperando para serem extraídas no fluxo de 'entrada'.
O computador pensa que você está tentando enviar para a entrada mais de uma variável. Esse sinal de "espaço" é um sinal para ele interpretar dessa forma.
Portanto, o computador atribui "Arkadiusz" ao 'nome' (2) e, como você colocou mais de uma string no fluxo (entrada), o computador tentará atribuir o valor "Wlodarczyk" à variável 'idade' (!). O usuário não terá a chance de colocar nada no 'cin' na linha 6 porque essa instrução já foi executada (!). Por quê? Porque ainda havia algo em funcionamento. E como eu disse antes, o fluxo está em um fluxo, então tudo deve ser removido dele o mais rápido possível. E a possibilidade surgiu quando o computador viu a ciência da instrução;
O computador não sabe que você criou uma variável que armazena a idade de alguém (linha 4). 'idade' é apenas um rótulo. Pois a 'era' do computador também poderia ser chamada de: 'afsfasgfsagasggas' e seria o mesmo. Para ele, é apenas uma variável que tentará atribuir "Wlodarczyk" porque você ordenou / instruiu o computador a fazê-lo na linha (6).
É errado fazer isso, mas foi você quem fez isso! É sua culpa! Bem, talvez usuário, mas ainda ...
Tudo bem, tudo bem. Mas como consertar ?!
Vamos tentar brincar um pouco com esse exemplo antes de corrigi-lo adequadamente para aprender mais algumas coisas interessantes :-)
Prefiro fazer uma abordagem onde entendemos as coisas. Consertar algo sem saber como a gente fazia não dá satisfação, não acha? :)
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();
Depois de invocar o código acima, você notará que o estado do seu stream (cin) é igual a 4 (linha 7). O que significa que seu estado interno não é mais igual a goodbit. Algo está bagunçado. É bastante óbvio, não é? Você tentou atribuir um valor de tipo de string ("Wlodarczyk") à variável de tipo int 'idade'. Tipos não correspondem. É hora de informar que algo está errado. E o computador faz isso mudando o estado interno do fluxo. É como: "Seu f ****-up cara, me conserta por favor. Eu te informo 'gentilmente' ;-)"
Você simplesmente não pode mais usar 'cin' (stream). Está preso. Como se você tivesse colocado grandes toras de madeira no riacho. Você deve consertá-lo antes de poder usá-lo. Os dados (água) não podem mais ser obtidos desse riacho (cin) porque a tora de madeira (estado interno) não permite que você faça isso.
Ah, então se houver um obstáculo (toras de madeira), podemos simplesmente removê-lo usando ferramentas feitas para isso?
Sim!
o estado interno de cin definido como 4 é como um alarme que está uivando e fazendo barulho.
cin.clear limpa o estado de volta ao normal (goodbit). É como se você tivesse vindo e silenciado o alarme. Você apenas adia. Você sabe que algo aconteceu, então você diz: "Tudo bem parar de fazer barulho, eu sei que algo já está errado, cale a boca (limpe)".
Tudo bem, vamos fazer isso! Vamos usar cin.clear ().
Chame o código abaixo usando "Arkadiusz Wlodarczyk" como primeira entrada:
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;
Certamente podemos ver depois de executar o código acima que o estado é igual a goodbit.
Ótimo então o problema está resolvido?
Chame o código abaixo usando "Arkadiusz Wlodarczyk" como primeira entrada:
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;
Mesmo que o estado seja definido como goodbit após a linha 9, o usuário não é questionado sobre "idade". O programa pára.
PORQUE?!
Oh cara ... Você acabou de disparar o alarme, que tal a tora de madeira dentro de uma água? * Volte para o texto onde falamos sobre "Wlodarczyk" como supostamente tinha sumido.
Você precisa remover "Wlodarczyk" aquele pedaço de madeira do riacho. Desligar os alarmes não resolve o problema. Você acabou de silenciá-lo e acha que o problema desapareceu? ;)
Então é hora de outra ferramenta:
cin.ignore pode ser comparado a um caminhão especial com cordas que vem e remove as toras de madeira que travaram o riacho. Isso elimina o problema que o usuário do programa criou.
Então, poderíamos usá-lo antes mesmo de fazer o alarme disparar?
Sim:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n');
int age;
cout << "Give me your age:" << endl;
cin >> age;
O "Wlodarczyk" será removido antes de fazer o ruído na linha 7.
O que é 10000 e '\ n'?
Diz remover 10.000 caracteres (apenas no caso) até que '\ n' seja encontrado (ENTER). BTW, isso pode ser feito melhor usando numeric_limits, mas não é o tópico desta resposta.
Portanto, a principal causa do problema foi embora antes que o ruído fosse feito ...
Por que precisamos 'limpar' então?
E se alguém tivesse feito a pergunta 'dê-me sua idade' na linha 6, por exemplo: "vinte anos" em vez de escrever 20?
Tipos não correspondem novamente. O computador tenta atribuir string a int. E o alarme começa. Você nem mesmo tem chance de reagir em uma situação como essa. cin.ignore não o ajudará neste caso.
Portanto, devemos usar claro em casos como este:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n');
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, '\n');
Mas você deve limpar o estado 'apenas no caso'?
Claro que não.
Se algo der errado (cin >> age;), a instrução irá informá-lo sobre isso retornando false.
Portanto, podemos usar a instrução condicional para verificar se o usuário colocou o tipo errado no fluxo
int age;
if (cin >> age)
cout << "You put integer";
else
cout << "You bad boy! it was supposed to be int";
Tudo bem, então podemos corrigir nosso problema inicial como por exemplo:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n');
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');
cout << "Give me your age name as string I dare you";
cin >> age;
}
Claro que isso pode ser melhorado, por exemplo, fazendo o que você fez em questão usando loop while.
BÔNUS:
Você pode estar se perguntando. E se eu quisesse que o nome e o sobrenome do usuário fossem na mesma linha? É mesmo possível usar cin se cin interpretar cada valor separado por "espaço" como uma variável diferente?
Claro, você pode fazer isso de duas maneiras:
1)
string name, surname;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin >> surname;
cout << "Hello, " << name << " " << surname << endl;
2) ou usando a função getline.
getline(cin, nameOfStringVariable);
e é assim que se faz:
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
A segunda opção pode sair pela culatra em caso de você usá-lo depois de usar 'cin' antes do getline.
Vamos dar uma olhada:
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;
Se você colocar "20" como idade, não será solicitado o nome e o sobrenome.
Mas se você fizer assim:
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
tudo está bem.
O QUE?!
Cada vez que você coloca algo na entrada (fluxo), você deixa no final um caractere branco que é ENTER ('\ n'). Você tem que inserir valores de alguma forma para o console. Portanto, deve acontecer se os dados vierem do usuário.
b) as características do cin são que ele ignora os espaços em branco, então quando você está lendo informações de cin, o caractere de nova linha '\ n' não importa. É ignorado.
a) a função getline obtém toda a linha até o caractere de nova linha ('\ n'), e quando o caractere de nova linha é a primeira coisa, a função getline obtém '\ n', e isso é tudo para obter. Você extrai o caractere de nova linha que foi deixado na transmissão pelo usuário que colocou "20" na transmissão na linha 3.
Portanto, para consertar é sempre invocar cin.ignore (); cada vez que você usar cin para obter qualquer valor, se algum dia for usar getline () dentro de seu programa.
Portanto, o código adequado seria:
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cin.ignore();
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
Espero que os streams sejam mais claros para você.
Hah me silencie por favor! :-)