C++ homework compile error with if statement - c++

Having trouble with the second if statement to only read ten values. If I remove the program will compile. I need it in for the assignment I have tried several modifications, so what is here may not reflect my last attempt. C++ homework compile error with if statement. Details how many more details do I need to add before this will post, more details
#include <iostream>
#include <fstream>
using namespace std;
/**********************************************************************
* Get File
* This function will prompt the user for the name of the file and
* return it.
*********************************************************************/
void getFileName(char fileName[])
{
//prompt the user
cout << "Please enter the filename: ";
cin >> filename;
ofstream fout(fileName);
}
/**********************************************************************
* Read
* This function will read the file and return the average score of the
* ten values.
*********************************************************************/
float readFile(char fileName[])
{
cout.setf(ios::fixed); //no scientific notation
cout.precision(0); //no decimals
//In case of error
ifstream fin(filename);
if (fin.fail())
{
cout << "Error reading file \"" << fileName << "\"" << endl;
exit(0);
}
float data; //always need a variable to store the data
float i = 0; //don't forget to initialize the variable
float gradeSum = 0;
float average;
//Add up all the grades
while (fin >> data) //while there was not an error
{
gradeSum += data; //do the work
i++;
}
// Hint: Make sure you only read ten values.
if (i != 10)
{
//tell the user what happened
cout < "Error reading file \"" << fileName << "\"" << endl;
exit(0);
}
//Calculate average grade
average = gradeSum / i;
//Close file
fin.close();
return average;
}
/**********************************************************************
* Display function
* This function will display the average score to zero decimals of
* accuracy.
*********************************************************************/
void display(float average)
{
cout << "Average Grade: " << average << "%" << endl;
}
/**********************************************************************
* main calls average grade and file name
***********************************************************************/
int main()
{
char fileName[256];
getFileName(fileName);
int average = readFile(fileName);
return 0;
}

Note the position of your if statement in relation to your while loop. When does your if statement run? When does your while loop run?
With these in mind, how would you adjust your while loop to take into consideration your restriction (while loop stops executing when i = 10)?
I hope this helps you better understand what you need to do without spoiling too much of the answer.
P.S. The contents of the if block will quit the program on the spot if i != 10, without executing anything beyond.
if (i != 10)
{
//tell the user what happened
cout < "Error reading file \"" << fileName << "\"" << endl;
exit(0);
}

Simple typo with regards to the stream operator.
This line:
cout < "Error reading file \"" << fileName << "\"" << endl;
Should be:
cout << "Error reading file \"" << fileName << "\"" << endl;
Also, you have other typos preventing your code from compiling: namely the mixed case usage of filename and fileName throughout. After I fixed those variable namings to be consistently fileName, it compiled.

your cout is invalid. cout << "Average Grade: " << average << "%" << endl; instead of "cout < Average Grade: " << average << "%" << endl;

Related

Using sentinel values and counter control to get data from a file

I am trying to allow the user to select which file to open then use either a sentinel value or counter control to get all the values from the selected file. The code I have just outputs:
There are 0 values in the file.
The values in the file are: -1206517578
The average is -inf
Which is not true as there are 10 numbers in each file and they are all less than 9. I have been staring at this and can't figure out what is wrong.
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main() {
char fileSel;
double numValues = 0; //# of values in list
int values; //numbers in list
double avg = values / numValues;
int counter = 10;
const int SENTINAL_VALUE = -9999;
//Which file would you like to open?
cout << "Which file would you like to open?" << endl;
//1. Counter Controlled
cout << "1. Counter Controlled" << endl;
//2. Sentinel Controlled
cout << "2. Sentinel Controlled" << endl;
//Input file
cin >> fileSel;
//loop file selected
//counter controlled
while (fileSel == 1){
//open and check file
ifstream inFile;
inFile.open("counter_controlled.txt ");
if (inFile.fail()) {
cerr << "Could not open input file" << endl;
return -1;
}
while (numValues <= counter) {
inFile >> values;
numValues += 1;
}
inFile.close();
}
//sentinal
while ( fileSel == 2) {
//open and check file
ifstream inFile;
inFile.open("sentinel_controlled.txt");
if (inFile.fail()) {
cerr << "Could not open input file" << endl;
return -1;
}
//get values until
while (inFile >> values);
numValues += 1;
if (values == SENTINAL_VALUE){
cout << "There are " << numValues << " values in the file." << endl;
cout << "The values in the file are: " << values << endl;
//The average is 4.93.
cout << "The average is " << avg << endl;
}
inFile.close();
}
//The values in the file are:
cout << "There are " << numValues << " values in the file." << endl;
cout << "The values in the file are: " << values << endl;
cout << "The average is " << avg << endl;
return 0;
}
Starting with just these 3 lines of code:
double numValues = 0; //# of values in list
int values; //numbers in list
double avg = values / numValues;
at this point avg is UNINITIALIZED divided by ZERO, which is not good in multiple ways. I'd think the compiler would have a lot to say about this.
values actually has to be accumulated before its average can be calculated, and values is never accumulated into anything, you just read it in over and over.
...C++ is imperative, not declarative like Excel.
In addition to dirck's observation that you are computing the results before you have the data, there is much more wrong with it.
You are reading the same value over and over, not making a collection of values and not summing the values read.
while (inFile >> values);
has nothing to do with stopping at the sentinel, and the following block of code will test the last value read (only), which is the last value in the file.

So I'm having trouble understanding files in C++

I just started learning files and I understand how to set it up and get it to work. I have to write this program where I have to allow the user to enter some information and have the user also update and adjust any data, using binary.
So I can write up until the point where the user can write to and read from the file. But I don't know how to let the user adjust data or add data.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class client {
public:
string name;
int balance;
string id;
};
int main()
{
int ans;
int x;
string nameIn;
string adjName;
client client1;
ofstream out("client1.dat", ios::binary);
cout << "\nDo you want to add information or update info" << endl;
cin >> ans;
if (ans == 1)
{
cout << "\nPlease enter the name of your client" << endl;
cin >> nameIn;
x = nameIn.length();
if (x <= 10)
{
for (int i; i < 10; i++)
{
adjName[i] = nameIn[i];
}
}
else
{
for (int i = x; i < 10; i++)
{
adjName[i] = ' ';
}
}
client1.name = adjName;
cout << "\nPlease enter the balance of your client" << endl;
cin >> client1.balance;
cout << "\nPlease enter the id of your client" << endl;
cin >> client1.id;
cout << "\nThe name of your client is " << endl << client1.name
<< endl << "\nThe balance of your client is " << endl
<< client1.balance << endl << "\nThe id of your client is "
<< endl << client1.id;
out.write(reinterpret_cast<const char*> (&client1), sizeof(client));
}
/*
else if (ans == 2)
{
string answer, newName,line;
cout << "\nWhat name do you want to update? " << endl;
cin >> answer;
cout << "\nWhat is the new name?" << endl;
cin >> newName;
if (out)
}
*/
system("pause");
return 0;
}
so the name needs to be only 10 characters long, so that we can adjust/update it. It compiles and runs, but every time the compiler gets to the part where it checks the name length, it freaks out and says "debug assertion failed"
string subscript out of range.
Also a thing about this code-- if i run it without the bits where you adjust the name to a certain array length, the program runs, and stores everything nicely. But when I try to read back the .dat, it reads it back but exits with an access violation, forcing me to manually stop the debugging. What am I doing wrong?
this is the code for reading the file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class client {
public:
string name;
int balance;
string id;
};
int main()
{
client client1;
char ans;
cout << "\nDo you want to view the information about your client?"
<< endl;
cin >> ans;
ifstream in("client1.dat", ios::binary);
if (ans == 'y' || ans == 'Y')
{
in.read(reinterpret_cast<char*> (&client1), sizeof(client));
cout << "The name is " << endl << client1.name << endl
<< "The balance is " << endl << client1.balance << endl
<< "The id is " << endl << client1.id << endl;
}
system("pause");
return 0;
}
As for the 1st part:
for (int i; i < 10; i++)
// ^
misses to initialize i to zero. Also what if the input was smaller than 10 characters? You're going to access the std::string out of bounds. You should replace the if/else and loops with simply
adjName = nameIn;
while(adjName.length() <= 10) {
adjName += ' ';
}
to get rid of the debug assertion.
For the 2nd part of the question, as already mentioned in the comments you cannot do this with a structure containing classes like std::string.
The reinterpret_cast<char*> (&client1) just obfuscates that std::string uses a pointer to the dynamically allocated character data internally, and that cannot be restored meaningfully when reading the stored data back later (hence the access violation you get).
A viable way might be to use something like
struct client {
char name[11];
int balance;
char id[5];
};
As I guess you need to do this for a homework exercise, and for this purpose that would probably be sufficient.
But you quickly can see the drawbacks, that the character data needs to be fixed in size and you cannot have arbitrary length strings. I never would use such for production ready code.
Another pitfall (as also mentioned) is, that int isn't represented in the same way (order of bytes used, i.e. endianess) in the same way for different CPU architectures. So the binary file can't be used portably with different computers.
The simplest solution is not to use a binary file, but a text formatted file and overload the std::ostream& operator<<(std::ostream&, const client&) and std::istream& operator>>(std::istream&, client&) output/input operators.
Or use some 3rd party library like boost::serialization or google protocol buffers, that supports de-/serialization to binary files.

get string array from text list c++

my text file was like
123456123456
Jason
uk
012456788
1000
456789456789
david
uk
012456788
1000
i'm trying to get the data from a text file and save it into arrays
however when i want to store the data from the text file into array it loop non-stop.
what should i do ?
the problem exiting in looping or the method i get the data from text file ?
code:
#include <iostream>
#include <fstream>
using namespace std;
typedef struct {
char acc_no[12];
char name[30];
char address[50];
char phone_no[12];
double balance;
} ACCOUNT;
//function prototype
void menu();
void read_data(ACCOUNT record[]);
int main() {
ACCOUNT record[31]; //Define array 'record' which have maximum size of 30
read_data(record);
}
//--------------------------------------------------------------------
void read_data(ACCOUNT record[]) {
ifstream openfile("list.txt"); //open text file
if (!openfile) {
cout << "Error opening input file\n";
return 0;
} else {
int loop = -1; //size of array
cout << "--------------Data From File--------------"<<endl;
while (!openfile.eof()) {
if (openfile.peek() == '\n')
openfile.ignore(256, '\n');
openfile.getline(record[++loop].acc_no, 12);
openfile.getline(record[loop].name, 30);
openfile.getline(record[loop].address, 50);
openfile.getline(record[loop].phone_no, 12);
openfile >> record[loop].balance;
}
openfile.close(); //close text file
for (int i = 0; i <= loop + 1; i++) {
cout << "Account " << endl;
cout << "Account No. : " << record[i].acc_no << endl;
cout << "Name : " << record[i].name << endl;
cout << "Address : " << record[i].address << endl;
cout << "Phone Number : " << record[i].phone_no << endl;
cout << "Balance : " << record[i].balance << endl;
}
}
}
UPDATE:
The OP didn't properly cite the correct format in his data file. This answer is only valid up until the last iteration.
Don't use .eof() - that's more applicable to when you want to open the file and read it by characters.
A better way would be to use the insertion operator >> as follows:
#define ARR_SIZE 31
ACCOUNT temp;
ACCOUNT record[ARR_SIZE];
int i=0;
while(i < ARR_SIZE) {
openfile >> temp.acc_no >> temp.name >> temp.address >> temp.phone_no >> temp.balance;
record[i] = temp;
i++;
}
Of course, even better is to use std::string to hold the values from the input file, in addition to using std::vectors instead of arrays.

Bar graph program behaving strangely

I have to make a program for a class that displays one star for every three degrees for each temperature read from an input file. I think I did ok, the code compiles. However, when I actually run it, I have a few problems:
1) when I run it without pressing ctrl+f5 in codelite it exits immediately, even though I have 'return 0;' at the end.
2) the console only shows stars for maybe half of the numbers, the rest are blank.
3) the numbers aren't lining up although I have set them all to the same width in my loop.
Here's what I see when I use ctrl+f5: http://imgur.com/w6jqPp5
Here's my code:
#include <fstream>
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
int main() {
//declare variables for input/loops
string graphLine = " | ";
int tempCount = 0;
int tempStars;
int tempValue;
int printedStars;
//Title
cout << "Welcome to the Hourly Temperature Bar-Graph Maker 1.0!" << endl;
//read input file, name it "tempData"
ifstream tempData;
tempData.open("temperatures.txt");
//display error if the input file read failed
if(!tempData) {
cout << "ERROR: The input file could not be read." << endl;
return 0;
}
cout << "Temperatures for 24 hours(each asterisk represents 3 degrees): " << endl;
//print the temperature range(horizontal label for graph)
cout << "-30 0 30 60 90 120" << endl;
//read a temperature, output the bar for each temperature
while (tempCount < 24) {
//read in temperature value
tempData >> tempValue;
//distinguish between negative and positive temperatures
if(tempValue >= 0) {
tempStars = tempValue/3;
cout << tempValue << setw(5) << graphLine;
//print the appropriate number of asterisks for the temperature
while (printedStars < tempStars) {
cout << '*';
printedStars++;
}
cout << endl;
}
//print the stars before the line
else {
tempStars = tempValue/3;
while (printedStars < tempStars) {
cout << '*';
printedStars++;
}
cout << tempValue << setw(5) << graphLine << endl;
}
tempCount++;
}
tempData.close();
return 0;
}
The program is just finishing normally - put a call to cin.getline or some other input call if you want it to wait. Alternatively run it through the debugger and put a breakpoint on the return 0 line.
You don't initialize or reset printedStars before you use it. Put printedStars = 0; before your star printing loops.
Move the setw(5) bit in the cout calls to before the value, so the value is output with a width of 5.

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.