First letter cut off from string - Wierd

There seems to be a wierd quirk in my code which causes the first letter of the string to be cut off in the output.

The code is simple, it asks for the number of students and quiz scores and then outputs the total and average of each student.

The first student name is fine. But the subsequent ones all have their first letters cut off, and I can't figure out why...


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

#include <iostream>

using std::cout;
using std::cin;
using std::endl;
using std::flush;
using std::string;

class Quizdata{
private:
    string name;
    double total;
    int number;

public:
    Quizdata()
    {
        total = 0;
        number = 0;

        cout << "Enter in name of student: ";
        cin.get();
        getline(cin, name);
    }

    // sums up quiz scores for each student
    int add_quiz(int score)
    {
        total+=score;
        number++;
    }

    string get_name()
    {
        return name;
    }

    int get_total_score()
    {
        return total;
    }

    int get_average_score()
    {
        return total/number;
    }
};


void printresults(Quizdata[], int); // Prototype function

int main()
{
    int SIZE, quizzes, score;

    cout << "Enter in number of students in class: ";
    cin >> SIZE;
    cout << "\n";
    Quizdata student[SIZE]; // object array created. 

    cout << "\nHow many quiz scores for each student will be entered? ";
    cin >> quizzes;
    cout << "\n";
 
   
    // traversing through object array to get scores of each student
    for(int k = 0; k < SIZE; k++)
    {
        for(int i = 1; i <= quizzes; i++)
        {
            cout << "Enter in score " << i << " of " << student[k].get_name() << " between 0 and 100: ";
            cin >> score;
            while(score < 0 || score > 100)
            {
                cout << "Invalid entry. Please enter again: ";
                cin >> score;
            }

            student[k].add_quiz(score); // send score to add_quiz function to add to 'total'
        }

        cout << "\n";
    }


    printresults(student, SIZE); // call to printresults function

    return 0;
}


// simply prints the name, total and average of each student
void printresults(Quizdata student[], int SIZE)
{
    cout << "\n\n";

    for (int i=0; i<SIZE; i++)
    {
        cout << "Student Name: " << student[i].get_name() << endl;
        cout << "Student Total: " << student[i].get_total_score() << endl;
        cout << "Student Average: " << student[i].get_average_score() << endl;

        cout << "\n\n";
    }
}
 


Here is the output:

Enter in number of students in class: 3

Enter in name of student: George
Enter in name of student: Larry
Enter in name of student: Bernard

How many quiz scores for each student will be entered? 2

Enter in score 1 of George between 0 and 100: 80
Enter in score 2 of George between 0 and 100: 85

Enter in score 1 of arry between 0 and 100: 90
Enter in score 2 of arry between 0 and 100: 92

Enter in score 1 of ernard between 0 and 100: 67
Enter in score 2 of ernard between 0 and 100: 81


Student Name: George
Student Total: 165
Student Average: 82


Student Name: arry
Student Total: 182
Student Average: 91


Student Name: ernard
Student Total: 148
Student Average: 74



Notice how the first letter of 'Larry' and 'Bernard' are not showing. 'George' however is fine. What the hell?
Last edited on
The problems seems to fix itself if I use cin instead of getline in my constructor.

Thats not good because I would really like to use getline in case the user enters in both first and last name (separated by space).
When you call cin.get(); you read one character from cin. That's why the first letter is missing.

The reason why the first letter of the first name is not missing is because when you read the size from cin using >> it leaves the newline character at the end of the line, so the first time get() is called it just removes this newline character and leaves the next line intact.

Using getline removes the whole line, including the newline character which means that the get() that comes after will consume the first character on the next line.

I don't think the get() function belong in the Quizdata constructor. Instead of calling get() before every call to getline you should call it after you have used >>. That way you always leave a fresh line for the next input operation to read from no matter if it happens to be >> or getline.
Last edited on
Thank you for the explanation. But i dont understand the solution you are proposing. Where should I put the cin.get() if not in the constructor?
Last edited on
After each time you use >>, to remove the newline at the end of the line.
But I dont even use >> in my constructor...

I I dont want to either. I'd rather keep it as getline in case the user wants to enter names with spaces.
Last edited on
But you use it in main().

Well, you don't really need to use get() after each time you use >> if you are absolutely sure it will not be directly followed by a getline.
Last edited on
closed account (48T7M4Gy)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iostream>

using std::cout;
using std::cin;
using std::endl;
using std::flush;
using std::string;

class Quizdata{
private:
    string name;
    double total;
    int number;

public:
    Quizdata()
    {
        total = 0;
        number = 0;

        cout << "Enter in name of student: ";
        //cin.get(); // <-----------------------------------------------------------------------
        getline(cin, name);
    }

    // sums up quiz scores for each student
    int add_quiz(int score)
    {
        total+=score;
        number++;
    }

    string get_name()
    {
        return name;
    }

    int get_total_score()
    {
        return total;
    }

    int get_average_score()
    {
        return total/number;
    }
};


void printresults(Quizdata[], int); // Prototype function

int main()
{
    int SIZE, quizzes, score;

    cout << "Enter in number of students in class: ";
    cin >> SIZE;
    cin.ignore();// <-----------------------------------------------------------------------
    cout << "\n";
    Quizdata student[SIZE]; // object array created. 

    cout << "\nHow many quiz scores for each student will be entered? ";
    cin >> quizzes;
    cout << "\n";
 
   
    // traversing through object array to get scores of each student
    for(int k = 0; k < SIZE; k++)
    {
        for(int i = 1; i <= quizzes; i++)
        {
            cout << "Enter in score " << i << " of " << student[k].get_name() << " between 0 and 100: ";
            cin >> score;
            while(score < 0 || score > 100)
            {
                cout << "Invalid entry. Please enter again: ";
                cin >> score;
            }

            student[k].add_quiz(score); // send score to add_quiz function to add to 'total'
        }

        cout << "\n";
    }


    printresults(student, SIZE); // call to printresults function

    return 0;
}


// simply prints the name, total and average of each student
void printresults(Quizdata student[], int SIZE)
{
    cout << "\n\n";

    for (int i=0; i<SIZE; i++)
    {
        cout << "Student Name: " << student[i].get_name() << endl;
        cout << "Student Total: " << student[i].get_total_score() << endl;
        cout << "Student Average: " << student[i].get_average_score() << endl;

        cout << "\n\n";
    }
}


While not directly affecting the outcome here and as mentioned by someone else above, it is bad programming practice to include input/output functionality (cin, cout, get, getline) in an abstract data class such as the one here. It should all be done elsewhere eg in main() via gets and sets or constructors.
Last edited on
Wow, I feel so stupid for not thinking of putting it there in the main function. Thank you so much. It works perfectly now.

And thank you for the heads up on bad programming practice. I'll keep that in mind from now on.
closed account (48T7M4Gy)
'Bad' is probably a bit discouraging but the point is by doing it the way I suggested your class can be used on any platform, not just a console program.

The 'rule' is a cin.ignore() goes after any cin which immediately precedes a getline()

Cheers.
Last edited on
Topic archived. No new replies allowed.