Unable to read char array using cin.getline - c++

We were asked to create a class which did the following:
Input int ecode, char ename and basicpay
Now in class, we had to calculate net_pay = basicpay*11/10
Lastly, we had to output ecode, ename and net_pay.
The question stated that net_pay variable cannot be created, its value only has to be used for output, and that value had to be calculated using a separate member function calc
Here is my code:
// Class employee
#include <iostream>
#include <cstdio>
using std::cin;
using std::cout;
class emp {
int ecode;
char ename[20];
float basic_pay;
public:
void input() {
cin >> ecode;
cin.ignore();
cin.getline( ename, 20); // <-- PROBLEM HERE
cin >> basic_pay;
}
float calc( float x) {
return x+x/10;
}
void output() {
cout << "\n Emp. code: " << ecode;
cout << "\n Emp. name: " << ename;
cout << "\n Emp. basic pay: " << basic_pay;
cout << "\n Emp. net pay: " << calc( basic_pay);
}
};
int main() {
emp e1;
cout << "Enter details of employee:\n";
e1.input();
cout << "\nUpdated Profile:\n";
e1.output();
return 0;
}
Error
I am frustrated from past hour about this problem with cin.getline.
String size < 20
The code is working fine for input string size less than 20, so I don't need cin.ignore(), and if I use it, cin.ignore is removing a first digit of basic_pay:
See images: Both are for small string input. Second one is with cin.ignore()
Notice below: Basic_pay was 1100, but it ignored 1.
String size > 20
If I input a string with char number greater than 20, then the overflowing char goes to float, and creates error. So to counter this, I need a cin.ignore(), but even that is not working!
Question
I am in a dilemma. For one string size, cin.ignore() is problamatic, but for other it has no effect. What to use, what not to use? Both are creating mutual conflict. Help me please!

cin.getline(name, 20) can only get 19 characters (one is reserved for the '\0'), therefore if someone inputs 20 or more, then cin.getline(name, 20) will fail, and the next cin >> basic_pay will fail too since the stream error flags are still set, you need to clear them with cin.clear().
Fix:
#include <limits> // for numeric_limits
if (!cin.getline(ename, 20)) // <-- PROBLEM HERE
{
std::cout << "Name too long, trimmed to: " << ename << std::endl;
// clear the stream error flags and ignore rest of the line
cin.clear();
cin.ignore(std::numeric_limits<int>::max(), '\n');
}
// now this line will not fail
cin >> basic_pay;
Live Demo

Related

Program is not asking 3 questions and uses my answer to the first question for the other two

I am trying to ask the user to enter the names of 3 of their friends, however, it only asks one question and writes the answer from my first one in the second and third.
#include <iostream>
using namespace std;
int main()
{
char first_name;
cout << "Please enter a name: ";
cin >> first_name;
cout << first_name << endl;
char second_name;
cout << "Please enter a name: ";
cin >> second_name;
cout << second_name << endl;
char third_name;
cout << "Please enter a name: ";
cin >> third_name;
cout << third_name << endl;
return 0;
}
You should probably be using string in your code to take the input of names. In names you are probably passing more than one character. The first one is read by first_name and any further character will be read by the following character, specifically cin>>second_name and cin>>third_name would read the 2nd and 3rd character of your input.
char a;
char b;
cin>>a; //will only read one character and stop
cin>>b; //will read the second character of the input...
//be that after pressing enter(a Enter b) or continuous input (ab)
cout<<a<<" "<<b; //will output 1st and 2nd character only
This will happen even if you don't press the Enter key explicitly and this is why your program uses the answer of first question(which is probably more than 1 character since it is a name) in your code as the answer to 2nd and 3rd questions as well.
So for your purpose, you are better of using string to take input from the users.
Hope this clears your doubt !
You tried to hold a lot of chars (one word) in one char who can hold only one char.
#include <iostream>
#include <string> // We need a string, container to hold a chars. Something like array of chars but have a few difference.
using namespace std; // You should avoid using this but in that short code this doesn't matter
int main()
{
// You don't need separate container for this code
// Then we create one container to holds all of inputs
string input;
cout << "Please enter a name: ";
cin >> input; // Put input from user in our input(string)
cout << input << endl; // Print input
// Next code is the same as above
cout << "Please enter a name: ";
cin >> input;
cout << input << endl;
cout << "Please enter a name: ";
cin >> input;
cout << input << endl;
return 0;
}
I special avoided a few elements like using function because this must be simple as possible.

Looping if user input invalid

I want to create a program that when a user inputs something that I didn't define, the program prompts him again.
I did it with if statements but it only loops for 1 time and doesn't do it again. I tried loops but whenever the input is false it just breaks the condition and refuses all inputs alike. In c++.
Any help is much appreciated.
#include <iostream>
#include <string>
using namespace std;
void xD(){string x;
do{cout << "Retry\n";
cin >> x;}while(true);}
//declaring a function to make the shop
void shop(){
string x;
float coins = 500;
float bow_cost = 200;
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
cin >> x;
// if u chose bow you get this and get to choose again
if (x == "bow"){
cout << "you bought the bow.\n you now have " <<coins - bow_cost << " coins." << endl; cin >> x;}
/*now the problem that whenever I excute the code and type something other than bow it gives me the cin only once more and then fails even if I type bow in the 2nd attempt*/
//in my desperate 5k attempt, I tried creating a function for it.. no use.
//i want it o keep prompting me for input till i type "bow" and the other block excutes. but it never happens.
else{xD();}
}
int main(){
string name;
string i;
cout << "if you wish to visit the shop type \"shop\"\n";
cin >> i;
if(i == "shop"){shop();}
else{cin >> i;}
return 0;
}
The problem lies on the condition in this loop block
void xD(){
string x;
do{
cout << "Retry\n";
cin >> x;
}while(true);
}
The while(true) condition makes it loops forever regardless of the input. To fix this, you can change the condition:
void xD(){
string x;
do{
cout << "Retry\n";
cin >> x;
}while(x!="bow");
cout << "you bought the bow. and some other messages"<<endl;
}
That should work. However, it is still too complicated for me. This can be simplified into the snippet below:
void shop(){
string x;
float coins = 500;
float bow_cost = 200;
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
cin >> x;
while (x!="bow"){
cout << "Retry\n";
cin>>x;
}
cout << "you bought the bow.\n you now have " <<coins - bow_cost << " coins." << endl; cin >> x;
}
Instead of doing this approach (which is checking the condition only once):
if (x == "bow"){
cout << "you bought the bow.\n you now have " <<coins - bow_cost << "
coins." << endl; cin >> x;
} else{
xD();
}
which is actually a RECURSIVE invocation to the method xD()
you should do a do-while loop,
example:
while (x.compare("bow") != 0)
{
cout << "sorry, wrong input, try again...";
cin >> x;
}
note the use of the compare method instead of the == operator
here more about it in the documentation
You can use return value of cin >> [your input object] here to check status or istream's method fail(). As soon as input stream fails to parse whole or part of streams it fails and stay in state of failure until you clear it. Unparsed input is preserved (so you can try to parse it differently?)m so if you try to >> again to object of same type, you'll get same failure. To ignore N chars of imput, there is method
istream::ignore(streamsize amount, int delim = EOF)
Example:
int getInt()
{
while (1) // Loop until user enters a valid input
{
std::cout << "Enter an int value: ";
long long x; // if we'll use char, cin would assume it is character
// other integral types are fine
std::cin >> x;
// if (! (std::cin >> x))
if (std::cin.fail()) // has a previous extraction failed?
{
// yep, so let's handle the failure, or next >> will try parse same input
std::cout << "Invalid input from user.\n";
std::cin.clear(); // put us back in 'normal' operation mode
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); // and remove the bad input
}
// Thechnically you may do only the above part, but then you can't distingusih invalid format from out of range
else if(( x > std::numeric_limits<int>::max()) ||
( x < std::numeric_limits<int>::min()))
{
std::cout << "Invalid value.\n";
}
else // nope, so return our good x
return x;
}
}
For strings parsing is almost always successful but you'll need some mechanism of comparison of string you have and one that is allowed. Try look for use of std::find() and some container that would contain allowed options, e.g. in form of pair<int,string>, and use int index in switch() statement (or use find_if and switch() within the function you give to it).
Consider that if() statement is a one_direction road, it checks the condition and if the condition was satisfied it goes to its bracket and do blah blah blah , if there is any problem with condition compiler passes ifand jump to compile other codes.
Every time that you begin to compile the codes it begins from int main() function. You did the wrong thing in the if and else statements again
Here is the correct code .I did the necessary changes.
#include "stdafx.h"
#include <iostream>
#include <string>
using std::string;
using std::cin;
using std::cout;
#define coins 500 ;
#define bow_cost 200 ;
int shop(string x)
{
//There is no need to allocate extra memory for 500 and 200 while they are constant.``
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
do
{
cout << "Input another :\n";
cin >> x;
if (x == "bow")
{
return (coins - bow_cost); //return to function as integer
}
} while (true);
}
int main()
{
string name, i;
cout << "if you wish to visit the shop type \"shop\"\n";
cin >> i;
if (i == "shop")
{
cout << "Input :\n";
cin >> name;
cout << shop(name) << "you bought the bow.\n you now have " << " coins." << "\n";
}
//argument passed to shop funnction parameters.
system("pause");
return 0;
}

How to use EOF loop to iterate for each student in the file

How do I set up a loop to read in file data until eof is reached?
Basically, I have a data file with student data, and for each student there is quiz grades, test grades, lab grades, etc.
I have a function that gives the values as letter grades.
My issue is to set up the loop to compute each function 4 times for each student. My loop code so far uses a counter loop, but I'm supposed to turn it into an eof loop instead.
My code below ends when there is no more data to read.
int main()
{
int counters = 1;
char lab;
char assgniment_score;
char quiz_score;
char test_score;
float final_total_average;
myfile.open("infile.txt");
while (counters <= 20) {
lab = Compute_lab_grade();
assgniment_score = Compute_Assignment_grade();
quiz_score = Compute_Quiz_grade();
test_score = Compute_test_grade();
final_total_average = (10 * (total(quiz_score))
+ (25 * (total(assgniment_score)))
+ (30 * (total(lab))) + (35 * total(test_score))) / 100;
cout << "Student " << counters << endl;
cout << "Student Lab grade is : " << lab << endl;
cout << "Student Assignment grade is : " << assgniment_score << endl;
cout << "Student Quiz grade is : " << quiz_score << endl;
cout << "Student Exam grade is : " << test_score << endl;
cout << "Student Final grade is : " << final_average_score(final_total_average) << endl << endl;
counters++;
}
}
The structure of the given data looks like this:
Rational for answer: OP is headed in many wrong directions all at once and I think a few of them can be headed off with one good example.
Problem 1: EOF loop is a myth. Read more here: Why is iostream::eof inside a loop condition considered wrong?
Problem 2: using char to represent numbers. Technically char is an integer type, but it is most commonly associated with a single character and its input/output routines are overloaded accordingly. Eg. if given input "1234" std::cin >> a_char; will result in char a_char containing the character '1', but std::cin >> an_int; will result in int an_int containing the the number 1234. In addition using a character to represent a number can often lead to confusion for thew reader who may misinterpret what your code is supposed to do. You can do it and sometimes it is the appropriate choice, but this time it doesn't make much sense.
Problem 3 Scattershot and unchecked IO. It's generally best to read in everything you want and then, if the input is good, make a decision on all of it all at once. If a student's record is not complete without 27 integers, read all 27 integers and check that each and every one read correctly. If you can't read them all, that's an error. If some are not integers, that's an error. If you have an error, the student is not a valid input and should either be discarded or investigated more closely.
Problem 4: Not using a data structure to contain associated data. A student is represented by a bunch of information. It is convenient to package that information with the methods by which the information can be accessed and manipulated. Read up on encapsulation.
Minor nag: Why is "using namespace std" considered bad practice?
So here we go:
#include <iostream>
#include <fstream>
#include <sstream>
// using namespace std; avoid using this. Can be very dangerous to the unwary.
// container class to aggregate student stats and provide manipulators to read
// and display a student
class Student
{
static int count; // only the students use the counter. No need for it to be global.
int student_number;
// int telegraphs your intent much better than char
// These variables are numbers, not characters and should be treated like them
int lab;
int assgniment_score;
int quiz_score;
int test_score;
float final_total_average;
public:
// simple input function. This is a bit too simple for OP, but should be
// enough for OP to get the idea.
friend std::istream & operator>>(std::istream & in, Student & student)
{
std::string line;
student.student_number = count ++;
if (std::getline(in, line))
{
std::stringstream stream(line);
if (stream >> student.lab
>> student.assgniment_score
>> student.quiz_score
>> student.test_score)
{ // if we read all the variables we needed
// divided by 4.0 because division of int by int will
// give an int, not a float.
student.final_total_average = (student.lab +
student.assgniment_score +
student.quiz_score +
student.test_score) / 4.0;
}
else
{ // failed to read. Mark stream bad.
in.setstate(std::istream::failbit);
}
}
return in;
}
// simple output function OP shouldn't have to change much here.
friend std::ostream & operator<<(std::ostream & out, Student & student)
{
//endl is line feed and IO flush very expensive, so use only
// when you absolutely need to flush the stream. This turns out to be
// almost enver.
out << "Student " << student.student_number << '\n'
<< "Student Lab grade is : " << student.lab << '\n'
<< "Student Assignment grade is : " << student.assgniment_score << '\n'
<< "Student Quiz grade is : " << student.quiz_score << '\n'
<< "Student Exam grade is : " << student.test_score << '\n'
<< "Student Final grade is : " << student.final_total_average << '\n';
return out;
}
};
// allocate storage for student counter
int Student::count = 1;
int main()
{
// create and open file. As with the counter, no need for it to be global
// because it can easily be passed by reference into functions that need it.
std::ifstream myfile("infile.txt");
Student student; // allocate a dummy student to read into and print
// because we have smart rules for reading in a student, this is easy.
while (myfile >> student) // read students until error or end of file
{
std::cout << student; // write the current student
}
}

Using array from class in main function

Consider the following code:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
class treasure
{
public:
char name[100];
double value[100];
double weight[100];
};
int itemNumber, totalWeight, i;
treasure item;
std::cout << "Enter total item weight: " << std::endl;
std::cin >> totalWeight;
std::cout << "Enter total item number: " << std::endl;
std::cin >> itemNumber;
for( i = 0; i < itemNumber; i++)
{
std::cout << "Enter item name: " << std::endl;
std::cin >> item.name[i];
}
return 0;
}
I wanted to input 5 item in the array but it is just asking for two item. It takes one item at first and then after printing three lines again takes another input. What seems to be the problem. What did went wrong?
char name[100]; means that you can save up to 100 items of type char, not 100 strings.
An important effect here is that your input is buffered. std::cin >> item.name[i]; takes one char from the input buffer and writes it to name[i]. The rest of your input remains in the buffer and will be used for the next execution of cin, i.e. the next execution of the same code line.
So if you enter e.g. 'abc' it saves 'a' to item.name[0], 'b' to item.name[1] and 'c' to item.name[2]. For item.name[3] the input buffer is empty so it waits for your next input.

Converting string to number when using getline()

I've picked up a book on C++ and I'm basically at the very beginning of it (just started). For some of the problems I had to solve within the book I used the input stream cin the following way -->
cin >> insterVariableNameHere;
But then I did some research and found out the cin can cause a lot of problems, and so found out about the function getline() within the header file sstream.
I'm just having some trouble trying to wrap my head around what's happening in the following code. I don't see anything that uses the extraction operator (>>) to store the number value in. Its (my problem) further explained in the comments I left.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
// Program that allows a user to change the value stored in an element in an array
int main()
{
string input = "";
const int ARRAY_LENGTH = 5;
int MyNumbers[ARRAY_LENGTH] = { 0 };
// WHERE THE CONFUSION STARTS
cout << "Enter index of the element to be changed: ";
int nElementIndex = 0;
while (true) {
getline(cin, input); // Okay so here its extracting data from the input stream cin and storing it in input
stringstream myStream(input); // I have no idea whats happening here, probably where it converts string to number
if (myStream >> nElementIndex) // In no preceding line does it actually extract anything from input and store it in nElementIndex ?
break; // Stops the loop
cout << "Invalid number, try again" << endl;
}
// WHERE THE CONFUSION ENDS
cout << "Enter new value for element " << nElementIndex + 1 << " at index " << nElementIndex << ":";
cin >> MyNumbers[nElementIndex];
cout << "\nThe new value for element " << nElementIndex + 1 << " is " << MyNumbers[nElementIndex] << "\n";
cin.get();
return 0;
}
stringstream myStream(input): Creates a new stream that uses the string in input as "input stream" so to speak.
if(myStream >> nElementIndex) {...): Extracts number from the stringstream created using the line above into nElementIndex and executes ... because the expression returns myStream, which should be non-zero.
You were probably confused by using the extraction as the condition in the if statement. The above should be equivalent to:
myStream>>nElementIndex; // extract nElement Index from myStream
if(myStream)
{
....
}
What you probably wanted was
myStream>>nElementIndex; // extract nElement Index from myStream
if(nElementIndex)
{
....
}