Importing data into array in C++ - c++

I have a school assignment that I feel should be relatively simply, but I've spent like 5 hours on this part now and can't figure out what I need to do. I'm trying to import 3 integers from each line in a file into 3 different arrays. Each line has an ID number, store number, and quantity ordered. I want to store them in 3 arrays, where the same index would address the integers taken from the same line in the text file.
Recommendations I'm getting from various other places say to use stringstream or a vector, neither of which I have used before and I assume are not needed at this point in the class. My code currently is:
bool loadArrays(const char* fileName, long idArray[], int storeArray[], int qtyArray[], int &count, int maxCells)
{
count = 0;
ifstream fileIn;
fileIn.open("data.txt");
int x = 0;
while ((fileIn.get()) && (x < maxCells))
{
fileIn >> idArray[x] >> storeArray[x] >> qtyArray[x];
count++;
x++;
std::cout << idArray[x] << endl;
}
fileIn.close();
return true;
}
It loops through fine. I'm passing the count variable by reference and printing it out after I run this function it gives me 20. However the cout << idArray[x] line above just displays 0 each time like I'm not importing data correctly?
I'm probably importing the data wrong, which is fine for now, but even so shouldn't I get at least SOMETHING in idArray[0]? The first line of data.txt is '16724 27 134' so idArray[0] should = 16724, yes? I thought the >> will import integers until it meets whitespace, so the numbers being spaced apart like above means that line should go into 3 arrays per line right?
I should point out I'm taking this course online for now to see how I like programming and my teacher effectively doesn't speak english so I'm kind of on my own learning this for now.

You're reading into position x of your array, and printing out position x + 1 (x++ between those lines), which obviously is still empty.
Try to print before incrementing x, like so:
fileIn >> idArray[x] >> storeArray[x] >> qtyArray[x];
std::cout << idArray[x] << endl;
count++;
x++;

You're calling fileIn.get() without using its return value. The get() method extracts on character from the stream and returns it, it doesn't check whether there's still a character in the stream.
You should put the actual input operation inside the loop parameters as it is a much better way of checking if the stream performed a successful read:
while ((fileIn >> idArray[x] >> storeArray[x] >> qtyArray[x]) && (x < maxCells))
Also, as pointed out in the comments, you're incrementing x before printing idArray[x], so it will skip the first index. Put x++ after the insertion.

Related

I'm Having Trouble Skipping Certain Characters from an Input Text File (C++)

(I apologize that this is so low level compared to most of the questions I have seen on this website, but I have run out of ideas and I do not know who else to ask.)
I am working on a school project that requires me to read basketball statistics from a file named in06.txt. The file in06.txt looks exactly as follows:
5
P 17 24 9 31 28
R 4 5 1 10 7
A 9 2 3 6 8
S 3 4 0 5 4
I am required to read and store the first number, 5, into a variable called "games." From there, I must read the numbers from the second line and determine the high, the low, and the average. I must do the same thing for lines 3, 4, and 5. (FYI, the letters P, R, A, and S are there to indicate "Points," "Rebounds," "Assists," and "Steals.")
Since I only have been learning about programming for a few weeks, I do not want to overwhelm myself by jumping right into dealing with every aspect of the project. So, I am first working on determining the average from each line. My plan is to keep a running total of each line and then divide the running total by the number of games, which is 5 in this case.
This is my code:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
int games;
int points_high, points_low, points_total;
int rebounds_high, rebounds_low, rebounds_total;
int assists_high, assists_low, assists_total;
int steals_high, steals_low, steals_total;
double points_average, rebounds_average, assists_average, steals_average;
ifstream fin;
ofstream fout;
fin.open("in06.txt");
if( fin.fail() ) {
cout << "\nInput file opening failed.\n";
exit(1);
}
else
cout << "\nInput file was read successfully.\n";
int tempint1, tempint2, tempint3, tempint4;
char tempchar;
fin >> games;
fin.get(tempchar); // Takes the endl; from the text file.
fin.get(tempchar); // Takes the character P from the text file.
while( fin >> tempint1 ) {
points_total += tempint1;
}
fin.get(tempchar); // Takes the endl; from the text file.
fin.get(tempchar); // Takes the character R from the text file.
while( fin >> tempint2 ) {
rebounds_total += tempint2;
}
fin.get(tempchar); // Takes the endl; from the text file.
fin.get(tempchar); // Takes the character A from the text file.
while( fin >> tempint3 ) {
assists_total += tempint3;
}
fin.get(tempchar); // Takes the endl; from the text file.
fin.get(tempchar); // Takes the character S from the text file.
while( fin >> tempint4 ) {
steals_total += tempint4;
}
cout << "The total number of games is " << games << endl;
cout << "The value of total points is " << points_total << endl;
cout << "The value of total rebounds is " << rebounds_total << endl;
cout << "The value of total assists is " << assists_total << endl;
cout << "The value of total steals is " << steals_total << endl;
return 0;
}
And this is the (incorrect) output:
Input file was read successfully.
The total number of games is 5
The value of total points is 111
The value of total rebounds is 134522076
The value of total assists is 134515888
The value of total steals is 673677934
I have been reading about file input in my textbook for hours, hoping that I will find something that will indicate why my program is outputting the incorrect values. However, I have found nothing. I have also researched similar problems on this forum as well as other forums, but the solutions use methods that I have not yet learned about and thus, my teacher would not allow them in my project code. Some of the methods I saw were arrays and the getline function. We have not yet learned about either.
Note: My teacher does not want us to store every integer from the input file. He wants us to open the file a single time and store the number of games, and then use loops and if statements for determining the high, average, and low numbers from each line.
If anyone could help me out, I would GREATLY appreciate it!
Thanks!
You have all these variables declared:
int games;
int points_high, points_low, points_total;
int rebounds_high, rebounds_low, rebounds_total;
int assists_high, assists_low, assists_total;
int steals_high, steals_low, steals_total;
double points_average, rebounds_average, assists_average, steals_average;
And then you increment them:
points_total += tempint1;
Those variables were never initialzed to a known value (0), so they have garbage in them. You need to initialize them.
Besides what OldProgrammer said, you've approached the reading of integers incorrectly. A loop like this
while( fin >> tempint2 ) {
rebounds_total += tempint2;
}
will stop when an error occurs. That is, either it reaches EOF or the extraction encounters data that cannot be formatted as an integer - or in other words, good() returns false. It does not, as you seem to think, stop reading at the end of a line. Once an error flag is set, all further extractions will fail until you clear the flags. In your case, a loop starts reading after P, extracts five intergers, but then it encounters the R from the next line and errors out.
Change this to a loop that reads a fixed number of integers or alternatively, read a whole line using std::getline into a std::string, put it into a std::stringstream and read from there.
In any case, learn to write robust code. Check for success of extractions and count how many elements you get.
An example of a loop that reads at most 5 integers:
int i;
int counter = 0;
while (counter < 5 && file >> i) {
++counter;
// do something with i
}
if (counter < 5) {
// hm, got less than 5 ints...
}

C++: Reading txt file through fstream

I have a .txt file that looks like this:
Toy ball
1.25
DVD
20.00
Row Boat
1.00
The first line is the item, the second is the price, and it repeats for the next 2 items and so on. So my question is how can i take the first line and put it in a string, and the second line and put it in a float value? Here is the code i have, i am using structs.
const int TOTAL_ITEMS = 3;
for (int itemNumber = 0; itemNumber < TOTAL_ITEMS; itemNumber++) {
string line;
getline(inFile,line);
list[itemNumber].item = line;
float cost;
inFile >> cost;
list[itemNumber].price = cost;
}
I then print the list:
for (int itemNumber = 0; itemNumber < TOTAL_ITEMS; itemNumber++) {
cout << itemNumber << ": " << list[itemNumber].item << " " << list[itemNumber].price << endl;
Now this doesnt print what i want it to, the struct array only took in the first line and the first price and printed it out, but the others all said "0". Any help would be awesome. Thanks guys
The float input (by the way, just use double, less trouble) leaves a newline in the input buffer, which is consumed by the subsequent line input.
Instead, use getline for both lines.
Then use e.g. istringstream to convert the second line to ... double, just by "reading" from it in the same as you'd read from inFile.
In addition to that direct bug fix, you need to check the stream state of inFile, e.g. by calling its fail member function. When you use the stream object directly as a condition, its conversion to bool calls fail for for you, and negates the result so that the stream object itself denotes "not fail". Note that good is not the opposite of fail, and also note that a fail state is persistent and causes subsequent input operations to be ignored.
You need to check the stream state as you consume input. You can do that by checking the return value of getline() and operator>>:
if (!getline(inFile,line))
; // oops, error, do something
if (!(inFile >> cost))
; likewise
Once you do this you will find that your input is failing because you're reading things slightly incorrectly, but it shouldn't be hard to fix once you see where it's broken.

How to convert vector to string and convert back to vector

----------------- EDIT -----------------------
Based on juanchopanza's comment : I edit the title
Based on jrok's comment : I'm using ofstream to write, and ifstream to read.
I'm writing 2 programs, first program do the following tasks :
Has a vector of integers
convert it into array of string
write it in a file
The code of the first program :
vector<int> v = {10, 200, 3000, 40000};
int i;
stringstream sw;
string stringword;
cout << "Original vector = ";
for (i=0;i<v.size();i++)
{
cout << v.at(i) << " " ;
}
cout << endl;
for (i=0;i<v.size();i++)
{
sw << v[i];
}
stringword = sw.str();
cout << "Vector in array of string : "<< stringword << endl;
ofstream myfile;
myfile.open ("writtentext");
myfile << stringword;
myfile.close();
The output of the first program :
Original vector : 10 200 3000 40000
Vector in string : 10200300040000
Writing to File .....
second program will do the following tasks :
read the file
convert the array of string back into original vector
----------------- EDIT -----------------------
Now the writing and reading is fine, thanks to Shark and Jrok,I am using a comma as a separator. The output of first program :
Vector in string : 10,200,3000,40000,
Then I wrote the rest of 2nd program :
string stringword;
ifstream myfile;
myfile.open ("writtentext");
getline (myfile,stringword);
cout << "Read From File = " << stringword << endl;
cout << "Convert back to vector = " ;
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
But it can only convert and push back the first element, the rest is erased. Here is the output :
Read From File = 10,200,3000,40000,
Convert back to vector = 10
What did I do wrong? Thanks
The easiest thing would be to insert a space character as a separator when you're writing, as that's the default separator for operator>>
sw << v[i] << ' ';
Now you can read back into an int variable directly, formatted stream input will do the conversion for you automatically. Use vector's push_back method to add values to it as you go.
Yes, this question is over a year old, and probably completely irrelevant to the original asker, but Google led me here so it might lead others here too.
When posting, please post a complete minimal working example, having to add #include and main and stuff is time better spent helping. It's also important because of your very problem.
Why your second code isn't working is all in this block
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
istringstream (stringword) >> value interprets the data up to the comma as an integer, the first value, which is then stored.
stringword.find(',') gets you the 0-indexed position of the comma. A return value of 0 means that the character is the first character in the string, it does not tell you whether there is a comma in the string. In that case, the return value would be string::npos.
stringword.erase deletes that many characters from the start of the string. In this case, it deletes 10, making stringword ,200,3000,40000. This means that in the next iteration stringword.find(',') returns 0.
if (stringword.find(',')) does not behave as wished. if(0) casts the integer to a bool, where 0 is false and everything else is true. Therefore, it never enters the if-block again, as the next iterations will keep checking against this unchanged string.
And besides all that there's this:
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
it uses i. That was declared in a for loop, in a different scope.
The code you gave simply doesn't compile, even with the added main and includes. Heck, v isn't even defined in the second program.
It is however not enough, as the for condition stringword.length() is recalculated every loop. In this specific instance it works, because your integers get an extra digit each time, but let's say your input file is 1,2,3,4,:
The loop executes normally three times
The fourth time, stringword is 4, stringword.length() returns 2, but i is already valued 3, so i<stringword.length() is invalid, and the loop exits.
If you want to use the string's length as a condition, but edit the string during processing, store the value before editing. Even if you don't edit the string, this means less calls to length().
If you save length beforehand, in this new scenario that would be 8. However, after 4 loops string is already empty, and it executes the for loop some more times with no effect.
Instead, as we are editing the string to become empty, check for that.
All this together makes for radically different code altogether to make this work:
while (!stringword.empty())
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(',')+1);
}
for (int i = 0; i < v.size(); i++)
{
cout << v.at(i) << " " ;
}
A different way to solve this would have been to not try to find from the start, but from index i onwards, leaving a string of commas. But why stick to messy stuff if you can just do this.
And that's about it.

c++ read in array struct trouble

i am experiencing much trouble reading in files from input into an array struct. here is the code if someone can tell me what im doing wrong i can figure it out. the loop is supposed to be reading 2 strings, and 1 int, and skipping possible blank lines. but when i run it, it reads the first set and doesnt read nothing after that.
struct Instruments
{
string model;
string maker;
int year;
};
int main()
{
int size;
Instruments data[20];
int i =0;
ifstream fin;
fin.open("input.txt");
for (i=0; i<20; i++)
{
do{
getline(fin, data[size].model);
getline (fin, data[size].maker);
fin >> data[size].year;
size++;
}
while (data[size].model.length() > 0);
}
fin.close();
for(int i=0;i<size; i++)
{
cout << data[i].model << "model"<<endl;
cout << data[i].maker << "maker" << endl;
cout << data[i].year<< " year" << endl;
}
return 0;
}
There are multiple issues here:
Your first 'for' loop is using i as the loop counter but size as the array index.
After this call:
fin >> data[size].year
it will read to the end of the number and any whitespace that follows will form part of your next read, so if you are expecting to start the next record at the next line, do a blank getline() here too.
Aside from that.
Use vectors not arrays
Have a method to read from a stream into your struct, and if that succeeds, use push_back() to add it to your vector.
That doesn't necessarily mean you have to loop until the read fails, it may be that you know in advance how many you wish to read. But you should still do it this way.
size variable is not initialized. In C++, variables are not automatically initialized.
You must add:
int size = 0;
This is just a guess. In addition to the missing initialization of size, the following:
do{
.....
}
while (data[size].model.length() > 0);
looks also quite suspect to me: as soon as data[size].model has some content (which it does after the first read, this will evaluate to true and you probably have an infinite loop.
If you craft the for loop correctly, you don't need the do-while loop.

Error in outputting to a file in C++ that I can't find

Not as in "can't find the answer on stackoverflow", but as in "can't see what I'm doing wrong", big difference!
Anywho, the code is attached below. What it does is fairly basic, it takes in a user created text file, and spits out one that has been encrypted. In this case, the user tells it how many junk characters to put between each real character. (IE: if I wanted to encrypt the word "Hello" with 1 junk character, it would look like "9H(eal~l.o")
My problem is that for some reason, it isn't reading the input file correctly. I'm using the same setup to read in the file as I had done previously on decrypting, yet this time it's reading garbage characters, and when I tell it to output to file, it prints it on the screen instead, and it seems like nothing is being put in the output file (though it is being created, so that means I've done something correctly, point for me!
code:
string start;
char choice;
char letter;
int x;
int y;
int z;
char c;
string filename;
while(start == "enc")
{
x = 1;
y = 1;
cout << "How many garbage characters would you like between each correct character?: " ;
cin >> z;
cout << endl << "Please insert the name of the document you wish to encrypt, make sure you enter the name, and the file type (ie: filename.txt): " ;
cin >> filename;
ifstream infile(filename.c_str());
ofstream outfile("encrypted.txt", ios::out);
while(!infile.eof())
{
infile.get(letter);
while ((x - y) != z)
{
outfile << putchar(33 + rand() % 94);
x++;
}
while((x - y) == z)
{
outfile << letter;
y = 1;
x = 1;
}
}
outfile.close();
cout << endl << "Encryption complete...please return to directory of program, a new file named encrypted.txt will be there." << endl;
infile.close();
cout << "Do you wish to try again? Please press y then enter if yes (case sensitive).";
cin >> choice;
What I pasted above the start of the while loop are the declaration variables, this is part of a much larger code that not only will encrypt, but decrypt as well, I left the decryption part out as it works perfectly, it's this part I'm having an issue with.
Thanks in advance for the assist!
EDIT:: I'm using visual C++ express 2008, and it shoots back that there are no errors at all, nor any warnings.
IMPORTANT EDIT
It turns out it is outputting to the file! However, it is outputting numbers instead of ascii characters, and it is also outputting the garbage character for the letter it should be. When it goes back to the "infile.get(letter)", it doesn't get a new character. So right now it seems to be the issues are 2 fold:
1) Printing numbers instead of ascii characters.
2) Using garbage instead of the actual character it should be getting.
Question Answered
Found out the second part in the "Important Edit" ...it turns out if you name something test.txt...that means it is actually called test.txt.txt when you type it into a C++ program. Just goes to show it's the tiny, minute, simple details that cause any program to go pooey.
Thank you to George Shore. Your comment about the input file being in the wrong place is what gave me the idea to try the actual items name.
Thank you to everyone who helped with the answer!
Further to the previous answers, I believe it's because the file you wish to encrypt is not being found by the original code. Is it safe to assume that you're running the code from the IDE? If so, then the file that is to be encrypted has to be in the same directory as the source.
Also:
outfile << putchar(33 + rand() % 94);
seems to be the source of your garbage to the screen; the 'putchar' function echoes to the screen whilst returning the integer value of that character. What is then going to happen is that number will be output to the file, as opposed to the character.
Changing that block to something like:
while ((x - y) != z)
{
c = (33 + rand() % 94);
outfile << c;
x++;
}
should enable the code to run as you want it to.
Rather than doing this:
while (!infile.eof())
{
infile.get(letter);
if (infile.good())
{
Do this:
while (infile.get(letter))
{
This is the standard pattern for reading a file.
It gets a character and the resulting infile (that is returned by get) is then checked to see if it is still good by converting it to bool.
The line:
outfile << putchar(33 + rand() % 94);
Should probably be:
outfile << static_cast<char>(33 + rant() % 94);
putchar() prints to the standard output. But the return value (same as the input) goes to the outfile. To stop this just convert the value to char and send to outfile.
Is the use of 'y' necessary? It seems confusing and unnecessary to me. If I were implementing this, then I'd expect to use just 'x' and 'z'.
I'm also not sure about the 'while (!infile.eof())' condition; Pascal determines EOF ahead of time, but C++ can only tell you about EOF after attempting to read a character. However, this would only affect the end of the file, not the main body of the loop.
while (!infile.eof())
{
infile.get(letter);
if (infile.good())
{
for (int i = 0; i < z; i++)
outfile << putchar(33 + rand() % 94);
outfile << letter;
}
}
(Uncompiled code!).
Also, do not use this for security - it may help a little, but it certainly won't conceal the information from the determined.