problem with getline() function - c++

I am a beginner at C++ and I'm trying to use the getline() function for the first time.
When I wrote this code, 2 errors showed up.
What is this code supposed to do?
It is supposed to read 4 numbers from read.txt then calculate it to find the mean and write the output in output.txt.
The 4 numbers (in read.txt) are all on separate lines like this:
6
12
15
19
Here is the code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
ifstream readFile;
ofstream sendFile;
readFile.open ("read.txt");
sendFile.open ("output.txt");;
float mean;
int num, num2, num3, num4;
getline(readFile, num), getline(readFile, num2), getline(readFile, num3), getline(readFile, num4);
readFile >> num >> num2 >> num3 >> num4;
sendFile << "1. The mean of " << num << ", " << num2 << ", " << num3 << ", and " << num4 << "is " << (num + num2 + num3 + num4) / 4;
readFile.close();
sendFile.close();
system ("PAUSE") ;
return 0;
}
Here are the errors:
IntelliSense: no instance of overloaded function "getline" matches the argument list 20
IntelliSense: too few arguments in function call 20

std::getline() takes two arguments: a stream and the std::string object into which to read the next line (and an optional third argument, the delimiter). You are passing an int instead of a std::string.
You should probably use the ordinary formatted extraction:
if (readFile >> num >> num2 >> num3 >> num4) {
// extraction succeeded!
}
else {
// extraction failed; handle the error here
}

getline reads into std::string, it can't read into ints. Just use readFile >> num >> num2 >> num3 >> num4; as you already have, and delete the line with getlines.
On another note, you don't need to close the files explicitly here as the destructors of file stream objects will take care of that for you.

std::getline is a useful tool for reading a single line of text or reading text up to a specific character, and writing it to a std::string where it can then be read further. By default it uses newline i.e. '\n' as the delimiter but you can change this.
With regards to using a stream to read in a number of integers then output their mean, why not just read to the end of the file, thus:
int count = 0, total = 0, num;
while( instr >> num )
{
++count;
total += num;
}
float mean = (count > 0 ) ? total / num : std::numeric_limits<float>::quiet_NaN();
outstr << mean;
You could make that a function, taking istream & instr and ostream & outstr
Suppose now we want to change that to read multiple lines, each with numbers delimited by space or tab. In our output we write all the means on their own line.
Now do something like this:
std::string line;
while( std::getline( bigInStr, line ) )
{
std::istringstream iss(line);
outputMean( iss, outstr );
outstr << '\n';
}
although you might want to not actually output the NaN but just leave that line blank in the output. A function calculating the mean probably would want to use a NaN as a return value if it has to return a float. We could calculate the variance, skewness and kurtosis at the same time if we want whilst iterating.
Then you would output these as multiple values on the line and you would have to pick your own delimiter. My own preference is to use tab ('\t') in this situation.
_

Related

C++ : if condition is evaluated with bad input (float) despite supposedly checking for it with cin.clear() and cin.ignore()

I thought I understood handling bad input with cin.clear() and cin.ignore(), like it is explained here, but in the following example
#include <iostream>
#include <limits>
using namespace std; //I know that this isn't good practice.
int main () {
int a, b;
while (cout << "Input some int: " && !(cin >> a)) {
cout << "Wrong datatype!\n";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
while (cout << "Input some int: " && !(cin >> b)) {
cout << "Wrong datatype!\n";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
if (a > 1) cout << "Some event.\n";
if (b > 1) cout << "Some other event.\n";
return 0;
}
the behavior I want is only present when the unwanted input is some character.
So if I enter x and y, I will again be asked for two ints and get the appropriate outputs, same if I enter a char and an int two times.
However: If I input, say, 2.3, I will get
Input some int: Wrong datatype!
but won't have a chance to correct my input, since the result invariantly outputs "Some event." The second prompt just accepts the float right away.
What's happening, actually, is the 2 in 2.3 is being accepted by the first prompt, leaving .3 in the input buffer. The Wrong datatype! you are seeing is from your second prompt, seeing a ., which is not a valid character for an integer. You then, I assume, enter an integer which is accepted by your second prompt.
This fundamental approach is fragile, and error-prone.
Your obvious intent is to accept a line of input, and process it. If so, then the correct function to do that is std::getline(). That's what its purpose is. That's exactly what it does. The >> operator does not do that. That's not what it's for. Of course, by using the various auxiliary methods, like ignore(), and clear(), one can still achieve that goal, but, as you've discovered, using those functions correctly is not intuitive. Of course, you can spend copious time pouring over their documentation to understand their every semantic behavior, but why bother, when you can simply use std::getline(), and then move on to something else. It's simply easier to do that.
Of course, once a line of input is received, you would like to parse it into an integer. Now is the correct time to use >> to parse it:
std::string line;
if (std::getline(line, std::cin))
{
std::istringstream i{line};
int n;
if (i >> n)
{
// Input parsed
}
}
Isn't this simpler, more straightforward, and less of a gotcha?. Of course, entering "2.3" here will result in the >> operator parsing the "2", and succeeding, leaving ".3" unparsed. If you would like to detect this situation, simply use get() to see what's left in the std::istringstream. Perhaps accept any trailing whitespace, if you wish.
The problem here is when you enter something like 2.3 to a int cin is okay with that. It reads the 2, sees the . so it stops reading and stores the 2 in the variable and leaves the .3 in the buffer for the next call. So, you pass the first loop, get to the second loop, and then you fail as it tries to read in the . into b. Then you clear the .3 and you can enter another input. If you enter another 2.3 the same thing will happen and b will get 2 and the program continues on.
The "bullet proof" way to read in input is to read it in as a std::string and then parse that to make sure the full input was good. That would look like
std::string line;
while (cout << "Input some int: " && std::getline(cin, line)) {
std::stringstream ss(line);
ss >> a;
if (ss.eof()) // we did consume all the input
break;
else
cout << "Wrong datatype!\n";
}
while (cout << "Input some int: " && std::getline(cin, line)) {
std::stringstream ss(line);
ss >> b;
if (ss.eof()) // we did consume all the input
break;
else
cout << "Wrong datatype!\n";
}
When you input "2.3", cin will stop at '.', and interpret '2' as the desired input.
Then, you will clear cin, when the '.' is encountered, discarding 3.
If you then input a new integer, it will accept it.
Many answers here suggest the use of std::getline and string parsing, either using the string functions or stringstreams. This is quite inefficient and not the way the streams are supposed to be used.
Instead, parse the data when it is still in the input stream:
#include <iostream>
#include <cctype>
#include <limits>
struct read_int {
int& a;
read_int(int& aa) : a{ aa } { }
friend std::istream& operator >>(std::istream& is, read_int& ri) {
char delim;
while(!(is >> ri.a) || (delim = is.get(), delim != '\n' && !std::isspace(delim))) {
std::cerr << "Bad!\n";
is.clear();
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return is;
}
};
int main() {
int a, b;
std::cin >> read_int(a) >> read_int(b);
std::cout << a << ' ' << b;
return 0;
}
This function will accept input like "4 5" or "4\n6" alike, but requests a new input for data like "4.2", discarding everything read before.

reading multiple lines from a file using getline?

I am trying to read in the data in a names.txt file and output the full name and ideal body weight for each person. Using a loop to read the names and feet and inches of each person from the file.
The file reads:
Tom Atto
6
3
Eaton Wright
5
5
Cary Oki
5
11
Omar Ahmed
5
9
I'm using the following code for this:
string name;
int feet, extraInches, idealWeight;
ifstream inFile;
inFile.open ("names.txt");
while (getline(inFile,name))
{
inFile >> feet;
inFile >> extraInches;
idealWeight = 110 + ((feet - 5) * 12 + extraInches) * 5;
cout << "The ideal weight for " << name << " is " << idealWeight << "\n";
}
inFile.close();
when i run this im getting output:
The ideal weight for Tom Atto
is 185
The ideal weight for
is -175
Add this statement in while loop after reading the two extraInches value.
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
It ignores the '\n' after the second integer you read in while loop. You may refer: Use getline and >> when read file C++
You are running into problems because after the line
inFile >> extraInches;
is executed in the first iteration of the loop, there is still a newline character in the stream. The next call to getline simply returns an empty line. The subsequent call
inFile >> feet;
fails but you don't check whether the call was successful.
Couple of things I want to mention in relation to your problem.
Mixing unformatted input, using getline, and formatted input, using operator>> is fraught with problems. Avoid it.
To diagnose IO related problems, always check the state of the stream after an operation.
In your case, you can use getline to read lines of text, and then use istringstream to extract numbers from the lines.
while (getline(inFile,name))
{
std::string line;
// Read a line of text to extract the feet
if ( !(inFile >> line ) )
{
// Problem
break;
}
else
{
std::istringstream str(line);
if ( !(str >> feet) )
{
// Problem
break;
}
}
// Read a line of text to extract the inches
if ( !(inFile >> line ) )
{
// Problem
break;
}
else
{
std::istringstream str(line);
if ( !(str >> inches) )
{
// Problem
break;
}
}
idealWeight = 110 + ((feet - 5) * 12 + extraInches) * 5;
cout << "The ideal weight for " << name << " is " << idealWeight << "\n";
}

C++ read in a line of string as ints?

I am trying to read a line of string characters with numbers (e.g "30 40 50 20") and put them into a vector. I also need to avoid empty space and newlines. But when I read the input, it doesn't see the string "30", it sees the characters "3" and "4".
void Input() {
getline(cin,line, '\n');
for (int i = 0; i < line.length(); i++) {
if (! (isspace(line[i]))) {
cout << line[i] << ", ";
scores.push_back(line[i]);//(atoi(input));
}
}
cout << scores.size() << "! ";
}
A line like "30 40 50" won't give a vector size of 3, it will give a size of 6.
What are the optimal ways to get around this issue?
EDIT: I should have clarified in the original message that this is for a challenge, in which I am unable to include the string stream library in the original case.
I think you're doing the right thing grabbing the whole line before parsing, otherwise you get into a bit of a pickle. But you do actually have to do some parsing. Right now you're just pulling out individual characters.
The following isn't optimal but it'll get you started — continue using formatted stream extraction, but isolated to this line from the file.
So:
void Input()
{
getline(cin, line, '\n');
istringstream ss(line);
int val;
while (ss >> val)
scores.push_back(val);
cout << scores.size() << "! ";
}
Read the line and put into a std::istringstream, then read as "normally" using the >> operator from the string stream.
Putting the line into a std::istringstream and extracting the numbers from that is the best way.
Here's an alternative to a manual loop using the standard library:
std::istringstream numbers(line);
std::copy(std::istream_iterator<int>(numbers),
std::istream_iterator<int>(),
std::back_inserter(scores));
It is probably best to take advantage of an input stringsteam, example: http://www.cplusplus.com/reference/sstream/stringstream/stringstream/.
The extraction operator allows you to parse data from the stream to some variable of datatype T. Another advantage of input stringstreams is the ability to query whether the pass was successful, and in your case ignore whitespace characters by setting the skipws format flag.
Example:
int main () {
std::istringstream ss("30 40 50");
float val = 0.0f;
while( ss >> std::skipws >> val )
{
std::cout << val << "\n";
}
return 0;
}
Out: 30 40 50

(c++) Reading numeric data in a column from a txt file and determining highest value

So I'm trying to make a program that will read a txt file where time, voltage and ampere are stored, the text file looks like this http://pastebin.com/a0ZvYGmj, only ten times bigger (it's obnoxiously huge, so large that it didn't fit into a single pastebin).
So what I have to do is write a program that will read through the entire voltage column and detect the highest value (second column), then display it and the time it occurs (first column). I can also do it with the ampere, but that's optional.
Problem is I literally have no idea what to do, this is what I have managed to do so far
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
FILE * pFile;
char mystring [100];
pFile = fopen ("voltage.txt" , "r");
if (pFile == NULL) perror ("Error opening file");
else {
if ( fgets (mystring , 100 , pFile) != NULL )
puts (mystring);
fclose (pFile);
}
system ("PAUSE");
return 0;
}
But all that does is read the first entry of each of the 3 columns ("Time Volt Ampere"), so I probably have to start over.
Can anyone send me in the right direction? How do I read an entire column, them make the program detect the biggest number in said column?
I'm completely lost so any help would be appreciated.
If you have the option of using the file as an input, then you could use simple cin in order to get your values for Time,Volt and Amp. ( the only thing you need to keep in mind is to ignore first row because they are just names)
If you know that all three values in each row will be present, then you can create while loop that runs until EOF. Then you read 3 values (Time, Volt, Amp) and compare with the previous Volt.
If previous volt is larger - ignore this row and move on.
Else - keep current Time, Volt and Amp.
On the next iteration, compare new 3 values to the max value of Volt so far.
Here is my "quick and dirty" solution:
#include <iostream>
#include <string>
using namespace std;
int main()
{
// cin>>temp goes through names and ignores it since we don't need it
string temp;
cin >> temp;
cin >> temp;
cin >> temp;
float timeval = 0;
float volt = 0;
float amp = 0;
float timevalTemp = 0;
float voltTemp = 0;
float ampTemp = 0;
while(cin >> timevalTemp >> voltTemp >> ampTemp)
{
if(voltTemp > volt)
{
timeval = timevalTemp;
volt = voltTemp;
amp = ampTemp;
}
}
cout << "Max Time: " << timeval << endl;
cout << "Max Volt: " << volt << endl;
cout << "Max Amp: "<< amp << endl;
return 0;
}
Let me know if something is not clear. I ran it on your text file and it produces:
Max Time: 0.00035
Max Volt: 9.78167
Max Amp: 0.1473
You can try using fscanf. Please have a look at this How to use fscanf to read a file
After you read you will have to compare voltage values of each row to get max voltage. I hope you know how to do this.
First, you must use a llop construction so you read the whole set of lines. So try putting your fgetsinside of a while.
Next, you need to split each line by spaces. Use strtokfor that.
Next I'll recommend you keep a max_voltage variable and as you travel through the file, you assign it the current max value. Also, you need to keep track of that max_voltage variable's timecompanion so use another variable for that one (Google for "find max value in an array" if you have doubts about how to do it).
After you try that, post your work if you have some question/need clarifications.
Bye.
fgets reads file untill it encounter newline character, or end of file.
If fgets encounters eof before any character it'll return null pointer. So it should be okay if you change file reading code to:
while ( fgets (mystring , 100 , pFile) != NULL )
puts (mystring);
I would define what a line looks like:
struct Line {
double time, volt, ampere;
int linenumber;
};
istream& operator>>(istream& in, Line& line) {
++linenumber;
return in >> line.time >> line.volt >> line.ampere;
}
ostream& operator<<(ostream& out, const Line& line) {
return out << "Line: " << line.linenumber
<< " Time: " << line.time
<< " Volt: " << line.volt
<< " Ampere: " << line.ampere;
}
and use it with std::cin.
int main()
{
string dummy;
std::istream& in = cin;
in >> dummy >> dummy >> dummy;
Line max;
Line line;
while(in.good()) {
in >> line;
if (line.volt > max.volt) max = line;
}
cout << "Max line: " << max;
return 0;
}
(or you can replace cin with a file input stream:
#include <ifstream>
...
std::ifstream in(argv[1]);
...
)
You can use sort for that, it's a highly specialized merge-sort implementation that surely included in your cygwin distro. You can tell it which columns to sort on (the -k switch), and it both works with stdandard input and filename.
Then just take e.g. the first 4 lines of output to account for 'special' lines. Use cat -n to prepend line numbers.
$ cat -n input.txt | sort -r -k 2 | head -n 10
1 Time Volt Ampere
4796 0.2398 9.76417 0.147683
4795 0.23975 9.75667 0.147833
4794 0.2397 9.77333 0.147867
4793 0.23965 9.7575 0.14765
4792 0.2396 9.75167 0.147533
4791 0.23955 9.75833 0.147542
4790 0.2395 9.75583 0.147542
4789 0.23945 9.77 0.1476
4788 0.2394 9.75583 0.147317

input from txt file to arrays

I have a text file with a line like:
James Dean 10 Automotive 27010.43
and I need to read that file and put each of the 4 above into arrays.
char nameArray[MAX][NAME_MAX];
int yearArray[MAX];
char departmentArray[MAX][DEP_MAX];
double payArray[MAX];
while(i < MAX && infile) {
infile.getline(nameArray[i], 20);
infile >> yearArray[i];
infile.getline(departmentArray[i], 15);
infile >> payArray[i];
cout << nameArray[i] << " " << yearArray[i] << " " << departmentArray[i] << " " << fixed << setprecision(2) << payArray[i] << endl;
i++;
}
The code is cut down just to give you an idea of what I am trying to do, but when I run this, I get something like:
James Dean -858993460 -92559631349317830000000000000000000000000000
000000000000000000.00
Thanks for the help.
==== Edit ==========================================
I changed from getline to get, thanks for that. I have to use get and not >> because some of the lines I am reading in are more than just "James Dean", they are up to 20 char long...ex: "William K. Woodward" is another one.
So, if I just use get, then it reads the first line in fine, but then I get the same messed up text for the second line.
Here is the code:
infile.get(nameArray[i], 20);
infile >> yearArray[i];
infile.get(departmentArray[i], 15);
infile >> payArray[i];
The getline functions takes an input stream and a string to write to. So, two getline calls read in two lines. Your input mechanism is broken. Either, use getline or the stream extraction operator (i.e. >>) but not both.
If you plan to use getline you need to parse the string (which is effectively one line of input) into tokes, and then store them in appropriately typed arrays. The second and fourth tokens are numbers, hence you will need to convert these from string to int or double.
The operator >> approach:
string name, surname;
int year;
double pay;
while (infile) {
infile >> name >> surname >> year >> department >> pay;
namearray[ i ] = name + " " + surname;
// ...
payarray[ i ] = pay;
++i;
}
The getline approach:
string line;
while (getline(infile, line)) {
parse(line, tokens);
namearray[ i ] = token[ 0 ] + " " + token[ 1 ];
// ...
payarray[ i ] = strTodouble(token[ 4 ]);
++i;
}
// parse definition
void parse(string line, vector<string>& token) {
// roll your own
}
double strToDouble(string s) {
// ...
}
I dont see where you define infile but I will assume that it is an ifile . In that case you should use it the same way u use cin to get input.
Why do you do a getline () ?
That function will stop only at an '\n' char or at an EOF char. So it means, you start reading the int after the end of the line, some random data.
Correct me if i'm wrong, but are there 20 or 19 characters in that first string (James Dean) before the number (10) ?