I found a way to read the data into my array structs but i cannot control how many it reads. It will read all 14 entries in the input file but after it has read the 14 it continues for a couple lines then stops. However, if i place the code to read data inside any loop whether while or for, it starts printing huge numbers instead of what is contained in the file. Does anyone know why this happens? Is there a way around it
Input file looks as follows( exclude the dot):
There are 14 sets of data in the file. So, as shown below, set 1 would include georgia 76.4 10, then north carolina 95.5 20, and so on till 14 sets.
Data inside input file looks like this:
georgia
76.4 10
north carolina
95.5 20
and so on.
Need to print data to the screen like:
georgia 76.4 10
north carolina 95.5 20
etc.
The problem lies in my code were i attempt and horribly fail to read into the input file.
#include <iostream>
#include <fstream>
#include <cstdlib>
struct ATdata
{
string state;
double miles;
int shelters;
};
int readData( ifstream& input, struct ATdata data[] );
int main()
{
ifstream input;
char filename[256];
ATdata data[14];
int i;
cout << "Enter input file name: ";
cin >> filename;
input.open( filename );
if ( input.fail() )
{
cout << "Input file does not exist." << endl;
exit(1);
}
readData( input, data );
cout << i << endl;
return(0);
}
int readData( ifstream& input, struct ATdata data[] )
{
int i, j;
getline( input, data[i].state, '\t' );
input.ignore( 14, '\n' );
input >> data[i].miles;
input.ignore( 1, ' ' );
input >> data[i].shelters;
for ( j = 0; j < 14; j++ )
{
cout << data[j].state << data[j].miles << data[j].shelters << endl;
}
}
I apologize for all the info trying to be as clear as can be as to not look more idiotic.
Thank you have a nice day.
getline() takes an ostream& and a string. Since your types are not string, it gives you an error. I recommend reading in your input like this:
for (int i = 0; i < 14; i++ )
{
input >> data[i].state >> data[i].miles >> data[i].shelters;
}
BTW, your state is a char, that's 1 character. Make it an std::string.
The best way to get a whole line is to use std::getline. However, if you try to mix unformatted input with formatted input then it gets a bit tricky. You need lots of ignore calls and other guff. I think it is always clearer to read a whole line at a time, and then use a stringstream to parse that line.
Try this:
size_t readData( ifstream& input, struct ATdata data[], size_t max_items )
{
size_t i;
for ( i = 0; i < max_items; )
{
ATdata item;
getline(input, item.state);
string line_2;
if ( ! getline(input, line_2) )
break;
istringstream iss(line_2);
if ( ! (iss >> item.miles >> item.shelters) )
{
// skip malformed entry (or you could abort instead)
continue;
}
data[i++] = item;
}
return i;
}
Call it with:
size_t num_items = readData(input, data, sizeof data / sizeof data[0]);
Related
i have a question.
I have a file in format like this:
A B
C D
E F
X Y
X2 Y2
X3 Y3
I know how to assign A,B,C,D,E,F,X,Y (each file i check have this data) but sometimes i have more data like X2 Y2, X3, Y3 and i want to assing these also (without previous knowledge about how many of these are in the file).
Actually my code looks like this:
reading >> a >> b >> c >> d >> e >> f >> x >> y;
Could You help me? Thank You
This solution with vectors might solve the problem:
#include <vector>
#include <string>
#include <iterator>
#include <iostream>
#include <fstream>
using namespace std;
void getItems(vector<string>& v, string path)
{
ifstream is(path.c_str());
istream_iterator<string> start(is), end;
vector<string> items(start, end);
v = items;
}
int main()
{
vector<string> v;
getItems(v, "C:\test.txt");
vector<string>::iterator it;
for (it = v.begin(); it != v.end(); it++)
cout << *it << endl;
return 0;
}
Note: here i am assuming that your file is in C:\test.txt
You can input all of them as a string. Give the header as #input and use gets() function to input the entire input. Then work on the string. You can differentiate between the numbers by neglecting space(" ") and new lines ("\n").
Hope this helps!
You can use 2D vector:
Input:
1 2 3
4 5
6
7 8 9
Code:
int val;
string line;
ifstream myfile ("example.txt");
vector<vector<int> > LIST;
if (myfile.is_open())
{
while ( getline(myfile,line) )
{
vector<int> v;
istringstream IS(line);
while( IS >> val)
{
v.push_back(val);
}
LIST.push_back(v);
}
myfile.close();
}
for(int i=0; i<LIST.size(); i++)
{
for(int j=0; j<LIST[i].size(); j++)
{
cout << LIST[i][j] << " ";
}
cout << endl;
}
Output:
1 2 3
4 5
6
7 8 9
In the case where you don't know how much data is in the file, it is worth to use a
WHILE loop with the condition that you perform the while loop until it reaches the end of the file.
Something like this (ensure you include: iostream, fstream, and string):
int main () {
string line;
ifstream thefile ("test.txt");
if (thefile.is_open())
{
while (thefile.good() )
{
getline (thefile, line);
}
thefile.close();
}
else
{
cout << "Unable to open\n";
}
return 0;
}
If I understood you well you want to be sure that all lines in the file must be read.
With the following code I solved the problem for me:
std::ifstream file_reading( filename_path_.c_str(), std::ios::in );
if( file_reading ) {
std::string buffer;
unsigned int line_counter = 0;
while( std::getline( file_reading, buffer ) ) {
std::istringstream istr;
istr.str( buffer );
if( buffer.empty() )
break;
istr >> x_array[local_counter] >> y_array[local_counter];
line_counter++;
}
}
using getline and a while loop you all get all lines in the file and store them in a std::vector which is resizable.
The instruction break will quit if no more data are found in the next line.
Good morning all.
I'm starting to learn c++ and i'm trying to make a prog that converts from one currency to another.
I made a text file "currency.txt" where i have all currencies, one after another, each with 4 lines:
Country, Currency description, Currency code, Exchange rate.
So far i made the following code:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
struct currency {
string country;
string coin;
string code;
double rate;
};
int count_lines ( ifstream &myfile ){
string line;
int lines = 0;
if ( myfile.is_open() ){
while ( getline( myfile, line ) ){
++lines;
}
} else cout << "error";
myfile.seekg (0, ios::beg);
return lines;
}
void read_coins ( currency coins[], ifstream &myfile, int lines) {
string line;
if ( myfile.is_open() ){
for ( int n=0; n<lines; n++){
getline( myfile, line );
coins[n].country = line;
getline( myfile, line );
coins[n].coin = line;
getline( myfile, line );
coins[n].code = line;
getline( myfile, line );
stringstream(line) >> coins[n].rate;
}
} else cout << "error";
myfile.seekg (0, ios::beg);
}
int main(){
ifstream myfile ( "currency.txt" );
int lines;
lines = count_lines ( myfile )/4;
currency coins [lines];
read_coins (coins, myfile, lines);
for (int n=0; n<lines; n++){
cout << coins[n].country << '\t';
cout << coins[n].coin << '\t';
cout << coins[n].code << '\t';
cout << coins[n].rate << endl;
}
myfile.close ();
return 0;
}
But it's just not working. If i open the file inside all of the functions it works, but not like this.
I know there must be a problem for sure but i just can't figure it ou yet.
And i have another problem: the exchage rates have 10 decimal digits, but when i put it in my coins[n].rate, it comes only with 5 ou 6 decimal digits. Is there anyway to get all 10?
Can somebody help me please?
Thanks
If you're not using C++11, seekg doesn't reset the end-of-file state of the file.
Add myfile.clear() before seeking to the beginning.
The output of floating point numbers depends on the current precision of the stream.
The default is six (6).
Add
#include <iomanip>
and
std::cout << std::setprecision(10);
before output.
(But remember that floating-point is inexact in itself, so you won't necessarily get exactly the same number as in the file - only the closest one possible.)
I'm writing a program that prompts the user for:
Size of array
Values to be put into the array
First part is fine, I create a dynamically allocated array (required) and make it the size the user wants.
I'm stuck on the next part. The user is expected to enter in a series of ints separated by commas such as: 1,2,3,4,5
How do I take in those ints and put them into my dynamically allocated array? I read that by default cin takes in integers separated by whitespace, can I change this to commas?
Please explain in the simplest manner possible, I am a beginner to programming (sorry!)
EDIT: TY so much for all the answers. Problem is we haven't covered vectors...is there a method only using the dynamically allocated array I have?
so far my function looks like this. I made a default array in main. I plan to pass it to this function, make the new array, fill it, and update the pointer to point to the new array.
int *fill (int *&array, int *limit) {
cout << "What is the desired array size?: ";
while ( !(cin >> *limit) || *limit < 0 ) {
cout << " Invalid entry. Please enter a positive integer: ";
cin.clear();
cin.ignore (1000, 10);
}
int *newarr;
newarr = new int[*limit]
//I'm stuck here
}
All of the existing answers are excellent, but all are specific to your particular task. Ergo, I wrote a general touch of code that allows input of comma separated values in a standard way:
template<class T, char sep=','>
struct comma_sep { //type used for temporary input
T t; //where data is temporarily read to
operator const T&() const {return t;} //acts like an int in most cases
};
template<class T, char sep>
std::istream& operator>>(std::istream& in, comma_sep<T,sep>& t)
{
if (!(in >> t.t)) //if we failed to read the int
return in; //return failure state
if (in.peek()==sep) //if next character is a comma
in.ignore(); //extract it from the stream and we're done
else //if the next character is anything else
in.clear(); //clear the EOF state, read was successful
return in; //return
}
Sample usage http://coliru.stacked-crooked.com/a/a345232cd5381bd2:
typedef std::istream_iterator<comma_sep<int>> istrit; //iterators from the stream
std::vector<int> vec{istrit(in), istrit()}; //construct the vector from two iterators
Since you're a beginner, this code might be too much for you now, but I figured I'd post this for completeness.
A priori, you should want to check that the comma is there, and
declare an error if it's not. For this reason, I'd handle the
first number separately:
std::vector<int> dest;
int value;
std::cin >> value;
if ( std::cin ) {
dest.push_back( value );
char separator;
while ( std::cin >> separator >> value && separator == ',' ) {
dest.push_back( value );
}
}
if ( !std::cin.eof() ) {
std::cerr << "format error in input" << std::endl;
}
Note that you don't have to ask for the size first. The array
(std::vector) will automatically extend itself as much as
needed, provided the memory is available.
Finally: in a real life example, you'd probably want to read
line by line, in order to output a line number in case of
a format error, and to recover from such an error and continue.
This is a bit more complicated, especially if you want to be
able to accept the separator before or after the newline
character.
You can use getline() method as below:
#include <vector>
#include <string>
#include <sstream>
int main()
{
std::string input_str;
std::vector<int> vect;
std::getline( std::cin, input_str );
std::stringstream ss(str);
int i;
while (ss >> i)
{
vect.push_back(i);
if (ss.peek() == ',')
ss.ignore();
}
}
The code is taken and processed from this answer.
Victor's answer works but does more than is necessary. You can just directly call ignore() on cin to skip the commas in the input stream.
What this code does is read in an integer for the size of the input array, reserve space in a vector of ints for that number of elements, then loop up to the number of elements specified alternately reading an integer from standard input and skipping separating commas (the call to cin.ignore()). Once it has read the requested number of elements, it prints them out and exits.
#include <iostream>
#include <iterator>
#include <limits>
#include <vector>
using namespace std;
int main() {
vector<int> vals;
int i;
cin >> i;
vals.reserve(i);
for (size_t j = 0; j != vals.capacity(); ++j) {
cin >> i;
vals.push_back(i);
cin.ignore(numeric_limits<streamsize>::max(), ',');
}
copy(begin(vals), end(vals), ostream_iterator<int>(cout, ", "));
cout << endl;
}
#include <iostream>
using namespace std;
int main() {
int x,i=0;
char y; //to store commas
int arr[50];
while(!cin.eof()){
cin>>x>>y;
arr[i]=x;
i++;
}
for(int j=0;j<i;j++)
cout<<arr[j]; //array contains only the integer part
return 0;
}
The code can be simplified a bit with new std::stoi function in C+11. It takes care of spaces in the input when converting and throws an exception only when a particular token has started with non-numeric character. This code will thus accept input
" 12de, 32, 34 45, 45 , 23xp,"
easily but reject
" de12, 32, 34 45, 45 , 23xp,"
One problem is still there as you can see that in first case it will display " 12, 32, 34, 45, 23, " at the end where it has truncated "34 45" to 34. A special case may be added to handle this as error or ignore white space in the middle of token.
wchar_t in;
std::wstring seq;
std::vector<int> input;
std::wcout << L"Enter values : ";
while (std::wcin >> std::noskipws >> in)
{
if (L'\n' == in || (L',' == in))
{
if (!seq.empty()){
try{
input.push_back(std::stoi(seq));
}catch (std::exception e){
std::wcout << L"Bad input" << std::endl;
}
seq.clear();
}
if (L'\n' == in) break;
else continue;
}
seq.push_back(in);
}
std::wcout << L"Values entered : ";
std::copy(begin(input), end(input), std::ostream_iterator<int, wchar_t>(std::wcout, L", "));
std::cout << std::endl;
#include<bits/stdc++.h>
using namespace std;
int a[1000];
int main(){
string s;
cin>>s;
int i=0;
istringstream d(s);
string b;
while(getline(d,b,',')){
a[i]= stoi(b);
i++;
}
for(int j=0;j<i;j++){
cout<<a[j]<<" ";
}
}
This code works nicely for C++ 11 onwards, its simple and i have used stringstreams and the getline and stoi functions
You can use scanf instead of cin and put comma beside data type symbol
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[10],sum=0;
cout<<"enter five numbers";
for(int i=0;i<3;i++){
scanf("%d,",&a[i]);
sum=sum+a[i];
}
cout<<sum;
}
First, take the input as a string, then parse the string and store it in a vector, you will get your integers.
vector<int> v;
string str;
cin >> str;
stringstream ss(str);
for(int i;ss>>i;){
v.push_back(i);
if(ss.peek() == ','){
ss.ignore();
}
}
for(auto &i:v){
cout << i << " ";
}
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I wrote a program that reads to one file, writes to another and prints to the screen. In other words, it is supposed to do three things (i.e. read, write and print).
The program is also supposed to count the number of records in a file named "Chap_11_employee_data.txt". It is just displaying the following, however.
**Total Records 0**
The End
When it writes to a file, it also displays weird numbers such as -858993460. I have tried almost everything, which led me to register an account here. My code is listed below as well as the file I am trying to read from and the file I am trying to write to.
Thank you very much for your guy's time.
Code:
#include <iostream>
#include <fstream>
#include <iomanip>
using std::cin;
using std::cout;
using std::endl;
using std::setw;
using std::ios;
using std::ifstream;
using std::ofstream;
const int EMPLOYEES = 20;
const int MAX = 21;
int ReadData( ifstream &inFile, ofstream &outFile, char name[][MAX], int age[] );
void WriteOutputFile( ofstream &outFile, char name[ ][MAX], int age[ ], int counter );
void PrintTotalsAndSummary( ofstream &out, int totalRecords );
int main()
{
char name[EMPLOYEES][MAX];
int age[EMPLOYEES];
int record_counter(0);
ifstream inFile;
ofstream outFile( "Chap_11_Report.txt" );
inFile.open( "Chap_11_employee_data.txt" );
if ( inFile.is_open() )
{
record_counter = ReadData( inFile, outFile, name, age );
inFile.close();
if( outFile.is_open() )
{
WriteOutputFile( outFile, name, age, record_counter );
PrintTotalsAndSummary( outFile, record_counter );
outFile.close();
}
else
{
cout << "Trouble Opening File";
cout << "\n\n\t\t ** About to EXIT NOW! ** ";
}
}
else
{
cout << "Trouble Opening File";
cout << "\n\n\t\t ** About to EXIT NOW! ** ";
}
return 0;
}
int ReadData( ifstream & inFile, ofstream & outFile, char name[][MAX], int age[] )
{
int counter = 0;
inFile >> name[counter] >> age[counter]; // Priming Read
while ( !inFile.eof() )
{
cout << setiosflags( ios::left ) << setw( 25 )
<< name[counter] << resetiosflags( ios::left )
<< setw( 4 ) << age [counter] << endl;
counter++;
inFile >> name[counter] >> age[counter];
}
return counter;
}
void WriteOutputFile( ofstream &outFile, char name[][MAX], int age[], int counter)
{
outFile << " Here is the Output File" << endl;
for ( int r = 0; r <= counter; r++ )
{
outFile << setiosflags( ios::left ) << setw( 25 )
<< name[r] << setw( 4 )
<< resetiosflags( ios::left ) << age[r]
<< endl;
}
}
void PrintTotalsAndSummary( ofstream &outFile, int totalRecords )
{
// To screen
cout << "\n\n\t** Total Records: " << totalRecords << " **\n"
<< "\t\t The End \n";
// To file
outFile << "\n\n\t** Total Records: " << totalRecords << " **\n"
<< "\t\t The End \n";
}
File I am reading from (Chap_11_employee_data.txt):
"Alexis","Blough",1-1921,"CEO"
"Bill","Pay",1-7711,"Accounting"
"Willy","Makit",4-1595,"Sales"
"Marie","Murray",1-4986,"MIS"
"Cal","Caldwellowinski",5-0911,"MIS"
"Jamie","Johanasola",5-9999,"Marketing"
File I am writing to (Chap_11_Report.txt):
Here is the Output File
-858993460
** Total Records: 0 **
The End
Here is your input statement...
inFile >> name[counter] >> age[counter];
And the output file format is this...
"Alexis","Blough",1-1921,"CEO"
"Bill","Pay",1-7711,"Accounting"
The input statement reads the name till it encounters a space or an endline character. So in the first case it would read the whole line as there is no space in between the words. Next on, it would take input of age which is an int. It would start taking input of age from the second line, which is full of characters from the beginning. A character in integer stream is undefined behavior. That is the reason you are getting wrong results.
The problem is the mismatch of the file format with the input format. Try to synchronise them.
For reading white spaces as well, use inFile.get() or inFile.getline().
Your read has one problem:
while ( !inFile.eof() )
The problem is that the stream can go bad in a way that is not eof(). If this happens you will enter an infinite loop. So really you should check for bad().
while ( !inFile.bad() ) // check for eof and other error cases.
Normally this test is completely wrong. But you have managed to get around this by doing the following:
<Get Input>
while ( !inFile.bad() )
{
< DO WORK>
<Get Input>
}
The same affect can be achieved (in a more idiomatic way) with:
while ( <Get Input> )
{
< DO WORK>
}
The read (using >> or std::getline()) returns a reference to a stream. When this is used in a boolean context (like a while loop test) it is converted to bool (actually bool like for the language lawyers) that represents the state of the stream which is obtained by using bad. Thus the loop body is only entered if the read actually worked.
The input stream operators are very simplistic and any failure on input will set an internal failure bit inside the stream causing them to sieze up and not provide further input until the failure bit is reset.
Given the input you have provided this will fail:
inFile >> name[counter] >> age[counter];
The variable name[counter] represents a C-String and the the input operator >> when applied to a C-String will read until the first white space character (in this case newline). So here we assign:
"Alexis","Blough",1-1921,"CEO"
to this value.
We then try and continue reading using age[counter] an integer value. This tries to read an integer from:
"Bill","Pay",1-7711,"Accounting"
This will fail as the character '"' is not a digit.
What you should be doing is:
std::string name;
std::getline(inFile, name, ','); // Read upto the ',' character (and discard it)
// You may want to remove the quotes here.
int age = 0;
// Age is not defined in the input so set it manually.
std::string line;
std::getline(inFile, line); // Read and ignore the rest of the line.
I'm trying to collect information from a textfile which contains names of organisations (without spaces) and floating integers. I want to store this information in an array structure.
The problem I'm having so far is collecting the information. Here is a sample of the textfile:
CBA 12.3 4.5 7.5 2.9 4.1
TLS 3.9 1 8.6 12.8 4.9
I can have up to 128 different numbers for each organisation, and up to 200 organisations in the textfile.
This is what my structure looks like so far:
struct callCentre
{
char name[256];
float data[20];
};
My main:
int main()
{
callCentre aCentre[10];
getdata(aCentre);
calcdata(aCentre);
printdata(aCentre);
return 0;
}
And the getdata function:
void getdata(callCentre aCentre[])
{
ifstream ins;
char dataset[20];
cout << "Enter the name of the data file: ";
cin >> dataset;
ins.open(dataset);
if(ins.good())
{
while(ins.good())
{
ins >> aCentre[c].name;
for(int i = 0; i < MAX; i++)
{
ins >> aCentre[c].data[i];
if(ins == '\n')
break;
}
c++;
}
}
else
{
cout << "Data files couldnt be found." << endl;
}
ins.close();
}
What I'm trying to achieve in my getdata function is this: store the organisation name first into the structure, then read each float into the data array until the program detects a newline byte. However, so far my check for the newline byte isn't working.
Assume that variables c and MAX are already defined.
How should I go about this properly?
The >> operator treats whitespace as a delimiter, and that includes newlines, so it just eats those and you never see them.
You need to read lines and then chop the lines up. The following bit of hackery illustrates the basic idea:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
string line;
while( getline( cin, line ) ) {
istringstream is( line );
string cs;
is >> cs;
double vals[10];
int i = 0;
while( is >> vals[i] ) {
i++;
}
cout << "CS: " << cs;
for ( int j = 0; j < i; j++ ) {
cout << " " << vals[j];
}
cout << endl;
}
}
char byte = ins.peek();
Or
if(ins.peek() == '\n') break;
(Edit): You'll want to also check for an eof after your peek(), because some files may not have a ending newline.
I'd like to point out that you might want to consider using a vector<callCentre> instead of a static array. If your input file length exceeds the capacity of the array, you'll walk all over the stack.
I would read the file, one line after another and parse each line individually for the values:
std::string line;
while (std::getline(ins, line)) {
std::istringstream sline(line);
sline >> aCentre[c].name;
int i = 0;
while (sline >> aCentre[c].data[i])
i++;
c++;
}