Wanneer en waarom moet ik cin.ignore() gebruiken in C++?

Ik heb een heel eenvoudig programma in C++ geschreven waarin de gebruiker werd gevraagd een getal en vervolgens een tekenreeks in te voeren. Tot mijn verbazing stopte het tijdens het uitvoeren van het programma nooit om naar de string te vragen. Het sloeg er gewoon overheen. Na wat gelezen te hebben over StackOverflow, kwam ik erachter dat ik een regel moest toevoegen die zei:

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

voor de regel die de tekenreeksinvoer krijgt. Door dat toe te voegen, werd het probleem opgelost en werkte het programma. Mijn vraag is waarom heeft C++ deze regel cin.ignore()nodig en hoe kan ik voorspellen wanneer ik cin.ignore()moet gebruiken?

Hier is het programma dat ik heb geschreven:

#include <iostream>
#include <string>
using namespace std;
int main()
{
    double num;
    string mystr;
    cout << "Please enter a number: " << "\n";
    cin >> num;
    cout << "Your number is: " << num << "\n";
    cin.ignore(256, '\n'); // Why do I need this line?
    cout << "Please enter your name: \n";
    getline (cin, mystr);
    cout << "So your name is " << mystr << "?\n";
    cout << "Have a nice day. \n";
}

Antwoord 1, autoriteit 100%

Negeren is precies wat de naam aangeeft.

Het “gooit” niet iets weg dat je niet nodig hebt, het negeert het aantal tekens dat je opgeeft wanneer je het aanroept, tot aan het teken dat je opgeeft als breekpunt.

Het werkt met zowel invoer- als uitvoerbuffers.

In wezen, voor std::cin-instructies die u negeert voordat u een getline-aanroep doet, omdat wanneer een gebruiker iets invoert met std::cin, ze drukken op enter en een '\n'char komt in de cinbuffer. Als u vervolgens getlinegebruikt, krijgt het de nieuwe regel char in plaats van de gewenste tekenreeks. Dus je doet een std::cin.ignore(1000,'\n')en dat zou de buffer moeten opruimen tot de string die je wilt. (De 1000 wordt daar geplaatst om een bepaald aantal tekens voor het opgegeven breekpunt over te slaan, in dit geval het \n-teken voor de nieuwe regel.)


Antwoord 2, autoriteit 44%

Je denkt hier op de verkeerde manier over. Elke keer dat cinof getlinewordt gebruikt, denk je in logische stappen. Ex. Vraag eerst om een nummer, vraag dan om een naam. Dat is de verkeerde manier om over cinte denken. Je komt dus in een raceconditie terecht omdat je ervan uitgaat dat de stream duidelijk is elke keer dat je om invoer vraagt.

Als je je programma puur voor input schrijft, zul je het probleem vinden:

void main(void)
{
    double num;
    string mystr;
    cin >> num;
    getline(cin, mystr);
    cout << "num=" << num << ",mystr=\'" << mystr << "\'" << endl;
}

In het bovenstaande denk je: “Koop eerst een nummer”. Dus je typt 123en drukt op enter, en je output is num=123,mystr=''. Waarom is dat? Het is omdat je in de stream 123\nhebt en de 123wordt geparseerd in de variabele numterwijl \nzit nog in de stream. Als u het document voor de functie getlineleest, zal het standaard in de istreamzoeken totdat een \nwordt aangetroffen. In dit voorbeeld, aangezien \nin de stream zit, lijkt het alsof het deze heeft “overgeslagen”, maar het werkte correct.

Om het bovenstaande te laten werken, moet je 123Hello Worldinvoeren, wat de juiste output num=123,mystr='Hello World'geeft. Dat, of je plaatst een cin.ignoretussen de cinen getlinezodat het in logische stappen uiteenvalt die je verwacht.

Daarom heb je de opdracht ignorenodig. Omdat je er in logische stappen aan denkt in plaats van in een stroomvorm, zodat je in een raceconditie terechtkomt.

Neem nog een codevoorbeeld dat vaak op scholen wordt aangetroffen:

void main(void)
{
    int age;
    string firstName;
    string lastName;
    cout << "First name: ";
    cin >> firstName;
    cout << "Last name: ";
    cin >> lastName;
    cout << "Age: ";
    cin >> age;
    cout << "Hello " << firstName << " " << lastName << "! You are " << age << " years old!" << endl;
}

Het bovenstaande lijkt in logische stappen te zijn. Vraag eerst naar voornaam, achternaam en vervolgens leeftijd. Dus als je Johnhebt ingevoerd, dan Doehebt ingevoerd en vervolgens 19hebt ingevoerd, werkt de applicatie elke logische stap. Als je het in “streams” bedenkt, kun je eenvoudig John Doe 19invoeren bij de “Voornaam:”-vraag en het zou ook werken en de resterende vragen lijken over te slaan. Om het bovenstaande in logische stappen te laten werken, moet je de resterende stream voor elke logische onderbreking in vragen ignore.

Denk eraan om aan uw programma-invoer te denken, aangezien deze leest uit een “stream” en niet in logische stappen. Elke keer dat je cinaanroept, wordt het gelezen uit een stream. Dit creëert een nogal buggy-applicatie als de gebruiker de verkeerde invoer invoert. Als u bijvoorbeeld een teken hebt ingevoerd waarbij een cin >> doublewordt verwacht, zal de applicatie een schijnbaar bizarre output produceren.


Antwoord 3, autoriteit 24%

Kort antwoord

Waarom? Omdat er nog steeds witruimte (carriage returns, tabs, spaties, nieuwe regel) over is in de invoerstroom.

Wanneer? Wanneer u een functie gebruikt die op zichzelf niet de leidende witruimten negeert. Cin negeert en verwijdert standaard de leidende witruimte, maar getline negeert de leidende witruimte niet op zichzelf.

Nu een gedetailleerd antwoord.

Alles wat je invoert in de console wordt gelezen uit de standaard stream stdin. Als je iets invoert, laten we zeggen 256 in jouw geval en op enter drukt, wordt de inhoud van de stream 256\n. Nu pakt cin 256 op en verwijdert het uit de stream en \nblijft nog in de stream.
Wanneer u nu uw naam invoert, laten we zeggen Raddicus, is de nieuwe inhoud van de stream \nRaddicus.

Nu komt de vangst.
Wanneer u een regel probeert te lezen met getline, als er geen scheidingsteken als derde argument is opgegeven, leest getline standaard tot het nieuweregelteken en verwijdert het het nieuweregelteken uit de stream.
Dus bij het aanroepen van een nieuwe regel leest en verwijdert getline \nuit de stream en resulteert in een lege string die wordt gelezen in mystr die lijkt alsof getline wordt overgeslagen (maar dat is niet zo) omdat er al een nieuwe regel in de stream, zal getline niet om invoer vragen omdat het al heeft gelezen wat het moest lezen.

Hoe helpt cin.ignore hier?

Volgens het uittreksel van de negeerdocumentatie van cplusplus.com

istream& negeren (stroomgrootte n = 1, int delim = EOF);

Haalt tekens uit de invoerreeks en verwijdert ze, totdat
ofwel n karakters zijn geëxtraheerd, of één is gelijk aan
delim.

De functie stopt ook met het extraheren van tekens als het einde van het bestand is
bereikt. Als dit voortijdig wordt bereikt (vóór het extraheren van n
karakters of het vinden van scheidingsteken), stelt de functie de eofbit-vlag in.

Dus, cin.ignore(256, '\n');, negeert de eerste 256 tekens of alle tekens totdat het scheidingsteken tegenkomt (hier \n in jouw geval), afhankelijk van wat zich het eerst voordoet ( hier is \n het eerste teken, dus het wordt genegeerd totdat \n wordt aangetroffen).

Ter referentie: als je niet precies weet hoeveel tekens je moet overslaan en je enige doel is om de stream te wissen om je voor te bereiden op het lezen van een string met getline of cin, dan moet je cin.ignore(numeric_limits<streamsize>::max(),'\n').

Snelle uitleg: Het negeert de karakters die gelijk zijn aan de maximale grootte van de stroom of totdat een ‘\ N’ wordt aangetroffen, waarmee de zaak eerst gebeurt.


Antwoord 4, Autoriteit 8%

Wanneer u een specifiek aantal tekens uit de ingangsstroom handmatig wilt weggooien.

Een zeer gebruikelijke gebruiksbehuizing gebruikt dit om de nieuwlijnpersonages veilig te negeren, omdat CIN soms Newline-personages zal achterlaten die u moet doen om naar de volgende invoerlijn te gaan.

Lang verhaal kort, het geeft je flexibiliteit bij het hanteren van stroominvoer.


Antwoord 5

Negeren functie wordt gebruikt om tekens in de ingangsstroom te overslaan (weggooien / gooien). Negeer bestand is geassocieerd met het bestand Istream.
Overweeg de onderstaande functie
ex: cin.ignore (120, ‘/ n’);
De specifieke functie slaat het volgende 120-invoerteken over of om de tekens over te slaan totdat een nieuwlijn wordt gelezen.


Antwoord 6

Zoals gericht door vele andere gebruikers. Het komt omdat er witruimte of een nieuwlijnkarakter kan zijn.

Overweeg de volgende code, het verwijdert alle dubbele tekens uit een bepaalde reeks.

#include <bits/stdc++.h>
using namespace std;
int main() {
    int t;
    cin>>t;
    cin.ignore(); //Notice that this cin.ignore() is really crucial for any extra whitespace or newline character
    while(t--){
        vector<int> v(256,0);
        string s;
        getline(cin,s);
        string s2;
        for(int i=0;i<s.size();i++){
            if (v[s[i]]) continue;
            else{
                s2.push_back(s[i]);
                v[s[i]]++;
            }
        }
        cout<<s2<<endl;
    }
    return 0;
}

Dus krijg je het punt dat het die ongewenste inputs zal negeren en de taak wordt gedaan.


Antwoord 7

Het is beter om scanf(” %[^\n]”,str) in c++ te gebruiken dan cin.ignore() na cin>> statement. Om dat te doen moet u eerst < cstdio > koptekst.

Other episodes