Loading Files Results in Program Stop Working - c++

I was wondering if anyone could help me with my code (C++)? This is the function that will not work. When I run it, Windows pops up and says "This program has stopped working." Here is the code that will not run (it's a little long, but the program is proprietary and I appreciate any help):
void ClassName::loadGrades(){
string temp;
int count=0;
ifstream labErnIn("labGradesErn.txt");
if(labErnIn.is_open()){
count=0;
while(labErnIn.good()){
getline(labErnIn, temp);
float tempF = ::atof(temp.c_str());
labGradesErn[count] = tempF;
if(labGradesErn[count]==0 && count==0) labGradesErn[count]=-1;
count++;
}
labGradesErn[count-1]=-1;
labErnIn.close();
}
else{
cout << "Unable to open file labGradesErn.txt" << endl;
}
// I repeat this for three other sections, same code, different var names.
// From 'ifstream...' to 'Unable to open file'
}
All variables not declared in this function are declared elsewhere.
Thanks, I really appreciate any and all help!

If labGradesErn is a fixed array, you risk an array overrun sooner or later. If it is a std::vector, you should use push_back() to append elements, because increasing the index doesn't increase the vector.
Another point is your while loop. You don't test if getline succeeds and you should loop on getline instead of good
while (getline(labErnIn, temp)) {
...
}

Related

How to print to file?

I'm need to print some info on a file ".txt".
I wrote on the program the link of the file I want to copy the info. The ".txt" file is empty.
Eclipse tells me that the code is without error. This is the part of code of the print on file:
void stampaVendute(string& vendute,int& n,Opere f[],char p[],int a){
cout<<"\nInserisci il file sul quale vuoi visualizzare le opere vendute: "<<endl;
getline(cin,vendute);
ofstream ofs;
ofs.open(vendute.c_str());
if(!ofs.good()){
cout<<"C'è qualche problema nell'apertura del file"<<endl;
return;
}
for(int i=0;i<n;i++){
if((!stricmp(p,f[i].N_C)) and a<=f[i].anno){
ofs<<"\nOPERA "<<(i+1)<<endl;
ofs<<"Codice: "<<f[i].codice<<";"<<endl;
ofs<<"Titolo: "<<f[i].titolo<<";"<<endl;
ofs<<"Autore: "<<f[i].N_C<<";"<<endl;
ofs<<"Anno: "<<f[i].anno<<";"<<endl;
ofs<<"Valore: "<<f[i].prezzo<<";"<<endl;
}
ofs.close();
}
cout<<"\nI DATI SONO STATI COPIATI CORRETTAMENTE SUL FILE!"<<endl;
}
If if((!stricmp(p,f[i].N_C)) and a<=f[i].anno){ fails the test then nothing is printed to the file. Add a line that unconditionally prints to the file after opening, to see if it works.
Print the file name to the user when the file is opened successfully.
If you are using Windows, you can use process monitor from SysInternals (now owned by Microsoft) to see what file is actually being opened.
ofs.open(vendute.c_str());
why are you using c_str here? You know that open takes a std::string normally! You are getting a pointer to the raw characters just to construct a new different string object, and forcing the compiler to re-count the number of characters (calling strlen() again).
You should write it as one line anyway. Initialize the variable when you define it:
ofstream ofs {vendute};
⧺SL.io.50 Don't use endl.
for(int i=0;i<n;i++){
... many uses of `f[i]` follows
You should be using a range-based for loop rather than subscripts, but the way you are passing the data (separate pointer to the first element and length) instead of simply passing a collection prevents that. This is not a good way to do things! See Standard Guidelines ⧺I.13 etc.
If you did need to go over the collection via subscripts, don't keep subscripting it over and over and over. Make a reference variable pointing to that spot:
for(int i=0;i<n;i++){
const auto& x = f[i];
... now use x over and over, not f[i]
here's your problem
Look where ofs.close(); is being called. The indentation of the code in the post is all messed up... it looks like this should be after the loop, before the final cout line. But what's that extra } coming from?
You are closing the file after the first iteration through the loop. If that case (i==0) did not print results, nothing will ever be shown.

Issue reading multiple lines from .txt file in C++

I'm trying to create a student database system for a school project. I'm trying to create a function that will search a .txt file for the student id and return all of the other variables on the string. This is working great if I search for the id of the student on the first line of the txt file but isn't capturing anything if I search for a student on another line. Am I missing something obvious?
The student data is 16 strings delimited by commas on each line. The student ID is the first string.
Thanks for any assistance!
StudentType findStudent(int studentToFind)
{
ifstream inFile;
inFile.open("students.txt");
string currentLine;
string dataRead[16];
istringstream is;
int currentStudent;
if (inFile)
{
while (getline(inFile, currentLine))
{
is.str(currentLine);
for (int i = 0; i < 16; i++)
{
getline(is, dataRead[i], ',');
}
currentStudent = stoi(dataRead[0]);
if (currentStudent == studentToFind)
{
/*
Do stuff here
*/
inFile.close();
return foundStudent;
}
cin.ignore(); // Not sure if this is needed but I was trying to
// clear the \n char if that was causing the issue
}
}
}
First : you aren't using cin, so get rid of cin.ignore().
Second : you should make sure you ALWAYS close infile at the end... so I would suggest not returning early or closing early, but using a break statement to exit your loop and then have a single return of whether you found it or not.
Third: Now that you removed all the 'gorp' we can finally hone in on the problem ... effectively the question is do we read all the lines?
Well let's check that, try printing out currentLine each time at the beginning of the while loop, if you know currentLine is updated properly, is is getting updated each time? yes...
ok then look at your next loop let's print out currentStudent each time... does currentStudent print the right value for each line? i.e. is the getline write into dataRead[i] actually writing what you think it should be to the right space?
Did you find the problem yet?
This is the kind of problem you need to learn how to solve yourself using print statements and a debugger. That what its for. If you are in visual studio run in debug mode and step through it... if not, use gdb. learn it and get used to it, you'll be using it a lot!
good luck

atof changing values of global array

I have an issue that I'm basically baffled by. To start off, I have two global arrays - trustArray[] and fashionArray[]. Here is the function that fills the trustArray:
void getTrust()
{
string line;
int reachedTrust=0;
int numberOfTrustsRecorded=0;
ifstream myfile ("BuyingJeans.Hw5 (1).csv");
if (myfile.is_open())
{
while ( myfile.good() )
{
getline (myfile,line,',');
//int found=line.find("Like-Purchase");
if (line=="Trust-Like"){
reachedTrust=1;
getline (myfile,line,',');
}
if(reachedTrust==1){
if(numberOfTrustsRecorded <6){
double testValue = atof(line.c_str());
trustArray[numberOfTrustsRecorded] = testValue;
numberOfTrustsRecorded++;
}
}
}
myfile.close();
}
else
cout << "Unable to open file";
}
For some reason, the atof() in this function is changing two of the values in fashionArray[]. If I change the atof() to say, an atoi(), the problem no longer occurs. Here is the method that fills the array that is being changed (fashionArray[]):
void getFashion(){
string line;
int reachedFashion=0;
int numberOfFashionsRecorded=0;
ifstream myfile ("BuyingJeans.Hw5 (1).csv");
if (myfile.is_open())
{
while ( myfile.good() )
{
getline (myfile,line,',');
if (line=="Like-Fash -->"){
reachedFashion=1;
getline (myfile,line,',');
//cout<<line<<endl;
//getchar();
}
if(reachedFashion==1){
if(numberOfFashionsRecorded <6){
fashionArray[numberOfFashionsRecorded] = atoi(line.c_str());
numberOfFashionsRecorded++;
}
}
}
myfile.close();
}
else cout << "Unable to open file";
}
Here is the main method that calls these two methods:
int main () {
getFashion();
getTrust();
for(int x=0; x<6;x++)
cout<<fashionArray[x]<<endl;
getchar();
return 0;
}
The first two values of fashionArray end up being changed to some ridiculously large negative and positive integers. One interesting thing is that if I reverse the order in which the two methods are called in the main() method, the issue no longer occurs. Anyone have any idea what could be causing this?
I think you are writing beyond trustArray and into fashionArray. You have not provided initialisation code (please do), but I suppose it looks something like this :
float trustArray[N];
float fashionArray[N];
With N equal to some positive integer. My guess is that in your case, N=5.
In your loop, you test that numberOfTrustsRecorded < 6. Values of numberOfTrustsRecorded that will pass that test are 0, 1, 2, 3, 4, 5. That's six (6) floats to fit in a array of 5. Writing numberOfTrustRecorded[5] will overwrite memory. Change your test or increase your buffer size to 6.
Why aren't you seeing valid values in fashionArray[0] ? I don't know. Maybe your compiler aligned the fashionArray memory buffer so the overwrite starts in unused memory, leaving you with half the bits required to make a IEEE float. Whatever bits are in memory make up a random float. A memory dump would show the problem.
Why is running the method in reverse order works ? Probably that the bug is still there, but running getFashion() second cleans the mess left by getTrust(). The memory you overwrite is yours, so as long as you don't try to make sense of it, nobody complains. Initialize fashionArray[0] = 0.0, run getTrust() and look at fashionArray[0] before running getFashion(). You will probably see the random floats.

read in values and store in list in c++

i have a text file with data like the following:
name
weight
groupcode
name
weight
groupcode
name
weight
groupcode
now i want write the data of all persons into a output file till the maximum weight of 10000 kg is reached.
currently i have this:
void loadData(){
ifstream readFile( "inFile.txt" );
if( !readFile.is_open() )
{
cout << "Cannot open file" << endl;
}
else
{
cout << "Open file" << endl;
}
char row[30]; // max length of a value
while(readFile.getline (row, 50))
{
cout << row << endl;
// how can i store the data into a list and also calculating the total weight?
}
readFile.close();
}
i work with visual studio 2010 professional!
because i am a c++ beginner there could be is a better way! i am open for any idea's and suggestions
thanks in advance!
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <limits>
struct entry
{
entry()
: weight()
{ }
std::string name;
int weight; // kg
std::string group_code;
};
// content of data.txt
// (without leading space)
//
// John
// 80
// Wrestler
//
// Joe
// 75
// Cowboy
int main()
{
std::ifstream stream("data.txt");
if (stream)
{
std::vector<entry> entries;
const int limit_total_weight = 10000; // kg
int total_weight = 0; // kg
entry current;
while (std::getline(stream, current.name) &&
stream >> current.weight &&
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n') && // skip the rest of the line containing the weight
std::getline(stream, current.group_code))
{
entries.push_back(current);
total_weight += current.weight;
if (total_weight > limit_total_weight)
{
break;
}
// ignore empty line
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
else
{
std::cerr << "could not open the file" << std::endl;
}
}
Edit: Since you wannt to write the entries to a file, just stream out the entries instead of storing them in the vector. And of course you could overload the operator >> and operator << for the entry type.
Well here's a clue. Do you see the mismatch between your code and your problem description? In your problem description you have the data in groups of four lines, name, weight, groupcode, and a blank line. But in your code you only read one line each time round your loop, you should read four lines each time round your loop. So something like this
char name[30];
char weight[30];
char groupcode[30];
char blank[30];
while (readFile.getline (name, 30) &&
readFile.getline (weight, 30) &&
readFile.getline (groupcode, 30) &&
readFile.getline (blank, 30))
{
// now do something with name, weight and groupcode
}
Not perfect by a long way, but hopefully will get you started on the right track. Remember the structure of your code should match the structure of your problem description.
Have two file pointers, try reading input file and keep writing to o/p file. Meanwhile have a counter and keep incrementing with weight. When weight >= 10k, break the loop. By then you will have required data in o/p file.
Use this link for list of I/O APIs:
http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx
If you want to struggle through things to build a working program on your own, read this. If you'd rather learn by example and study a strong example of C++ input/output, I'd definitely suggest poring over Simon's code.
First things first: You created a row buffer with 30 characters when you wrote, "char row[30];"
In the next line, you should change the readFile.getline(row, 50) call to readFile.getline(row, 30). Otherwise, it will try to read in 50 characters, and if someone has a name longer than 30, the memory past the buffer will become corrupted. So, that's a no-no. ;)
If you want to learn C++, I would strongly suggest that you use the standard library for I/O rather than the Microsoft-specific libraries that rplusg suggested. You're on the right track with ifstream and getline. If you want to learn pure C++, Simon has the right idea in his comment about switching out the character array for an std::string.
Anyway, john gave good advice about structuring your program around the problem description. As he said, you will want to read four lines with every iteration of the loop. When you read the weight line, you will want to find a way to get numerical output from it (if you're sticking with the character array, try http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/, or try http://www.cplusplus.com/reference/clibrary/cstdlib/atof/ for non-whole numbers). Then you can add that to a running weight total. Each iteration, output data to a file as required, and once your weight total >= 10000, that's when you know to break out of the loop.
However, you might not want to use getline inside of your while condition at all: Since you have to use getline four times each loop iteration, you would either have to use something similar to Simon's code or store your results in four separate buffers if you did it that way (otherwise, you won't have time to read the weight and print out the line before the next line is read in!).
Instead, you can also structure the loop to be while(total <= 10000) or something similar. In that case, you can use four sets of if(readFile.getline(row, 30)) inside of the loop, and you'll be able to read in the weight and print things out in between each set. The loop will end automatically after the iteration that pushes the total weight over 10000...but you should also break out of it if you reach the end of the file, or you'll be stuck in a loop for all eternity. :p
Good luck!

reading data from files, file name as input

I am writing a program which reads data from different files, which are given as input strings, and stores them into a vector of vectors. The problem I am not able to debug the loop which reads different files. I have closed the ifstream object, cleared the string using empty function... but still it just terminates when i give second file name as input.
I am copying the code for your perusal. It is a function called by another another function. Transposectr transposes a matrix.
code:
vector<vector<float> > store1,store2;
ifstream bb;
string my_string;
float carrier;
vector<float> buffer;
cout<<"enter the file name"<<endl;
getline(cin,my_string);
while (my_string!="end")
{
bb.open(my_string.c_str());
while (!bb.eof())
{
bb >> carrier;
if (bb.peek() == '\n' || bb.eof() )
{
buffer.push_back(carrier);
store1.push_back(buffer);
buffer.clear();
}
else
{
buffer.push_back(carrier);
}
}
bb.close();
buffer.clear();
transposectr1(store1);
storex.push_back(store1[1]);
storey.push_back(store1[0]);
store1.clear();
my_string.empty();
cout<<"done reading the file"<<endl;
cout<<"enter the file name"<<endl;
getline(cin,my_string);
}
I'm really not clear what you are trying to do. But I have one golden ruile when it comes to using istreams:
Never use the eof() function!
It almost certainly does not do what you think it does. Instead you should test if a read operation succeeded.
int x;
while( in >> x ) {
// I read something successfully
}
You might also want to avoid peek() too. Try re-writing your code with this advice in mind.
Add
bb.clear();
after the bb.close() you may get the right thing. bb.close() doesn't reset the cursor I think.
Neil Butterworth is right
Never use the eof() function!
This link explains why.