Struggling to use getline correctly? Skipping inputs?

Hey guys! Im new to C++ and having a little difficulty with this program, Its supposed to be where it prompts you for a name and you can enter anything, for example: "Andre the giant" it then asks for that names career, where the user enters 1-4, and it produces a line such as: "Andre the giant is a certified Professional". The issue im having though, is when someone enters somehting other than 1-4 it needs to say "Wrong Entry!" And start at the line "Please enter another student name", the issue it my getline is grabbing the wrong input and using that then as the name? How do I get around it? I can use cin and it will work correctly, but getline is causing me some issues, however, i need the full string? Any advice ? Thanks alot <3


#include <iostream>
#include <string>
#include <iomanip>

using namespace std;

void func(int studentProf, string studentName);

int main()
{
string studentName;
int studentProf = 0;
int i = 0;

cout << "Please enter a student name (\"done\" to leave the program):" << endl;
getline(cin, studentName);


if (studentName != "done") {

//Call function that spits out prof
func(studentProf, studentName);

while (studentName != "done")
{

cout << "Please enter another student name (\"done\" to leave the program):" << endl;
getline(cin, studentName);




if (studentName != "done") {
//check prof
func(studentProf, studentName);
}

}
}
}


void func(int studentProf, string studentName)
{

string jobName;

cout << "Please enter the profession of: " << studentName << endl;
cin >> studentProf;


if (studentProf == 1)
cout << studentName << " is a Certified Professional" << endl;
else if (studentProf == 2)
jobName = "Management Professional";
else if (studentProf == 3)
jobName = "Service Professional";
else if (studentProf == 4)
jobName = "Law_and_Order Professional";
else
cout << "Wrong answer" << endl;




cin.ignore();
cin.clear();
studentName.clear();
}

Last edited on
http://www.augustcouncil.com/~tgibson/tutorial/iotips.html

in part:

std::getline() can run into problems when used before std::cin >> var.

The solution is to add std::cin.ignore(); immediately after the first std::cin statement. This will grab a character off of the input buffer (in this case, newline) and discard it.

but you may want to read the whole section.
Last edited on
So I would be adding it at line 27? right after getline(cin, studentName) in the while loop? Thank you for your prompt reply and help by the way!
Last edited on
So I would be adding it at line 27?
Line 27? What line 27?

PLEASE learn to use code tags, they make reading and commenting on source code MUCH easier.

http://www.cplusplus.com/articles/jEywvCM9/
http://www.cplusplus.com/articles/z13hAqkS/

HINT: you can edit your post and add code tags.

Some formatting & indentation would not hurt either

Using code tags would include line numbers.
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
#include <iostream>
#include <string>
#include <iomanip>

using namespace std;

void func(int studentProf, string studentName);

int main()
{
   string studentName;
   int studentProf = 0;
   int i = 0;

   cout << "Please enter a student name (\"done\" to leave the program):" << endl;
   getline(cin, studentName);

   if (studentName != "done")
   {

      //Call function that spits out prof
      func(studentProf, studentName);

      while (studentName != "done")
      {

         cout << "Please enter another student name (\"done\" to leave the program):" << endl;
         getline(cin, studentName);

         if (studentName != "done")
         {
            //check prof
            func(studentProf, studentName);
         }

      }
   }
}

void func(int studentProf, string studentName)
{

   string jobName;

   cout << "Please enter the profession of: " << studentName << endl;
   cin >> studentProf;

   if (studentProf == 1)
      cout << studentName << " is a Certified Professional" << endl;
   else if (studentProf == 2)
      jobName = "Management Professional";
   else if (studentProf == 3)
      jobName = "Service Professional";
   else if (studentProf == 4)
      jobName = "Law_and_Order Professional";
   else
      cout << "Wrong answer" << endl;

   cin.ignore();
   cin.clear();
   studentName.clear();
}

std::cin::ignore should be located after std::cin, not std::getline. I'd recommend moving line 59 to underneath the std::cin at line 46. And modify the statement to something like
std::cin.ignore(10000, '\n');
so it discards the ending carriage return left in the istream by std::cin. That carriage return is removed from the istream when using std::getline.

Having std::cin::clear along with std::cin::ignore is a bit of overkill since the istream hasn't actually gone in an error state. The problem was caused by mixing inputs with std::cin and std::getline; that is not an error affecting the stream.
I see! These changes seem to be much better! I will definitely try to format it better sorry! So i changed the code with your recommendations, it seems the problem still remains. If i type input the profession as "e", it will return, 'wrong answer' and the next line will print the "enter a student name", immediately followed by "Please enter the profession of e:". How would this be solved?


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
#include <iostream>
#include <string>
#include <iomanip>

using namespace std;

void func(int studentProf, string studentName);

int main()
{
	string studentName;
	int studentProf = 0;

	cout << "Please enter a student name (\"done\" to leave the program):" << endl;
	getline(cin, studentName);


	if (studentName != "done") {

		//Call function that spits out prof
		func(studentProf, studentName);
		while (studentName != "done")
		{
			
			cout << "Please enter another student name (\"done\" to leave the program):" << endl;
			getline(cin, studentName);
			


			if (studentName != "done") {
				//check prof
				func(studentProf, studentName);
			}
			
		}
	}
}


void func(int studentProf, string studentName)
{

	string jobName;

	cout << "Please enter the profession of: " << studentName << endl;
	cin >> studentProf;
	std::cin.ignore(10000, '\n');
	

	if (studentProf == 1)
		cout << studentName << " is a Certified Professional" << endl;
	else if (studentProf == 2)
		jobName = "Management Professional";
	else if (studentProf == 3)
		jobName = "Service Professional";
	else if (studentProf == 4)
		jobName = "Law_and_Order Professional";
	else
		cout << "Wrong answer" << endl;

		
	
	
	
	cin.clear();
	studentName.clear();
}

Last edited on
Hello Hybrid10,

Consider this. Be sure to read the comments.
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
#include <iostream>
#include <limits>  // <--- Added.
#include <string>
#include <iomanip>

using namespace std;  // <--- Best not to use.

//void func(int studentProf, string studentName);
void GetProfession(string& studentName);  // <--- All that is needed for this function

int main()
{
    string studentName;
    int studentProf = 0;  // <--- This will always be (0)zero. Passing it to the function has no effect.
    int i{};  // <--- "i" has no meaning. Does this variable have a purpose?

    cout << "\n Please enter a student name (\"done\" to leave the program): ";  // <--- No (\n) or "endl" needed
    getline(cin, studentName);


    if (studentName != "done")
    {
        //Call function that spits out prof
        //func(studentProf, studentName);
        GetProfession(studentName);

        while (studentName != "done")
        {
            cout << "\n Please enter another student name (\"done\" to leave the program): ";
            getline(cin, studentName);

            if (studentName != "done")
            {
                //check prof
                //func(studentProf, studentName);
                GetProfession(studentName);
            }
        }
    }

    return 0;  // <--- Not required, but makes a good break point for testing.
}


//void func(int studentProf, string studentName)
//{
//    string jobName;
//    //std::string jobNames[]{ "", "Certified", "Management", "Service", "Law_and_Order" };
//
//    cout << "Please enter the profession of: " << studentName << ": ";
//    cin >> studentProf;
//
//    if (studentProf == 1)
//        jobName = "Certified";
//    else if (studentProf == 2)
//        jobName = "Management";
//    else if (studentProf == 3)
//        jobName = "Service";
//    else if (studentProf == 4)
//        jobName = "Law_and_Order";
//    else
//        cout << "Wrong answer" << endl;
//    
//    cout << studentName << " is a "<< jobName <<" Professional\n";
//
//    cin.ignore();
//    cin.clear();
//    studentName.clear();
//}

void GetProfession(string& studentName)
{
    int studentProf{};
    std::string jobNames[]{ "", "Certified", "Management", "Service", "Law_and_Order" };

    std::cout << "\n The professions are:\n";

    for (int idx = 1; idx < 5; idx++)
    {
        std::cout << idx << ") " << jobNames[idx] << " Professional\n";
    }

    while (cout << "  Please enter the profession of " << studentName << ": " && !(std::cin >> studentProf) || studentProf < 1 || studentProf > 4)
    {
        if (!std::cin)
        {
            std::cerr << "\n     Invalid entry! Must be a number.\n\n";
            
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
        }
        else if (studentProf < 1 || studentProf > 4)
        {
            std::cerr << "\n     Invalid choice! Try again.\n\n";
        }
    }


    cout << "\n " << studentName << " is a " << jobNames[studentProf] << " Professional\n";

    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
}

The function I changed not only has a better name that describes the function it also deals with entering a non numeric value when a numeric value is expected with the formatted input of cin >> studentProf;.

And you do not have to pass "studentProf". It should be defined as a local variable in the function. Also the defined variable back in "main" is never changed or used.

Not saying it is the best way to write the program. "main" could still be done differently, but it is a start.

Andy
Thank you very much Andy! Im stepping through to make sure I understand each component of what you have done to try and learn! Thank you very much and i appreciate you taking the time to help me out! :)
Hello Hybrid10,

Any questions let me know.

I still want to do some more work.

In the function definition it is better to pass more complicated variables like "std::string", "std::vector" and other containers by reference rather than have the overhead of making a copy.

Andy
Hello Hybrid10,

I worked on the program some more and came up with this:
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
#include <iostream>
//#include <iomanip>  // <--- Good that you know about this, but not used in this program.
#include <limits>   // <--- Added.
#include <string>

constexpr int MAXSIZE{ 5 };

using namespace std;  // <--- Best not to use.
using JOBNAMES = std::string[MAXSIZE];

const JOBNAMES jobNames{ "", "Certified", "Management", "Service", "Law_and_Order" };

int GetProfession(string& studentName);

int main()
{
    int studentProfIdx{};
    string studentName{ " " };

    while (!studentName.empty())
    {
        //cout << "\n Please enter another student name\n (\"Enter when done\" to leave the program): ";
        cout << "\n Please enter a student name\n (\"Enter when done\" to leave the program): ";
        getline(cin, studentName);

        if (!studentName.empty())
        {
            //check prof
            //func(studentProf, studentName);
            studentProfIdx = GetProfession(studentName);

            cout << "\n " << studentName << " is a " << jobNames[studentProfIdx] << " Professional\n";
        }
    }

    return 0;  // <--- Not required, but makes a good break point for testing.
}

int GetProfession(string& studentName)
{
    int studentProf{};
    
    std::cout << "\n The professions are:\n";

    for (int idx = 1; idx < 5; idx++)
    {
        std::cout << idx << ") " << jobNames[idx] << " Professional\n";
    }

    while (cout << "  Please enter the profession of " << studentName << ": " && !(std::cin >> studentProf) || studentProf < 1 || studentProf > 4)
    {
        if (!std::cin)
        {
            std::cerr << "\n     Invalid entry! Must be a number.\n\n";

            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
        }
        else if (studentProf < 1 || studentProf > 4)
        {
            std::cerr << "\n     Invalid choice! Try again.\n\n";
        }
    }

    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.

    return studentProf;
}

"main" should direct the program flow, but in this case that is not as easy to do. A function should do 1 thing and either return a value or use variables passed by reference.

I eliminated the duplication in "main" and only used the while loop.

Line 9 may seem strange. What it is doing is defining a user variable type similar to "char" and "int". The advantage I have found is that it makes it much easier to pass an array by reference. The array type does not matter and it works well for 2D arrays.

Notes:
Try to use the new line (\n) over the function "endl" The changes and upgrades to the C++11 standards and the others that follow make using the (\n) work much the same as "endl". Also a "cout" statement followed by a "cin" statement will flush the buffer before any input is allowed. Unfortunately this does not work in reverse.

If you can figure out where to make the change, usually under a "Tools" menu, change the tab setting to use spaces instead of the tab character. The indenting will not look as exaggerated here.

If I think of anything else I will let you knnow.

Andy
Perhaps even simplified as:

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
#include <iostream>
#include <limits>
#include <string>
#include <iterator>

const std::string jobNames[] {"Certified", "Management", "Service", "Law_and_Order"};

int GetProfession(const std::string& studentName);

int main()
{
	for (std::string name; (std::cout << "\nEnter student name (or CR to exit): ") && std::getline(std::cin, name) && !name.empty(); ) {
		const auto studentProfIdx {GetProfession(name)};
		std::cout << '\n' << name << " is a " << jobNames[studentProfIdx] << " Professional\n";
	}
}

int getInt(const std::string& prm)
{
	int i {};

	while ((std::cout << prm) && (!(std::cin >> i) || std::cin.peek() != '\n')) {
		std::cout << "Not an integer\n";
		std::cin.clear();
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	}

	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	return i;
}

int GetProfession(const std::string& studentName)
{
	std::cout << "\nThe professions are:\n";

	size_t idx {};
	for (/*size_t idx {}; */ const auto& job : jobNames)
		std::cout << ++idx << ") " << job << " Professional\n";

	int prof {};

	do {
		prof = getInt("\nPlease enter the profession of " + studentName + ": ");
	} while ((prof < 1 || prof > std::size(jobNames)) && (std::cout << "Invalid number\n"));

	return prof - 1;
}




Enter student name (or CR to exit): seeplus

The professions are:
1) Certified Professional
2) Management Professional
3) Service Professional
4) Law_and_Order Professional

Please enter the profession of seeplus: 1

seeplus is a Certified Professional

Enter student name (or CR to exit):

Last edited on
Topic archived. No new replies allowed.