I wrote a program that dynamically allocates memory for an array of structure. It seems to work fine but when ever I try to delete the array the computer makes a "bong" noise and the program stops responding. It doesn't throw an error or anything, it just stops. I have tried delete and delete[] with the same result. I've tried moving the location of delete and found that I can delete it right after its created, but not after its been passed to any functions. Can anyone tell me why I can't delete memory?
#include <iostream>
#include <iomanip>
#include <fstream>
using std::cin;
using std::cout;
using std::endl;
using std::ifstream;
using std::ofstream;
using std::setw;
using std::left;
using std::fixed;
using std::setprecision;
//structure of an employee
struct Employee
{
char first_name[32];
char last_name[32];
char SSN[11];
float wage;
int hours;
char status;
};
void ReadData(Employee work_force[]);
void PrintData(Employee work_force[], int number_entries);
float CalculateStarightPay(Employee worker);
float CalculateOvertimePay(Employee worker);
int FindNumberEntries();
const int SPACING = 15; //spacing used in formating
const char dataFile[] = "EmployeeData.txt"; //file to read data from
const int union_dues = 5; //amount deducted from pay for the union
int main()
{
int number_entries = FindNumberEntries();
//array of employees
Employee * work_force = new Employee[number_entries];
//read in data
ReadData(work_force);
//prints the data
PrintData(work_force, number_entries);
//clean up memory
delete[] work_force;
return 0;
}
//finds the number of entries in the file
int FindNumberEntries()
{
int counter = 0;
//worker to read through file entries
Employee worker_temp;
ifstream input;
input.open(dataFile);
if (input.is_open())
{
while (!input.eof())
{
input >>
worker_temp.first_name >>
worker_temp.last_name >>
worker_temp.SSN >>
worker_temp.wage >>
worker_temp.hours >>
worker_temp.status;
cin.clear();
counter++;
}
input.close();
}
else
{
cout << "File could not be opened!" << endl;
}
return counter - 1;
}
//reads employee data from file
void ReadData(Employee work_force[])
{
ifstream input;
input.open(dataFile);
//reads in entries
if (input.is_open())
{
for (int i = 0; !input.eof(); i++)
{
//reads in employee data
input >>
work_force[i].first_name >>
work_force[i].last_name >>
work_force[i].SSN >>
work_force[i].wage >>
work_force[i].hours >>
work_force[i].status;
cin.clear();
}
input.close();
}
else
{
//error that file could not open
cout << "File could not be opened!" << endl;
}
}
//calculates straight pay
float CalculateStarightPay(Employee worker)
{
//determines of worker is fulltime or not
if (worker.status == 'F')
{
if (worker.hours > 40)
{
return ((worker.wage * 40) - 5);
}
else
{
return (worker.wage * worker.hours) - union_dues;
}
}
else
{
if (worker.hours > 40)
{
return (worker.wage * 40);
}
else
{
return worker.wage * worker.hours;
}
}
}
//calculate overtime pay
float CalculateOvertimePay(Employee worker)
{
//deermines if there are any overtime hours
if (worker.hours <= 40)
{
return 0;
}
else
{
//calculates overtime pay
return ((worker.hours - 40) * (worker.wage * 1.5));
}
}
//prints employee data in a well formated manner
void PrintData(Employee work_force[], int number_entries)
{
delete work_force;
float straight_pay = 0.0F;
float Overtime_pay = 0.0F;
char name[32] = { '\0' };
//print headers
cout << left <<
setw(SPACING) << "Name" <<
setw(SPACING) << "SSN" <<
setw(SPACING) << "Hourly Wage" <<
setw(SPACING) << "Hours Worked" <<
setw(SPACING) << "Straight Pay" <<
setw(SPACING) << "Overtime Pay" <<
setw(SPACING) << "Status" <<
setw(SPACING) << "Net Pay" << endl;
//prints data for each EMPLOYEE
for (int i = 0; i < number_entries; i++)
{
straight_pay = CalculateStarightPay(work_force[i]);
Overtime_pay = CalculateOvertimePay(work_force[i]);
//adds a space after first name
work_force[i].first_name[strlen(work_force[i].first_name) + 1] = '\0';
work_force[i].first_name[strlen(work_force[i].first_name)] = ' ';
//puts last name and first name together
strcpy(name, strcat(work_force[i].first_name, work_force[i].last_name));
//prints out all the data in a nic eformat
cout << fixed << setprecision(2) <<
setw(SPACING ) << name <<
setw(SPACING) << work_force[i].SSN << '$' <<
setw(SPACING) << work_force[i].wage <<
setw(SPACING) << work_force[i].hours << '$' <<
setw(SPACING) << straight_pay << '$' <<
setw(SPACING) << Overtime_pay <<
setw(SPACING) << work_force[i].status << '$' <<
setw(SPACING) << (straight_pay + Overtime_pay) << endl;
}
}
Don't delete work_force; at the top of PrintData.
Use std::strings for your names and SSN. (Fixed length strings are a usability accident waiting to happen).
Use a std::vector<Employee>. The important thing is that this means you no longer have to use new (which is something you should always try and avoid). It also means that you only have to read the file once - you just read the entry, and then push it onto the vector with push_back.
When reading from an input stream, you need to try to read and then test the stream to see if you have hit eof. So the read function would look like:
while (input >>
worker_temp.first_name >>
worker_temp.last_name >>
worker_temp.SSN >>
worker_temp.wage >>
worker_temp.hours >>
worker_temp.status)
{
workforce.push_back(worker_temp);
}
Related
I am not sure how to connect a part of an array or if it is even possible.
My code is as follows:
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
string name;
string date[3];
double height[3];
double enter;
cout << "Enter name of a pole vaulter: ";
cin >> name;
cout << "Enter date of first vault: ";
cin >> date[0];
cout << "Enter height of first vault: ";
cin >> enter;
if (enter >= 2.0)
{
if (enter <= 5.0)
{
height[0] = enter;
}
else
{
cout << "Incorrect Value";
abort();
}
}
else
{
cout << "Incorrect Value";
abort();
}
cout << "Enter date of second vault: ";
cin >> date[1];
cout << "Enter height of second vault: ";
cin >> enter;
if (enter >= 2.0)
{
if (enter <= 5.0)
{
height[1] = enter;
}
else
{
cout << "Incorrect Value";
abort();
}
}
else
{
cout << "Incorrect Value";
abort();
}
cout << "Enter date of third vault: ";
cin >> date[2];
cout << "Enter height of third vault: ";
cin >> enter;
if (enter >= 2.0)
{
if (enter <= 5.0)
{
height[2] = enter;
}
else
{
cout << "Incorrect Value";
abort();
}
}
else
{
cout << "Incorrect Value";
abort();
}
int len = sizeof(height) / sizeof(height[0]);
sort(height, height + len, greater<int>());
cout << "Stats for " << name << ":" << endl;
for (int i = 0; i < len; i++) {
cout << height[i] << " ";
}
cout << height[0];
}
I am trying to enter dates and a double value, and then organize the double values in descending order and keep the dates with the corresponding value. I am not sure if this is possible, any alternative way of completing this would be helpful.
Thank you
Group of data, data sorting, multiple data points that should be aligned/connected to their respective other data points. I think the best solution here would be the use of a struct or class with vectors:
Let's say you want a variable that contains both your date and number. We can construct a class or structure for that:
#include <iostream>
using namespace std;
struct str1
{
string date;
double number;
};
class cls1
{
public:
string date;
double number;
};
int main()
{
str1 ob1;
cls1 ob2;
ob1.date = "somedate";
ob1.number = 12345;
cin >> ob1.date;
cout << ob1.date << " " << ob1.number << endl;
ob2.date = "somedate2";
ob2.number = 54321;
cin >> ob2.number;
cout << ob2.date << " " << ob2.number << endl;
return 0;
}
Having a class or struct enables you to use objects (variables made from those structs or classes). Every object created has their own place in memory for storing both date and number. You can use, find, search any of these variables and have access to both values this way.
Grouping them up so there's a list of them can be done in vectors.
Vectors are like better arrays. They not only have a dynamical size (meaning its size can change and doesnt stay static like in arrays), but they also have quite a bit ready made functions for you to use:
bool sortingFunction(int &a, int &b)
{
if (a > b) return true;
else return false;
}
int main2()
{
vector<int> numbers;
//to add
numbers.emplace_back(5); //5 is the number to add
//to remove
numbers.erase(numbers.begin() + 2); //2 is the index of the variable to delete
//to sort
sort(numbers.begin(), numbers.end(), sortingFunction);
return 0;
}
Vectors need the #include <vector> header.
Sort is a function that sorts. Needs #include <algorithm> header.
Sort function is neat because you can define the logic behind how you want to sort the vector or array with a seperate function that returns either true or false.
For your example you could do something like this in the end:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct myType
{
string date;
double number;
};
bool sortByDate(myType &a, myType &b)
{
if (a.date > b.date) return true;
else return false;
}
bool sortByNumber(myType &a, myType &b)
{
if (a.number > b.number) return true;
else return false;
}
int main()
{
vector<myType> variables;
int num;
cout << "how many do you want to add" << endl;
cin >> num;
for(int i = 0; i < num; i++)
{
myType tmp;
cout << "Enter date of var" << i+1 << ": ";
cin >> tmp.date;
cout << "Enter number of var" << i+1 << ": ";
cin >> tmp.number;
variables.emplace_back(tmp);
}
//after that you can use the vector as you want...
//sort
sort(variables.begin(), variables.end(), sortByDate);
sort(variables.begin(), variables.end(), sortByNumber);
//delete
variables.erase(variables.begin()+5);
//or clear the entire thing
variables.clear();
//Either way each item in the vector consists of both number and date thus even
//if you sort the vector the values are still connected at the same position
return 0;
}
I know this program is long, but any help would be much appreciated. When I try to read in an object from a file, I always end up with a segmentation fault. I've commented the line where the problem is. It's under 'case d' in the switch statement.
The objects I'm writing out the text file is polymorphic, which might be part of why I'm getting segmentation faults, but I'm not sure.
#include <iostream>
#include <string.h>
#include <vector>
#include <unistd.h>
#include <fstream>
#include "employee.h"
int main(int argc, char* argv[])
{
std::string command, choice, name;
float wage, percent;
int hours = 1;
std::ofstream file;
std::ifstream infile;
std::vector<Employee*> database;
while (command[0] != 'q')
{
clear();
menu();
std::cout << "Enter command: ";
std::cin >> command;
try
{
if(command.size() != 1)
throw "Not a character.";
else
{
switch(command[0])
{
case 'n':
std::cout << "Enter the name of the new employee: ";
//std::cin >> name;
std::cin.clear();
std::cin.ignore();
getline(std::cin, name);
std::cout << "Hourly (h) or salaried (s): ";
std::cin >> choice;
if(choice.size() != 1)
throw "Not a valid choice.";
else
if(choice == "h")
{
std::cout << "Enter hourly wage: ";
std::cin >> wage;
if(!wage)
throw "Not an option";
else{
Employee *emp = new PartTimeEmployee(wage, name);
database.push_back(emp);
continueWithProgram();
break;
}
}else if(choice == "s")
{
std::cout << "Enter salaried wage: ";
std::cin >> wage;
if(!wage)
throw "Not an option";
else{
Employee *emp = new FullTimeEmployee(wage, name);
database.push_back(emp);
continueWithProgram();
break;
}
}else{
throw "Not an option";
}
case 'c':
if(database.size() < 1)
throw "No employees in database.";
else
{
for(int i = 0; i < database.size(); i++)
{
std::cout << "Enter number of hours worked by " << database[i]->getName() << ": ";
std::cin >> hours;
std::cout << "Pay: $" << database[i]->computePay(hours) << std::endl;
}
continueWithProgram();
}
break;
case 'r':
std::cout << "Enter percentage to increase: ";
std::cin >> percent;
std::cout << "\nNew Wages\n---------" << std::endl;
for(int i = 0; i < database.size(); i++)
{
database[i]->raiseWage(percent);
std::cout << database[i]->getName() << "\t\t" << "$" << database[i]->toString(database[i]->getWage()) << std::endl;
}
continueWithProgram();
break;
case 'p':
std::cout << "\nEmployee Database: " << database[0]->count << " Personnel\n-----------------\n";
for(int i = 0; i < database.size(); i++)
{
std::cout << database[i]->getName() << std::endl;
}
continueWithProgram();
break;
case 'd':
infile.open("emp.txt", std::ios::in);
Employee *temp;
if(infile.is_open())
{
while(!infile.eof())
{
infile >> *temp; // PROBLEM IS HERE...
database.push_back(temp);
}
}else{
std::cout << "Error occured. File not found." << std::endl;
}
infile.close();
std::cout << "*Data has been downloaded*" << std::endl;
continueWithProgram();
break;
case 'u':
file.open("emp.txt", std::ios::trunc);
if(file.is_open()){
for(int i = 0; i < database.size(); i++)
file << *database[i];
}
file.close();
std::cout << "*Data has been uploaded*\n";
continueWithProgram();
break;
default:
if(command[0] == 'q')
break;
else
{
throw "Not a command";
break;
}
}
}
}catch(const char* message)
{
std::cout << message << std::endl;
std::cin.clear();
std::cin.ignore();
continueWithProgram();
}
catch(...)
{
std::cout << "Error occured." << std::endl;
std::cin.clear();
std::cin.ignore();
continueWithProgram();
}
}
return 0;
}
______________________________________________________-
Header File:
*This is where the operator overload is, which I'm sure is not part of the problem.
#include <iostream>
#include <fstream>
#include <string.h>
#include <vector>
#include <unistd.h>
class Employee
{
protected:
float wage;
std::string name;
public:
static int count;
Employee(float wage, std::string name)
{
this->wage = wage;
this->name = name;
count++;
}
virtual float getWage() = 0;
virtual void setWage(float wage) = 0;
virtual float computePay(int hours = 0) = 0;
virtual float raiseWage(float percent = 0) = 0;
virtual std::string toString(int value) = 0;
std::string getName(){return name;}
void setName(std::string name){this->name = name;}
friend std::ofstream& operator<<(std::ofstream &out, Employee &emp);
friend std::ifstream& operator>>(std::ifstream &in, Employee &emp);
};
class FullTimeEmployee : public Employee
{
public:
FullTimeEmployee(float annualSalary, std::string name) : Employee(annualSalary, name)
{
getWage();
}
float getWage() {return wage;}
void setWage(float wage) {this->wage = wage;}
float computePay(int hours = 0) {return (wage / 52);}
std::string toString(int value){return std::to_string(value) + "/year";}
float raiseWage(float percent = 0)
{
wage = wage + (wage * (percent / 100));
return wage;
}
};
class PartTimeEmployee : public Employee
{
public:
PartTimeEmployee(float wage, std::string name) : Employee(wage, name)
{
getWage();
}
float getWage() {return wage;}
void setWage(float wage) {this->wage = wage;}
std::string toString(int value){return std::to_string(value) + "/hour";}
float computePay(int hours)
{
if(hours <= 40)
return wage * hours;
else
{
hours -= 40;
return ((wage * 40) + ((wage * 1.5) * hours));
}
}
float raiseWage(float percent = 0)
{
wage = wage + (wage * (percent / 100));
return wage;
}
};
std::ofstream& operator<<(std::ofstream &out, Employee &emp)
{
out << emp.name << std::endl << emp.wage << std::endl;
return out;
}
std::ifstream& operator>>(std::ifstream &in, Employee &emp)
{
in >> emp.name;
in >> emp.wage;
return in;
}
int Employee::count = 0;
void menu()
{
std::cout << "-----------------------------------" << std::endl;
std::cout << "|Commmands: n - New Employee |" << std::endl;
std::cout << "| c - Compute Paychecks |" << std::endl;
std::cout << "| r - Raise Wages |" << std::endl;
std::cout << "| p - Print Records |" << std::endl;
std::cout << "| d - Download Data |" << std::endl;
std::cout << "| u - Upload Data |" << std::endl;
std::cout << "| q - Quit |" << std::endl;
std::cout << "-----------------------------------" << std::endl;
}
void clear() {std::cout << "\033[2J\033[1;1H";}
int continueWithProgram()
{
std::string anw;
while(anw[0] != 'y' || anw[0] != 'Y')
{
std::cout << "\nDo you want to continue?(y/n) ";
std::cin >> anw;
return 0;
if(anw.size() != 1)
{
throw "Not a character";
}else if (anw[0] == 'n' || anw[0] == 'N')
exit(0);
}
}
You must add subtype information (Ex: 'f' or 'p', denoting partime and fulltime) somewhere in your file-format. If you really want do deserialize a Pointer from the file you might change both operators.
(However I strongly recommend to use an other approach and fix memory leaks):
operator<< should first print an extra line consisting of just one character denoting the subtype of Employ that is serialized.
using PEmployee = *Employee;
std::ifstream& operator>>(std::ifstream &in, PEmployee &emp)
{
char subType;
float wage;
std::string name;
in >> subType;
in >> name; // FIXIT - we suspect file in not eof
in >> wage;
if(subType == 'f')
emp = new FullTimeEmploy(wage, name);
else
emp = new PartTimeEmploy(wage, name); // FIXIT: we suspect subType == 'p'
return in;
}
And in the while-Loop beneath case 'd': you should call the new operator by infile >> temp;
I hope this works and answers your question.
I do not recommend this approach, calling new as side-effect from an operator rises the question who (which part of the Prog) is responsible for cleaning up (i.e. calling delete). It might work in small Progs but usually it will results in a mess.
Memory leaks: If you use new and delete, be always aware where in Your Prog the allocated memory will be freed. It is not done by the Run-time environment, C++ is not a managed language. HINT: std::vector<Employee*> wont call delete on the stored pointers, it just frees its workload (Employee*). It's the pointer itself not the pointee, i.e. the Object you accuired with new .
PS:
A more straight forward aproach is to change only the operator<< and evaluate the subtype inside the while-Loop beneath case 'd': First read the subtype-char, switch subtype, create the according subclass (Ex: temp = new PartTimeEmployee(); and call the unchanged operator>> with the newly created temp.
For this approach you'll need standart Constructors like PartTimeEmployee::PartTimeEmployee(); for all your subclasses.
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.
The program works all the way up until it checks for the name the user enters. When you enter the name you wish to search for in the array of structures that have been imported from a file full of customer info) it comes back segmentation fault core dumped. This puzzles me.
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
using namespace std;
struct AccountsDataBase{
char name[50];
string email;
long int phone;
string address;
};
#define MAX 80
AccountsDataBase * account = new AccountsDataBase[MAX];
void readIn(ifstream& file){
int i=0;
while(!file.eof()){
file >> account[i].name >> account[i].email >> account[i].phone >> account[i].address;
}
}
void getAccount(){
char userPick[50];
char streamName[50];
cout << " What account will we be using? " << endl;
cin.getline(streamName, 50);
for(int i=0; strcmp(account[i].name, streamName)!=0; i++){
if( strcmp(account[i].name, streamName)==0){
cout << "\n\n FOUND IT!! \n\n";
cout << account[i].name << "\n" << account[i].email << "\n" << account[i].phone << "\n" << account[i].address << endl;
}
}
}
int main(){
ifstream file;
file.open("2.dat"); //opens data account records text
readIn(file);
getAccount();
delete account;
return 0;
}
Your loop keeps reading everything into the initial element of the array:
while(!file.eof()){
file >> account[i].name >> account[i].email >> account[i].phone >> account[i].address;
}
because the value of i is never incremented. You can convert this to a for loop, like this:
for (count = 0 ; count < MAX && !file.eof() ; count++) {
file >> account[count].name >> account[count].email >> account[count].phone >> account[count].address;
}
Note that I changed i to count:
AccountsDataBase * account = new AccountsDataBase[MAX];
int count = 0;
This will help you solve another problem - determining when the array ends in the getAccount function. Currently, you assume that the record is always there, so the outer loop keeps going on. Now that you have count, you could change the loop like this:
for(int i=0; i < count && strcmp(account[i].name, streamName)!=0; i++){
if( strcmp(account[i].name, streamName)==0){
cout << "\n\n FOUND IT!! \n\n";
cout << account[i].name << "\n" << account[i].email << "\n" << account[i].phone << "\n" << account[i].address << endl;
break;
}
}
if (i == count) {
cout << "Not found." << endl;
}
Entire question :
Question 3
You are the owner of a hardware store and need to keep an inventory that can tell you what different tools you have, how many of each you have on hand and the cost of each one. Write a program that initializes the random-access file "hardware.dat" to 100 empty records, let you input the data concerning each tool, enables you to list all your tools, lets you delete a record for a tool that you no longer have and lets you update any information in the file. The tool identification number should be the record number. Use the following information to start your file.
My Code :
int question_3()
{
cout << "Question 3" << endl;
fstream hardware;
hardware.open("hardware.dat" , ios::binary | ios::out);
//Create 100 blank objects---------------------------------------------------------------
if (!hardware)
{
cerr << "File could not be opened." << endl;
exit(1);
}
HardwareData myHardwareData;
for (int counter = 1; counter <= 100; counter++)
{
hardware.write(reinterpret_cast< const char * >(&myHardwareData), sizeof(HardwareData));
}
cout << "Successfully create 100 blank objects and write them into the file." << endl;
hardware.close();
hardware.open("hardware.dat" , ios::binary | ios::out | ios::in);
//Write data-----------------------------------------------------------------------------
int record;
int quantity;
float cost;
string tool_name;
cout << endl;
cout << "Enter record number (1 to 100, 0 to end input) : ";
cin >> record;
while (record != 0)
{
cin.sync();
cout << "Enter tool name : "; getline(cin, tool_name);
cout << "Enter quantity : "; cin >> quantity;
cout << "Enter cost : "; cin >> cost;
myHardwareData.setRecord(record);
myHardwareData.setToolName(tool_name);
myHardwareData.setQuantity(quantity);
myHardwareData.setCost(cost);
hardware.seekp((myHardwareData.getRecord() - 1) * sizeof(HardwareData));
hardware.write(reinterpret_cast<const char *>(&myHardwareData), sizeof(HardwareData));
cout << endl
<< "Enter record number (1 to 100, 0 to end input) : ";
cin >> record;
}
cout << "Successfully write all input data into the file." << endl;
//Read data----------------------------------------------------------------------------
cout << endl;
outputDataLineHead();
hardware.read(reinterpret_cast<char *>(&myHardwareData), sizeof(HardwareData));
int counter = 0;
cout << setprecision(2) << fixed;
while (hardware && !hardware.eof())
{
if (myHardwareData.getRecord() != 0)
outputDataLine(cout, myHardwareData);
hardware.seekp(counter++ * sizeof(HardwareData));
hardware.read(reinterpret_cast<char *>(&myHardwareData), sizeof(HardwareData));
}
return 0;
}
//Function for showing data in line form.-----------------------------------------------
void outputDataLineHead()
{
cout << left << setw(17) << "Record No."
<< left << setw(17) << "Tool Name"
<< left << setw(17) << "Quantity"
<< left << setw(17) << "Cost" << endl;
}
void outputDataLine(ostream &output, const HardwareData &Object_in_file)
{
output << left << setw(17) << Object_in_file.getRecord()
<< left << setw(17) << Object_in_file.getToolName()
<< left << setw(17) << Object_in_file.getQuantity()
<< left << setw(17) << Object_in_file.getCost() << endl;
}
HardwareData.h :
#ifndef HAREWAREDATA_H
#define HAREWAREDATA_H
#include <iostream>
using std::string;
class HardwareData
{
public :
HardwareData(string name = "", int recd = 0, int qutity = 0, float cot = 0.0)
{
setToolName(name);
setRecord(recd);
setQuantity(qutity);
setCost(cot);
}
void setToolName(string name)
{
const char *nameValue = name.data();
int length = 0;
length = (length < 15 ? length : 14);
strncpy(tool_name, nameValue, length);
tool_name[length] = '\n';
}
string getToolName() const
{
return tool_name;
}
void setRecord(int recd)
{
record = recd;
}
int getRecord() const
{
return record;
}
void setQuantity(int qutity)
{
quantity = qutity;
}
int getQuantity() const
{
return quantity;
}
void setCost(float cot)
{
cost = cot;
}
float getCost() const
{
return cost;
}
private :
char tool_name[15];
int record;
int quantity;
float cost;
};
#endif
I want to show the data like the following :
Record No. Tool Name Quantity Cost
4 electric hammer 3 34.32
How to achieve this?
Thank you for your attention.
I think your problem is while reading data.. Please check your variables if they get correct data or not.. You can check this with counting characters or try to printf them.
If they are not correct. You can use such an example which i used in below.
First of all i prefer you to read your line like this example ;
In this example i get coordinates of faces. You should change parameters.. In order not to read no need data
std::string str;
while(std::getline(in, str))
{
sscanf(str.c_str(), "%d %f %f", &fiducial.number, &fiducial.x, &fiducial.y);
coord_Num[fiducial.number] = fiducial.get_number();
coord_X[fiducial.number] = fiducial.get_x();
coord_Y[fiducial.number] = fiducial.get_y();
}
If everything looks fine. You should check
void outputDataLine(ostream &output, const HardwareData &Object_in_file)
The core issue here is that you're reading and writing bytes to/from objects of type HardwareData when rather you should be creating inserters/extractors so you can implement correct I/O semantics. For example:
// Inside HardwareData class
friend std::ostream& operator<<(std::ostream&, const HardwareData&);
friend std::istream& operator>>(std::istream&, HardwareData&);
These two declarations are for the inserter and extractor respectively. Input should consist of extracting into the record, tool_name, quantity and cost data members; and output should simply be an stream insertion which is trivial to implement.
It is often the problem when mixing formatted input with unformatted input that the residual newline inhibits further input. That seems to be the case here:
cin >> record; /*
^^^^^^^^^^^^^^ */
while (record != 0)
{
cin.sync();
cout << "Enter tool name : "; getline(cin, tool_name);
// ^^^^^^^^^^^^^^^^^^^^^^^^
// ...
}
After cin >> record; finishes, there will be a newline left inside the stream. That newline will stop std::getline() from working correctly because std::getline() only reads until the newline.
The fix here is to ignore this new line by using the std::ws manipulator:
std::getline(std::cin >> std::ws, tool_name);
// ^^^^^^^^^^^^^^^^^^^
Note: I talk about this in more detail here.
But this manual extraction isn't needed as we've already defined the inserter and extractor for our class. So all that's really needed is the following:
while (std::cin >> myHardwareData)
{
hardware << myHardwareData;
}
or
std::copy(std::istream_iterator<HardwareData>(std::cin),
std::istream_iterator<HardwareData>(),
std::ostream_iterator<HardwareData>(hardware));
Noticed how I've also taken out the check for a 0 value of record in the while loop. That's because the extractor takes care of it by reflecting a 0 value of record as invalid input. It sets the stream state of the stream if this occurs, thus allowing ourselves to be ejected from the while if that happens:
std::istream& operator>>(std::istream& is, HardwareData& hd)
{
cout << "Enter record number (1 to 100, 0 to end input) : ";
if ((is >> record) && record != 0)
{
// ...
} else
{
is.setstate(std::ios_base::failbit);
}
// ...
}
And the rest of your code be changed to:
std::cout << myHardwareData;
hardware >> myHardwareData;
std::cout << std::setprecision(2) << std::fixed;
while (hardware >> myHardwareData)
{
if (myHardwareData.getRecord() != 0)
std::cout << myHardwareData;
}
I don't really know what the seekps are for. If you elaborate on that, that would really help me adapt my code more accurately to your needs.