0

I have a code from my friend and we do not know how to use cin. ignore very well.

Our problem is that we are using do while and at the end of loop we want to ask user to enter if he wants to again enter some values as you will see from the code itself.

If the answer is 'y' then he can "write" again but the problem is we are using getline and we have the problem with the first getline in this loop. The program does not recognise it after the first time use.

Here is the code:

int main() {
    ofstream datoteka("podaci.txt", ios::app);

    if (datoteka.fail()) {
        cout << "Ne postojeca datoteka";
        exit(1);
    }
    string ime;
    string prezime;
    char pol;
    int godiste;
    float prosjek;
    char odluka;
    do{
        system("CLS");
        cout << "Unesite ime: ";
        getline(cin, ime);
        datoteka << ime;

        cout << "Unesite prezime: ";
        getline(cin, prezime);
        datoteka << " " << prezime;

        cout << "Unesite pol(M - musko, Z - zensko): ";
        cin >> pol;
        datoteka << " " << pol;

        cout << "Unesite godiste: ";
        cin >> godiste;
        datoteka << " " << godiste;

        cout << "Unesite prosjek: ";
        cin >> prosjek;
        datoteka << " " << prosjek << endl;
        cout << endl;
        cout << "Da li zelite unijeti podatke za jos jednu osobu?" << endl; 
        cout << "[Y] za da, [N] za ne : ";
        cin >> odluka;
    } while (odluka != 'N' || odluka !='n');

The problem is with the

getline(cin,ime);

It wont recognize it after the first time use. Can someone help me?

  • 1
    Does this answer your question? [Why does std::getline() skip input after a formatted extraction?](https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction) – churill May 18 '20 at 14:29
  • In short: after `cin>>` if it is followed by `getline()`. Or you can only use `std::getline` and do the parsing yourself (easier to handle any user errors) – Yksisarvinen May 18 '20 at 14:32
  • You might want to use ignore **after** you have extracted a number. `cin >> godiste; cin.ignore(...);` for example. When you read a number, anything that isn't part of the number will be left behind, so that is when you might want to use ignore. – john May 18 '20 at 14:34

2 Answers2

1

The basic problem is that this code mixes two different forms of input. Stream extractors (operator>>) do formatted input; they skip whitespace, then try to interpret non-whitespace characters, and stop when they encounter something that doesn't fit with what they're looking for. That works fine when you have multiple extractors: std::cin >> x >> y >> z;,

getline() is an unformatted input function; it grabs whatever is in the input stream, up to the first newline.

If you mix them you can get into trouble. The usual way to get around this is to call some variation of cin.ignore() when you switch from formatted to unformatted input, and that's where the code in the question goes astray.

At the end of the loop, the code calls std::cin >> odluka;. That reads one character from the console, and leaves any additional input in place. Since the console itself typically will sit waiting for characters until it sees a newline character, typing that single character also requires hitting the Enter key, which puts a newline into the input stream. The extractor leaves the newline there. When the loop repeats, the code calls std::getline(std::cin, ime), which sees the newline character and stops reading input.

So whenever you transition from formatted input to unformatted input you have to clear out any remnants from the previous input efforts.

Or you can always read a line at a time, and parse the input yourself.

Pete Becker
  • 69,019
  • 6
  • 64
  • 147
-2

i'm not sure exactly what the problem is. i took your code and it does what it's supposed to be doing on my machine (made a few adjustments so i can understand what's going on):

#include <iostream>
#include <vector>
#include <string>
#include <fstream>

using namespace::std;
int main() {
    ofstream datoteka("podaci.txt", ios::app);

    if (datoteka.fail()) {
        cout << "Ne postojeca datoteka";
        exit(1);
    }
    string ime;
    string prezime;
    char pol;
    int godiste;
    float prosjek;
    // changed it to a char pointer
    char odluka[] =  { "Y" };
    do{
        system("CLS");
        cout << "1: ";
        getline(cin, ime);
        datoteka << ime;

        cout << "2: ";
        getline(cin, prezime);
        datoteka << " " << prezime;

        cout << "3: ";
        cin >> pol;
        datoteka << " " << pol;

        cout << "4: ";
        cin >> godiste;
        datoteka << " " << godiste;

        cout << "5: ";
        cin >> prosjek;
        datoteka << " " << prosjek << endl;
        cout << endl;
        cout << "6" << endl; 
        cout << "[Y], [N]: ";
        cin >> odluka;
        // added this. it was not waiting for my input properly.
        cin.get();

        // print results

        system("cls");
        printf("results (press any key to move on)\n\n1: %s\n2: %s\n3: %c\n4: %d\n5: %.02f\n6: %c\n\n", ime.c_str(), prezime.c_str(), pol, godiste, prosjek, odluka);
        getchar();
    } while (_stricmp(odluka, "n")); // while "odluka" is not "n" or "N" (the _stricmp is not case-sensitive so they both return the same result)

    system("cls");
    printf("press any key to exit!\n");
    getchar();

    getchar();
}

here is the output from "podaci.txt":

test1 test1 1 1 1.1
test2 test2 2 2 2.2

consider using scanf/sprintf/printf with c strings in the future if this keeps malfunctioning perhaps?

tb044491
  • 134
  • 6
  • 1
    This isn't an answer to the question. – john May 18 '20 at 14:38
  • my answer is at the bottom, advising the use of other functions for this purpose, as i've had problems like him before, where my code would malfunction all the time when using cin and getline. i cannot reproduce his error, therefore, it is not the code he wrote. – tb044491 May 18 '20 at 14:43
  • 1
    Well I think you mean scanf, since we are talking about input here, not output. Using scanf and C strings in a C++ program needs strong justification. Just because you couldn't get it to work in your programs doesn't really seem enough to me. – john May 18 '20 at 14:47
  • yeah that's what i meant. sprintf_s is for formatting. and the fact that this works fine for me and not for him shows the code is not at fault. i also do not see what's wrong with using scanf instead of cin. – tb044491 May 18 '20 at 14:54
  • 1
    It only works for you because of `// added this. it was not waiting for my input properly. cin.get();` which is an inadequate solution and (I'll say it again) not what he was asking about, which was the correct use of ignore. – john May 18 '20 at 15:06