Cannot read integers from a txt file containing 2 columns (C++) - c++

i have to write a code that prompts user to enter a file name (containing 2 columns of integer). The program then reads that file, prints out the numbers set.
My txt file looks like this (the numbers are separated by space):
2 3
5 6
7 8
8 9
5 7
I thought it would be easy, but now i stuck. When i run the program, this line appeared
"There're no number in the file."
I set number to "int", so why can't the compiler read the number? But when i change the type to "string", the numbers did appear O_O , since i later need to calculate the average of those num also, i cannot use string.
Here is my code, I appreciate any help TT___TT
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
int main()
{
ifstream in_file;
string filename;
int number;
int number1;
cout << "In order to process, please enter the file name: ";
cin >> filename;
in_file.open(filename.c_str());
if (!in_file.is_open())
{
cout << "Cannot open file" << endl;
}
else
{
in_file >> number;
if (in_file.fail())
{
cout << "There're no number in the file." << endl;
}
while (in_file >> number >> number1)
{
cout << number << " " << number1;
}
}
system("pause");
return 0;
}

Error in your logic:
in_file >> number; // Assigns 2 from first line to number
if (in_file.fail())
{
cout << "There're no number in the file." << endl;
}
while (in_file >> number >> number1) // Assigns 3 to number from first line
// and assigns 5 to number1 from second line
{
cout << number << " " << number1;
}
You need to use just:
while (in_file >> number >> number1)
{
cout << number << " " << number1;
}
If you must print "There're no number in the file." in the output, you can use:
bool gotSomeNumbers = false;
while (in_file >> number >> number1)
{
cout << number << " " << number1;
gotSomeNumbers = true;
}
if (!gotSomeNumbers)
{
cout << "There're no number in the file." << endl;
}

The method you are using to find to know whether file is empty is not
correct in following way :: As soon as this line gets executed
in_file >> number;
The compiler will treat first line as an integer as a whole , i.e.
number = "2 3" in given scenario. now this is not a standard number
because of space in between 2 and 3 and
in_file.fail() will return true.
The Correct way is to use "eof" function as follows : (I also added
1-2 lines to calculate average of these numbers as you mentioned)
Correct code
Reference :
When will ofstream::open fail?
Checking for an empty file in C++

Related

Trying to validate input in C++

The idea behind this code in c++ is to calculate the sum of all the entered numbers. When the user enters 0, the program should stop. This part of the code is working as I intended, but I'd like to include a variant which recognizes that a character different than a float number has been entered, ignore it in the calculation and allow the user to continue entering float numbers. At the moment, entering anything else but a float number stops the program.
I know there's a "if (!(cin >> numb))" condition, I've tried parsing it in different places in the code, but I can't figure out how to force the program to ignore these invalid inputs. I would be very grateful for any help.
#include <iostream>
#include <stdlib.h>
using namespace std;
float numb; float sum=0;
int main()
{
cout << "This app calculates the sum of all entered numbers." << endl;
cout << "To stop the program, enter 0." << endl << endl;
cout << "Enter the first number: ";
cin >> numb;
while(true)
{
sum += numb;
if (numb!=0)
{
cout << "Sum equals: " << sum << endl << endl;
cout << "Enter another number: ";
cin >> numb;
}
else
{
cout << "Sum equals: " << sum << endl << endl;
cout << "Entered 0." << endl;
cout << "Press Enter to terminate the app." << endl;
exit(0);
}
}
return 0;
}
You have three options:
trial and error: try to read a float, and in case of error clear the error flag, ignore the bad input and read again. The problem is that you don't know really how many of the input is to be ignored.
read strings: read space delimited strings, try to convert the string using stringstream, and just ignore the full string in case of error. The problem is that if the input starts with a valid float but then contains invalid characters (e.g. 12X4), the invalid part will be ignored (e.g. X4)
control parsing: read space delimited strings, try to convert the string using std::stof(), and check that all characters of the string where successfully read
Here the second approach, with a slightly restructured loop, so that a 0 entry will lead to exiting the loop and not the full program:
string input;
while(cin >> input)
{
stringstream sst(input);
if (sst>>numb) {
sum += numb;
cout << "Sum equals: " << sum << endl << endl;
if (numb==0)
{
cout << "Entered 0." << endl;
break; // exits the while loop
}
cout << "Enter another number: ";
}
else
{
cout << "Ignored entry "<<input<<endl;
}
}
cout << "Press Enter to terminate the app." << endl;
Online demo
If you prefer a more accurate parsing, consider something like:
size_t pos=0;
float xx = stof(input, &pos );
if (pos!=input.size()) {
cout << "error: invalid trailing characters" <<endl;
}
You have to clear the failbit after a failed read. After that, you can read in the invalid stuff into a string (that you just ignore). This function will read in values and add them up until it encounters a 0 or the end of the input stream.
int calc_sum_from_input(std::istream& stream) {
int sum = 0;
// If it couldn't read a value, we just read the thing into here
std::string _ignored;
while(stream) // Checks if the stream has more stuff to read
{
int value;
if(stream >> value)
{
if(value == 0) // Exit if it read the value 0
break;
else
sum += value; // Otherwise update the sum
}
else {
// Clear the failbit
stream.clear();
// Read ignored thing
stream >> _ignored;
}
}
return sum;
}
The logic is basically:
set the initial sum to 0
check if there's stuff to read
if there is, try reading in a value
if successful, check if the value is 0
if it's 0, exit and return the sum
otherwise, add the value to the sum
otherwise, clear the failbit (so that you can read stuff in again) and read the bad value into a string (which gets ignored)
otherwise, return the value

visual studioc++ array size in struct is too long

I am currently doing an assignment for my beginner C++ course, the chapter is on structs. I am using visual studio so I am can't do anything fancy for dynamic array's (i.e. no vector's etc.).
The part of the homework I am having trouble with is reading a file with some spaces at the end of the file. Since I am using filename.eof() it is reading the blanks and recording that data. I tried doing cin.ignore(xxxxx, '\n'), however that did not work. The my current out put is the data I want but a row of garbage. How do I get rid of the garbage?
a) A function to read the data into the array. You can use the attached file named soccer-1.txt to test your code. It also goes without saying that your code must work with any input data file. Of course, for testing, use your file to avoid entering data while testing. The name of the data file must always be entered by the user (do not hard code a file name). Also, check to make sure that the given input data file exists. If the file does not exist, issue an error message to alert the user about the invalid file name. Make sure to ask the user again for the name of another file. However, terminate the program after the user has entered an incorrect file name for a total of 3 times. NOTE: the data file name can be input inside the function.
The text file looks like this:
"
Duckey E Donald forward 8 2 21
Goof B Goofy defense 12 0 82
Brave A Balto goalkeeper 0 0 5
Snow W White defense 1 2 3
Alice I Wonderful midfield 1 5 15
Samina S Akthar right_defense 1 2 7
Simba P Green left_back 7 3 28
**************WHITESPACE****************************
**************WHITESPACE****************************
Here is my code:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int subSize = 100;
//struct to store nameInfo
struct nameInfo
{
string fName;
char middleInitial;
string lName;
};
//struct to store playerInfo
struct playerInfo
{
nameInfo name;
string postion;
int goals;
int penalties;
int jersey;
};
int getData(playerInfo matrix[]);
void displayData(playerInfo matrix[], int arraySize);
int main()
{
playerInfo p;
playerInfo playerArray[subSize];
int arraySize;
int userSelection;
string searchTerm;
arraySize = getData(playerArray);
cout << arraySize << " records found." << endl << endl;
displayData(playerArray, arraySize); //call to display all data
cout << endl;
return 0;
}
//function to read the data into the array
int getData(playerInfo matrix[])
{
ifstream infile;
string fileName;
int i = 0; //counter to hold array row length
int k = 0; //counter for file input
int x = 0; //counter for user input
cout << "Enter the file name (e.g. soccer-1.txt): ";
getline(cin, fileName);
cout << endl;
infile.open(fileName.c_str());
//checks if file exists
//ask the user again for the name of another file
//loop returns -1 after 3 failed attempts to enter a file
while (!infile)
{
k++;
cout << "After attempt " << k
<< " input file not opened." << endl;
cout << "Attempt " << k + 1 << ", enter the file name (e.g. soccer.txt): ";
getline(cin, fileName);
cout << endl;
infile.open(fileName.c_str());
cout << endl;
if (k == 2) //terminate program at 2 because entered validation loop
{ //after first attempt
cout << "Terminating program.";
return -1;
}
}
while (!infile.eof())
{
infile >> matrix[i].name.fName >> matrix[i].name.middleInitial
>> matrix[i].name.lName >> matrix[i].postion
>> matrix[i].goals >> matrix[i].penalties
>> matrix[i].jersey;
i++; //holds size of array
}
infile.close();
return i;
}
void displayData(playerInfo matrix[], int arraySize)
{
for (int y = 0; y < arraySize; y++)
{
//display format:
//Duckey.(E)Donald:8 2 21 – forward
cout << matrix[y].name.fName
<< ".(" << matrix[y].name.middleInitial << ")"
<< matrix[y].name.lName << ":" << matrix[y].goals << " "
<< matrix[y].penalties << " " << matrix[y].jersey
<< " - " << matrix[y].postion << endl;
}
}
OK, this is where you can apply a change:
while (!infile.eof()) {
infile >> matrix[i].name.fName >> matrix[i].name.middleInitial >>
matrix[i].name.lName >> matrix[i].postion >> matrix[i].goals >>
matrix[i].penalties >> matrix[i].jersey;
i++; // holds size of array
}
Read to a string, or a set of strings, instead of straight to the container. That way you can check they're valid (i.e. not blank) before copying to the matrix container.

While Loop with LCV of cin won't exit in C++

This is hw. I have asked my professor why the following code won't exit the while loop, and he/she couldn't tell me. My understanding is that once the input stream has no more values to read, the cin will return a value of false, and should cause the while loop to exit. Mine does not. It seems to keep read the input values (a set of integers) process through the loop, then wait for more input. Can anyone tell me why? Below is the code.
# include <iostream>
using namespace std;
int main()
{
int iEvenSum = 0;
int iOddSum = 0;
int iNum;
// prompt user
cout << "Input any set of integers, separated by a space:\n";
cin >> iNum;
cout << "You input: ";
while (cin)
{
cout << iNum << " ";
if (iNum % 2 == 0)
iEvenSum = iEvenSum + iNum;
else
iOddSum = iOddSum + iNum;
cin >> iNum;
}
cout << "\n\nThe sum of Even numbers is " << iEvenSum << "." << endl;
cout << "The sum of Odd numbers is " << iOddSum << "." << endl;
return 0;
}
while(cin) remains true as long as the cin stream is ok and becomes false if cin encounters an end of file character or an error.
In your case, while(cin) will keep on reading the numbers until it encounters an EOF character or an error. Type Ctrl-D when you don't have any more input numbers and it should quit the while loop

File pointer movement for getline

I have got an input file with following data
2
100
2
10 90
150
3
70 10 80
Now, I am able to read till 4th line ( 10 90) but when reading 5th line(150), the file pointer seems to be stuck at 4th line. I have tried infile.clear() just incase. How do I make sure that file pointer is moving correctly or position it at next line? Appreciate your feedback.
-Amit
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
int main(void) {
int cases;
int total_credit=0;
int list_size=0;
string list_price;
//Read file "filename".
ifstream infile;
infile.open("A-large-practice.in",ifstream::in);
if(!infile.is_open()) {
cout << "\n The file cannot be opened" << endl;
return 1;
}
else {
cout<<"Reading from the file"<<endl;
infile >> cases;
cout << "Total Cases = " << cases << endl;
int j=0;
while (infile.good() && j < cases) {
total_credit=0;
list_size=0;
infile >> total_credit;
infile >> list_size;
cout << "Total Credit = " << total_credit << endl;
cout << "List Size = " << list_size << endl;
//cout << "Sum of total_credit and list_size" << sum_test << endl;
int array[list_size];
int i =0;
while(i < list_size) {
istringstream stream1;
string s;
getline(infile,s,' ');
stream1.str(s);
stream1 >> array[i];
//cout << "Here's what in file = " << s <<endl;
//array[i]=s;
i++;
}
cout << "List Price = " << array[0] << " Next = " << array[1] << endl;
int sum = array[0] + array[1];
cout << "Sum Total = " << sum << endl;
cout <<"Testing" << endl;
j++;
}
}
return 0;
}
The problem is that you're using ' ' (space) as your "line terminator" for getline. So when you're reading the numbers on line 4 into the string s, the first one will be "10" and the second will be "90\n150\n3\n70" -- that is, everything up to the next space. This is almost certinaly not what you want and is leading to your confusion about where you are in the file. The next number you read will be 10, leading you to think you're on line 4 when in fact you're on line 7.
edit
The easiest way to fix this is probably to not use getline at all and just read ints directly from the input:
while (i < list_size)
infile >> array[i++];
This ignores the newlines altogether, so the input might as well be all on one line or split between lines randomly, but as you have an initial number that tells you how many numbers to read, that's just fine.

User input(cin) - Default value

I can't figure out how to use a "default value" when asking the user for input. I want the user to be able to just press Enter and get the default value. Consider the following piece of code, can you help me?
int number;
cout << "Please give a number [default = 20]: ";
cin >> number;
if(???) {
// The user hasn't given any input, he/she has just
// pressed Enter
number = 20;
}
while(!cin) {
// Error handling goes here
// ...
}
cout << "The number is: " << number << endl;
Use std::getline to read a line of text from std::cin. If the line is empty, use your default value. Otherwise, use a std::istringstream to convert the given string to a number. If this conversion fails, the default value will be used.
Here's a sample program:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
std::cout << "Please give a number [default = 20]: ";
int number = 20;
std::string input;
std::getline( std::cin, input );
if ( !input.empty() ) {
std::istringstream stream( input );
stream >> number;
}
std::cout << number;
}
This works as an alternative to the accepted answer. I would say std::getline is a bit on the overkill side.
#include <iostream>
int main() {
int number = 0;
if (std::cin.peek() == '\n') { //check if next character is newline
number = 20; //and assign the default
} else if (!(std::cin >> number)) { //be sure to handle invalid input
std::cout << "Invalid input.\n";
//error handling
}
std::cout << "Number: " << number << '\n';
}
Here's a live sample with three different runs and inputs.
if(!cin)
cout << "No number was given.";
else
cout << "Number " << cin << " was given.";
I'd be tempted to read the line as a string using getline() and then you've (arguably) more control over the conversion process:
int number(20);
string numStr;
cout << "Please give a number [default = " << number << "]: ";
getline(cin, numStr);
number = ( numStr.empty() ) ? number : strtol( numStr.c_str(), NULL, 0);
cout << number << endl;