Why is the program skipping the first line of every new deptnum?
I am trying to read from a file that looks like:
1 Suits 0300 100 092
1 Coats 0200 060 065
1 Shirts 1000 012 013
2 Dresses 0400 060 065
2 Coats 0185 184 200
2 Shoes 0600 040 030
3 Jeans 0200 040 035
3 Shoes 0200 030 034
4 Jeans 0300 042 043
The deptnum is the first column.
And when I write to the other file I get:
Blinn Discount Apparel Company
Inventory Evaluation
10/12/2018
Unit Cost Extended
Quantity Cost Market Cost Market Lower Cost
Mens Dept
Suits 300 100.00 92.00 30000.00 27600.00
Coats 200 60.00 65.00 12000.00 13000.00
Shirts 1000 12.00 13.00 12000.00 13000.00
Total $54000.00 $53600.00 $53600.00
Womens Dept
Coats 185 184.00 200.00 34040.00 37000.00
Shoes 600 40.00 30.00 24000.00 18000.00
Total $112040.00 $108600.00 $108600.00
Girls Dept
Shoes 200 30.00 34.00 6000.00 6800.00
Total $118040.00 $115400.00 $115400.00
Boys Dept
Total $118040.00 $115400.00 $115400.00
Total Inventory $393000.00
It skipped Womens Dept -> Dresses, Girls Dept -> Jeans, and Boys Dept -> Jeans.
Here is my code:
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
int main()
{
ifstream inFile;
ofstream outFile;
int x = 1, deptnum, quant,cost,mkt,extcost,extmkt,totalcost = 0,totalmkt = 0,
lowcost,totalInv = 0;
char item [15];
inFile.open("blinn.dat");
outFile.open("blinn.dout");
if (!inFile)
cout <<"\n\t\t Can't open data file: blinn.dat\n";
else {
outFile <<"\n\t Blinn Discount Apparel Company\n";
outFile <<"\t Inventory Evaluation\n";
outFile <<"\t 10/12/2018\n";
outFile <<"\n\t\t\t\t\t\t Unit Cost\t\t\t Extended\n";
outFile <<"\t\t Quantity Cost Market Cost Market Lower Cost";
while (x < 5)
{
if (x == 1)
outFile << "\nMens Dept";
else if (x == 2)
outFile << "\nWomens Dept";
else if (x == 3)
outFile << "\nGirls Dept";
else if (x == 4)
outFile << "\nBoys Dept";
else
break;
while (inFile >> deptnum >> item >> quant >> cost >> mkt)
{
if (deptnum == x){
extcost = quant * cost;
extmkt = quant * mkt;
outFile << left << "\n " << setw(7)<< item << " "
<< right << setw(4)<< quant << " "
<< right << setw(4) << cost << ".00 "
<< right << setw(3) << mkt << ".00 "
<< right << setw(5) << extcost<< ".00 "
<< right << setw(5) << extmkt << ".00";
totalcost += extcost;
totalmkt += extmkt;
if (totalcost > totalmkt)
lowcost = totalmkt;
else
lowcost = totalcost;
}else
break;
}
outFile << right << "\n Total\t\t\t\t\t $" << totalcost << ".00 $"
<< totalmkt << ".00 $"<< lowcost << ".00";
x += 1;
totalInv += lowcost;
}
}
outFile << "\nTotal Inventory\t\t\t\t\t\t $"<< totalInv<< ".00";
inFile.close ();
outFile.close ();
return 0;
}
What is wrong with my logic?
There is a problem with your logic:
if (deptnum == x) {
// do something
}
else {
break;
}
To achieve the else branch, you have already read a line that deptnum != x (the first line of every new deptnum) so at the next iterator, the current line is discarded by the next input line.
Related
I am trying to get this C++ assignment aligned properly. The main goal is to properly read data from a file, which is being done, but the output is not aligned properly.
Somebody has suggested putting all the variables into one string and outputting that row by row, but that seems like I would need to re-write the majority of the program and I'm not completely sure how to do it. I have attached the code and what the output looks like below. Just wondering if there's a better way to keep everything aligned while using setwidth, or another basic alignment method if one exists. By the way, the file's input can change.
while (!PatientsFile.eof()) {
PatientsFile >> firstName;
PatientsFile >> lastName;
PatientsFile >> pulse;
PatientsFile >> respir;
PatientsFile >> oxygen;
PatientsFile >> room;
string name = firstName + ", " + lastName;
//patient info
cout << setw(4) << room << ' ';
cout << name;
//pulse
if (pulse >= 101) {
cout << setw(13) << "High=" << pulse << ' ';
dangerCount++; }
else if (pulse <= 59) {
cout << setw(16) << "Low=" << pulse << ' ';
dangerCount++; }
else {
cout << setw(19) << pulse << ' '; }
//respir
if (respir >= 21) {
cout << setw(5) << "High=" << respir << ' ';
dangerCount++; }
else if (respir <= 10) {
cout << setw(6) << "Low=" << respir << ' ';
dangerCount++; }
else {
cout << setw(7) << respir << ' '; }
//oxygen
if (oxygen >= 101) {
cout << setw(7) << "High=" << oxygen << ' ';
dangerCount++; }
else if (oxygen <= 91) {
cout << setw(5) << "Low=" << oxygen << ' ';
dangerCount++; }
else {
cout << setw(7) << oxygen << ' '; }
//dangerCount
if (dangerCount == 1) {
checkTotal++;
cout << "CHECK\n";}
else if (dangerCount == 2) {
alertTotal++;
cout << "ALERT***\n"; }
else if (dangerCount == 3) {
criticalTotal++;
cout << setw(15) << "CRITICAL****\n"; }
else {
normalTotal++;
cout << endl; }
dangerCount = 0;
}
//display totals
cout << endl << normalTotal << " Normal\n";
cout << alertTotal << " ALERT\n";
cout << checkTotal << " CHECK\n";
cout << criticalTotal << " CRITICAL\n";
Output:
Room Name Pulse Respir Oxygen
-----------------------------------------------------
111 Pete, Moss Low=59 11 Low=91 ALERT***
312 Diana, Canser High=107 Low=10 96 ALERT***
332 Willie, Makit High=123 High=30 94 ALERT***
111 Betty, Wont Low=50 Low=10 Low=90 CRITICAL****
331 Freda, Spirit High=110 High=23 Low=90 CRITICAL****
321 Wilma, Moneylast High=132 18 Low=88 ALERT***
121 Robin, Banks Low=59 20 100 CHECK
122 Charlie, Horse Low=56 15 95 CHECK
121 Eileen, Back Low=45 17 Low=88 ALERT***
222 Eaton, Buggs 79 16 97
222 Summer, Day 60 12 92
231 Bea, Sting 73 High=21 Low=91 ALERT***
311 Anita, Bath High=111 High=33 97 ALERT***
232 April, Showers 61 High=22 93 CHECK
222 Rose, Bush 100 20 100
231 Buster, Leggs 88 High=44 Low=88 ALERT***
221 Barb, Wire 60 12 Low=82 CHECK
322 Jim, Shoos High=101 19 94 CHECK
322 Kris, Mass Low=4 14 99 CHECK
222 Rich, Bright 77 16 92
4 Normal
8 ALERT
6 CHECK
2 CRITICAL
You can try using tab \t in order to align your list correctly.
Here is the link you might want to look at: How many spaces for tab character(\t)?
Otherwise you will have to do
cout << "text" << setw(#) << "text" << setw(#) << endl;
I would advise against this since it just hardcoding set numbers and its tedious because you would have to count and make sure it is matching correctly.
As Xion's answer mentioned, the process of hardcoding the correct value for the for the text to be aligned correctly, is tedious. Furthermore, it might even not be correct at all for a different data set - For example, what would happen if someone had a much larger name than anticipated?
My suggestion is the following: Iterate over the data completely once, and store the maximum width of each field in a separate variable (also storing the data retrieved).
After that, you could then loop once again over the input, and now everything would be correctly aligned, as you would now know the maximum width of each field (including not having the guess the correct spacing for the header column beforehand, which would be ideal).
You could either create objects of this information and store them in a std::vector, or do the same with each separate data field, having a vector for each one.
I almost have it working however, it is seperating the last names that start in caps and the ones that do not.
Example file
LastName FirstName DaysofRental BalanceDue
Smith Joe 15 100.50
Doe John 10 95.20
Anderson Paul 30 20.00
O'Donell Miriam 10 24.30
Foster Sam 30 15.00
Zom Pete 10 20.00
Mock Chilly 100 30
smitty Chris 200 200
xu Conor 1 200
anilo steve 0 0
What "Sorted" file is outputing
LastName FirstName DaysofRental BalanceDue
Anderson Paul 30 $20.00
Doe John 10 $95.20
Foster Sam 30 $15.00
Mock Chilly 100 $30.00
O'Donell Miriam 10 $24.30
Smith Joe 15 $100.50
Zom Pete 10 $20.00
anilo steve 0 $0.00
smitty Chris 200 $200.00
xu Conor 1 $200.00
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <fstream>
#include <string.h>
using namespace std;
const int STRINGSIZE = 30;
const int LISTSIZE = 10;
const int HEADSIZE = 4;
typedef char STRING30[STRINGSIZE];
typedef STRING30 NAMES[LISTSIZE];
int main(int argc, char** argv)
{
ofstream outfile;
outfile.open("sorted.txt");
int count,
count2,
mindex;
int rdays[LISTSIZE],
hrdays;
double baldue[LISTSIZE],
totalbaldue,
hbaldue,
tempnum;
NAMES first,
last,
header;
STRING30 mname,
tempname;
ifstream in;
in.open("invoice1_test1.txt");
//Input Section
if(in.is_open())
{
in >> header[0]
>> header[1]
>> header[2]
>> header[3];
int count = 0;
while(!in.eof())
{
in >> last [count]
>> first[count]
>> rdays[count]
>> baldue[count];
count++;
}
in.close();
}
else
{
cout << "File failed to open" << endl;
}
for(count = 0; count < LISTSIZE; count++)
{
mindex = count;
strcpy(mname, last[count]);
for(count2 = count; count2 < LISTSIZE; count2++)
{
if(strcmp(last[count2], mname) == -1)
{
mindex = count2;
strcpy(mname, last[count2]);
}
}
strcpy(tempname, last[count]);
strcpy(last[count], mname);
strcpy(last[mindex], tempname);
strcpy(tempname, first[count]);
strcpy(first[count], first[mindex]);
strcpy(first[mindex], tempname);
tempnum = rdays[count];
rdays[count]= rdays[mindex];
rdays[mindex]= tempnum;
tempnum = baldue[count];
baldue[count] = baldue[mindex];
baldue[mindex] = tempnum;
}
outfile << setiosflags(ios::showpoint | ios::fixed) << setprecision(2);
outfile << left << setw(20) << header[0] << setw(20) << header[1] << setw(20) << header[2] << setw(20) << header[3] << endl;
for(int count = 0; count<LISTSIZE; count++)
{
outfile << left << setw(20) << last[count] << setw(20) << first[count] << setw(20) << rdays[count] << "$" << setw(20) << baldue[count] << endl;
}
Use if (strcmpi(last[count2], mname) < 0); for the comparison, instead of if (strcmp(last[count2], mname) ==-1);
strcmpi() functions same as strcmp() but it is not case sensitive.
Also add exit(1) if ifstream in fails to open.
Convert all names to uppercase before storing.
I'm trying to convert written code used by shared_ptr to unique_ptr because in the code of its usage seems shared_ptr unnecessary and it will be an exercise with smart pointers. As far as I can detect with debugger the problem is on v.at(i)->push_back(t);. So, as soon as a value entered, the program crashes.
Working code with shared_ptr:
#include <iostream>
#include <iomanip>
#include <memory> // For smart pointers
#include <vector> // For vector container
#include <locale> // For toupper()
using std::vector;
using std::shared_ptr;
int main()
{
vector <shared_ptr<vector<double>>>records; // Temperature records by days
size_t day{ 1 }; // Day number
char answer{}; // Response to prompt
double t{}; // A temperature
while (true) // Collect temperatures by day
{ // Vector to store current day's temperatures created on the heap
auto pDay = std::make_shared<vector<double>>();
records.push_back(pDay); // Save pointer in records vector
std::cout << "Enter the temperatures for day " << day++
<< " separated by spaces. Enter 1000 to end:\n";
while (true)
{ // Get temperatures for current day
std::cin >> t;
if (t == 1000.0) break;
pDay->push_back(t);
}
std::cout << "Enter another day's temperatures (Y or N)? ";
std::cin >> answer;
if (toupper(answer) == 'N') break;
}
double total{};
size_t count{};
day = 1;
std::cout << std::fixed << std::setprecision(2) << std::endl;
for (auto record : records)
{
std::cout << "\nTemperatures for day " << day++ << ":\n";
for (auto temp : *record)
{
total += temp;
std::cout << std::setw(6) << temp;
if (++count % 5 == 0) std::cout << std::endl;
}
std::cout << "\nAverage temperature: " << total / count << std::endl;
total = 0.0;
count = 0;
}
}
Output:
23 34 29 36 1000
Enter another day's temperatures (Y or N)? y
Enter the temperatures for day 2 separated by spaces. Enter 1000 to end:
34 35 45 43 44 40 37 35 1000
Enter another day's temperatures (Y or N)? y
Enter the temperatures for day 3 separated by spaces. Enter 1000 to end:
44 56 57 45 44 32 28 1000
Enter another day's temperatures (Y or N)? n
Temperatures for day 1:
23.00 34.00 29.00 36.00
Average temperature: 30.50
Temperatures for day 2:
34.00 35.00 45.00 43.00 44.00
40.00 37.00 35.00
Average temperature: 39.13
Temperatures for day 3:
44.00 56.00 57.00 45.00 44.00
32.00 28.00
Average temperature: 43.71
The converted code with unique_ptr:
#include <iostream>
#include <vector>
#include <memory>
#include <iomanip>
using std::vector;
int main()
{ // Function scope starts here
// a vector(outside) holding unique_ptrs to a vector(inside) which type is double
vector<std::unique_ptr<vector<double>>> v;
size_t day{ 1 };
char answer{};
double t{};
while (true)
{
size_t i{};
auto pDay = std::unique_ptr<vector<double>>();
v.push_back(std::move(pDay));
std::cout << "Enter the temperatures for day " << day++
<< " separated by spaces. Enter 1000 to end:\n";
while (true)
{
std::cin >> t;
if (t >= 1000.0) break;
v.at(i)->push_back(t);
++i;
}
//std::cout << v.at(0)->at(0) << std::endl;
std::cout << "Enter another day's temperatures (Y or N)? ";
std::cin >> answer;
if (toupper(answer) == 'N') break;
}
double total{};
size_t count{};
day = 1;
std::cout << std::fixed << std::setprecision(2) << std::endl;
for (auto const& record : v)
{
std::cout << "\nTemperatures for day " << day++ << ":\n";
for (auto temp : *record)
{
total += temp;
std::cout << std::setw(6) << temp;
if (++count % 5 == 0) std::cout << std::endl;
}
std::cout << "\nAverage temperature: " << total / count << std::endl;
total = 0.0;
count = 0;
}
} // Function scope ends here
Your std::unique_ptr<std::vector<double>> doesn't point at anything. You'd need to initialize it with a pointer to a vector.
I am using xcode. I compile fine and then once it runs it opens the file successfully and then reads two values but the values do not go into the variable, as such it then skips the for loop and closes the file and returns from main.
#include <stdio.h>
#include <iostream>
#include <fstream>
//salesman struct
struct Salesman
{
char firstname[64];
char lastname[64];
char middleinitial[1];
int averagecents;
int totalcents;
};
int main(int argc, const char * argv[]) {
//setup variables
const char* inputFilename = "TheSales.txt";
int numberPeople = 0, weeksToHandlePerPerson = 0;
int workweeklength = 5;
int totalcents = 0;
//open file
std::ifstream fileHandle;
fileHandle.open(inputFilename, std::ios::in | std::ios::app);
if(!fileHandle)
perror ( "Stream Failed to open because: " );
fileHandle >> numberPeople; <----- does not get value
fileHandle >> weeksToHandlePerPerson; <----- does not get value
//do calculations
for ( int i = 0; i < numberPeople; ++i ) <---- this gets skipped
{
Salesman nextsalesman;
fileHandle >> nextsalesman.firstname;
fileHandle >> nextsalesman.middleinitial;
fileHandle >> nextsalesman.lastname;
float t1, t2, t3, t4, t5;
fileHandle >> t1 >> t2 >> t3 >> t4 >> t5;
nextsalesman.totalcents = 100 * ( t1 + t2 + t3 + t4 + t5 );
nextsalesman.averagecents = nextsalesman.totalcents / workweeklength;
totalcents += nextsalesman.totalcents;
//print calculations calculateNumbers()
std::cout << "salesman " << i << " total: $" << nextsalesman.totalcents / 100 << "." << nextsalesman.totalcents % 100
<< " and average $" << nextsalesman.averagecents / 100 << "." << nextsalesman.averagecents % 100 << std::endl;
int averagecents = totalcents / ( numberPeople * weeksToHandlePerPerson );
std::cout << "total for all: " << totalcents / 100 << "." << totalcents % 100 << " and average for all $" <<
averagecents / 100 << "." << averagecents % 100 << std::endl;
}
fileHandle.close(); <---- this works
return 0; <---- then we return main.
}
File:
3
2
firstName1 A lastName1
20.00 25.00 30.90 40.00 55.50
20.00 25.00 30.90 40.00 55.50
firstname2 B lastName2
30.00 24.00 45.00 67.00 65.50
56.90 87.00 43.50 56.98 55.40
firstName3 C lastName3
62.00 34.50 12.50 34.00 34.90
70.00 80.00 90.00 65.00 39.00
where first int is number of employees and second is number of weeks and each week is 5 days.
Actual output:
Expected output:
(fake output but expected form)
salesman1 total: 23424 avg: 3654
salesman2 total: 234 avg: 1654
salesman3 total: 424 avg: 364.
total for all: 5345683 and average for all: 34564564
when the program used to work the output was correct.
Your code is fine and works for me.
Are you using a text editor that writes out a unicode Byte Order Marker at the start of TheSales.txt? If so, then it will confuse your program.
You can use notepad++ to strip the BOM, as described here:
http://www.larshaendler.com/2015/01/20/remove-bom-with-notepad/
(TextWrangler on OSX might be a good alternative)
After adding records in the relative file, I am trying to update one field (the balance) of a given record(client) that the user provide the account number. The update happens in the file, but it is not properly done. The output shows that the update has affected other data, and it comes also with garbage. I cannot figure out the cause of the problem. Your help will be appreciated. I am using Dev-C++. The code followed by the output is below.
#include <iostream> // cin, cout
#include <iomanip>
#include <fstream>
#include <conio.h>
using namespace std;
#define SIZE 10
struct client // Client record
{ int account; // from 1 to SIZE
char name[20];
double balance;
};
void show_file(char filename[]) // Sequential display of all records
{
client c;
int n=0;
void *ptr;
ifstream IS(filename, ios::in); // Open for sequential read
if(!IS) {cerr << filename<< " file open error." << endl; exit(1);}
cout << "\n\nSHOW_FILE: The contents of file " << filename;
while(ptr=IS.read((char *)&c, sizeof(c)))
{
cout <<'\n'<< setw(3)<< ++n << setw(6) << c.account <<setw(20)
<< c.name << setw(10) << c.balance;
}
IS.close();
}
int main(void)
{ client c;
void *ptr;
int n=0, acc,number_of_records=SIZE, field1;
double new_balance, field3;
char *fname = "credit.dat"; char field2;
cout << "\nMAKE_FILE: Creating a blank relative file " << fname
<< " containing " << number_of_records << " records.";
fstream iof(fname, ios:: in | ios::out | ios::binary );
if(!iof) {cerr << "File open error." << endl; exit(1);}
client blank={0, "", 0.0}; // Create an empty client record
while(number_of_records--)
iof.write((char *)&blank, sizeof(blank));
cout << "\n\n\nFile has been succesfully created!"; //file is still empty, no records yet.
cout<<"\n\nenter the 10 customers into the file: "<< fname<<endl<<endl;
cout << "\nAccount[1.." << SIZE
<< "], Name, Balance (0 0 0 to exit)= ";
cin >> c.account >> c.name >> c.balance;
while(0 < c.account) // && c.account <= maxrec)
{
iof.seekp((c.account-1) * sizeof(client)); // position the pointer
iof.write((char *)&c, sizeof(c));
cout << "Account[1.."<< SIZE
<< "], Name, Balance (0 0 0 to exit)= ";
cin >> c.account >> c.name >> c.balance;
}
cout << "\n\nAccount number to apply changes on balance(0 to exit) = ";
cin >> acc;
/// while(0 < acc && acc <= SIZE)
if (0<acc && acc <= SIZE)
{
//cout << "\nPositioning at " << (acc-1) * sizeof(client)<< endl;
iof.seekg((acc-1) * sizeof(client)); // position the pointer
iof.read((char *)&c, sizeof(c));
if(c.account)
cout <<'\n'<< setw(6) << c.account <<setw(20)
<< c.name << setw(10) << c.balance;
new_balance=c.balance+0.05*(c.balance); //calculation of the new balance by adding interests of 5%
cout<<"\n\n\nnew balance after the 5% interest:"<<new_balance<<endl;
c.balance=new_balance;
cout<<"current new balance: "<<c.balance<<endl; //just to check if it will be displayed
//WHERE THE PROBLEM IS...
iof.seekg(0, ios::cur); //trying to stay in the current position to apply
//change on current balance
iof<<c.account << c.name << c.balance; //trying to update record with new balance
}
else cout << "\nEmpty record";
iof.close();
cout<<"\n\nFILE after THE UPDATE: "<<endl;
show_file (fname);
cout << "\n\n";
system("pause");
return 0;
}
*********************output**************************
MAKE_FILE: Creating a blank relative file credit.dat containing 10 records.
File has been succesfully created!
enter the 10 customers into the file: credit.dat
Account[1..10], Name, Balance (0 0 0 to exit)= 1 aaaa 2399
Account[1..10], Name, Balance (0 0 0 to exit)= 2 bbbb 4000
Account[1..10], Name, Balance (0 0 0 to exit)= 3 cccc 50
Account[1..10], Name, Balance (0 0 0 to exit)= 4 dddd 5000
Account[1..10], Name, Balance (0 0 0 to exit)= 5 eeee 180
Account[1..10], Name, Balance (0 0 0 to exit)= 0 0 0
Account number to apply changes on balance(0 to exit) = 3
3 cccc 50
new balance after the 5% interest:52.5
current new balance: 52.5
FILE after THE UPDATE:
SHOW_FILE: The contents of file credit.dat
1 1 aaaa 2399
2 2 bbbb 4000
3 3 cccc 50
41667457843 c52.5♫' 5000
5 5 eeee 180
6 0 0
7 0 0
8 0 0
9 0 0
10 0 0
Press any key to continue . . .
Ha ha ha, we must be in the same class...
You use seekg() to position pointer to read and seekp() to position pointer to write.
Like this as you did earlier in your file:
iof.seekp((c.account-1) * sizeof(client)); // position the pointer
iof.write((char *)&c, sizeof(c));
seekg = seek to get
seekp = seek to put - requ
good luck!