Load functions using a case switch statement - c++

I'm writing a program in C++ and I've been able to get it to compile and start to run how ever when I choose an option the coresponding function that is supposed to be called by a switch-case statement isn't called. Am I missing something in my code?
//The following program framework is given.
//Add the programming logic to complete the assignment.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
//function prototypes should be placed here
//Main must be the first function in the program. Write other functions after it.
int main()
{
char cInput;
string strFileName;
vector<string> vecStudent;
cout<<"Please enter the data file name (with location): ";
cin >> strFileName;
//call a function to read the content of the input file into
//the vector vecStudent
while (true)
{
cout<<"----------------------------------------"<<endl;
cout<<" Student Record - Main Menu "<<endl;
cout<<"----------------------------------------"<<endl;
cout<<" Enter 1 to display ALL students"<<endl;
cout<<" Enter 2 to add a student name"<<endl;
cout<<" Enter 3 to delete a student name"<<endl;
cout<<" Enter 4 to SAVE and quit the program"<<endl;
cout<<"----------------------------------------"<<endl;
cout<<"Enter menu option: ";
cin>>cInput;
switch (cInput)
{
case '1':
//call function display names
void displaynames();
break;
case '2':
void addname();
//call a function add name
break;
case '3':
void deletename();
//call function delete names
break;
case '4':
void saveandquit();
//call function save and quit
return 0;
if( cInput != 1,2,3,4)
cout<<"invalid input"<<endl;
break;
}
}
return 0;
}
int displaynames()
{
ifstream inFile;
ofstream outFile;
string strFileName;
string strFName,strLName;
vector<string> vecStudent;
char line[80];
// open input file
inFile.open(strFileName.c_str());
if (inFile.fail())
{
cout << " Input file error!" << endl;
return -1;
}
while (inFile>>strFName>>strLName)
vecStudent.push_back(strFName+ " "+strLName);
inFile.close();
//display the content of the vector
for(int i =0; i< vecStudent.size();i++)
cout<<vecStudent[i]<<endl;
return 0;
}
int addname()
{
ifstream inFile;
ofstream outFile;
string strFileName;
string strFName,strLName;
vector<string> vecStudent;
char line[80];
//add a new name
cout << endl<< " Enter a new name( First and Last Name):";
cin>>strFName>>strLName;
vecStudent.push_back(strFName+ " "+strLName);
// open output file for writing
outFile.open(strFileName.c_str());
if ( outFile.fail())
{
cout<<" Output file error! Student was not added"<<endl;
return -1;
}
//display the content of the vector
for(int i=0; i<vecStudent.size(); i++)
cout<< vecStudent[i]<<endl;
for(int i=0; i<vecStudent.size();i++)
outFile<<vecStudent[i]<<endl;
outFile.close();
return 0;
}
int saveandquit()
{
ifstream inFile;
ofstream outFile;
string strFileName;
string strFName,strLName;
vector<string> vecStudent;
int i=0;
char line[80];
// open output file for writing
outFile.open(strFileName.c_str());
if ( outFile.fail())
{
cout<<" Output file error!"<<endl;
return -1;
}
//display the content of the vector
for(int i=0; i<vecStudent.size(); i++)
cout<< vecStudent[i]<<endl;
for(int i=0; i<vecStudent.size();i++)
outFile<<vecStudent[i]<<endl;
outFile.close();
cout << " file saved. enter -1 to quit";
cin>> i;
if( i=-1)
return 0;
}
int deletename()
{
ifstream inFile;
ofstream outFile;
string strFileName;
string strFName,strLName;
vector<string> vecStudent;
int namepos = 0;
char line[80];
inFile.open(strFileName.c_str());
if (inFile.fail())
cout <<"Input file error!"<<endl;
//read the names from the file into the vector
while (inFile >> strFName >> strLName)
vecStudent.push_back(strFName+" "+strLName);
inFile.close();
cout <<"\nEnter the name to be deleted (First name and Last name): ";
cin >>strFName >>strLName;
int i=0, pos=-1;
int size = vecStudent.size();
bool found=false;
// use a linear search to find the name in the vecotor of names
while (i < size && !found)
{
if (vecStudent [i] == strFName+" "+strLName)
{
found = true;
cout <<"\nthat name is in the "<<(pos + 1) <<" position in the list\n";
cout <<"Please enter the position in list\n";
cin>> pos;
// use an iterator to delete name from vecStudent. vector.erase requires an iterator. used a while loop to find the name and make sure it was in the
// vector of strings. then the loop displays the position in the vector that the string is. the program asks the user to enter the number position of the name
// from there the user enters the name and the program uses a for loop to find the position and the built in vector.erase to remove the name from the list.
for(int i=0; i ==pos; i++)
{
if(i == pos)
{
vecStudent.erase (vecStudent.begin());
}
}
}
}
return 0;
}

You are actually just declaring functions instead of calling them.
void displaynames();
Declares a function.
displaynames();
Calls a function.

You are calling the functions wrong. It should be
case '1':
//call function display names
displaynames();
break;
case '2':
addname();
//call a function add name
break;
case '3':
deletename();
//call function delete names
break;
case '4':
saveandquit();
To call a function, you just need the function name and the function parameters (which in this case, seem to be none. The way you currently have it is declaring a function rather than calling a function.

In your code block (switch), you're not calling any functions, but rather just declaring them.
...
case '1':
//call function display names
void displaynames();
break;
...
Move the (forward) declarations (void displaynames();) to the top level of your source file (as you're defining the functions after using them), and then call them using the normal function application syntax (displaynames();).
From somewhere on the net:
"A declaration for a function is also called a prototype and it
informs the compiler of your intent to define and to use it. A
definition for a function is the body (code) associated with the
prototype."

Related

Problem while reading objects from file in c++

I am doing a small college project where I have to add, edit and search records in/from file using OOP concept. Adding into file is working fine but whenever I try to read from file it is printing in unreadable texts.
Here is full code and output.
main.cpp
#include <iostream>
#include <cstdlib>
#include <fstream>
#define MIN 20
#define MAX 100
#include "student.h"
using namespace std;
void add_student();
void edit_student();
void search_student();
void addToFile(const Student&);
Student* fetchFromFile();
int getFileSize();
void updateFile(Student*);
// Student stud[MAX];
int main()
{
int choice;
system("cls");
system("Color B0");
while(1)
{
cout<<"\n\t\tWhat do you want to do?"<<endl;
cout<<"\t\t----------------------"<<endl;
cout<<"\t\t1-Add student"<<endl;
cout<<"\t\t2-Edit student"<<endl;
cout<<"\t\t3-Search student"<<endl;
cout<<"\t\t4-Quit Program"<<endl;
cout<<"\t\t----------------------"<<endl;
cout<<"Enter your choice: ";
cin>>choice;
switch(choice)
{
case 1:
add_student(); //calling add_student function to add records.
break;
case 2:
edit_student();
break;
case 3:
search_student();
break;
case 4:
return 0;
break;
default:
cout<<"Invalid choice";
break;
}
}
return 0;
}
int Student::id = getFileSize() - 1; //Initialize id equals to size of file
// setData function of class Student definition
void Student :: setData()
{
// taking input from user
cout<<"Enter student roll no in format(1XXX): ";
cin>>roll;
cout<<"Enter student name: ";
cin>>name;
cout<<"Enter stduent date of birth(dd/mm/yy): ";
cin>>dob;
cout<<"Enter stduent phone no: ";
cin>>phone;
cout<<"Enter student address: ";
cin>>address;
stdId = Student::id;
}
void Student :: showData()
{
cout<<stdId<<" ";
cout<<roll<<" ";
cout<<name<<" ";
cout<<dob<<"\t";
cout<<phone<<" ";
cout<<address<<"\n\n";
}
const int Student :: getRoll()
{
return roll;
}
Student& Student::operator = (const Student& newObj)
{
stdId = newObj.stdId;
roll = newObj.roll;
name = newObj.name;
dob = newObj.dob;
phone = newObj.phone;
address = newObj.address;
return *this;
}
void add_student()
{
Student stud;
Student::incrementId();
stud.setData();
addToFile(stud); //adding records to file
system("CLS");
cout<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------Student updated record Table---------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"DOB "<<"Phone no "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
Student* student = fetchFromFile(); //getting records from file in array of objects
int length = getFileSize(); //getting length of array of objects
for(int i=0; i<(length-1); i++)
{
student[i].showData(); //showing all the data
}
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------------FINISH-----------------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"You want to add more?(Y/n): ";
char c;
cin>>c;
if(c=='y' || c=='Y')
{
add_student();
}
else{
system("pause");
}
}
void edit_student(){
//Showing existing record first before editing
cout<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------Student Existing record Table---------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"DOB "<<"Phone no "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
Student* student = fetchFromFile(); //fetching all records from file
int length = getFileSize();
for(int i=0; i<(length-1); i++)
{
student[i].showData();
}
int idnumber;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"Which ID number your want to edit: ";
cin>>idnumber; //Asking the user at which ID he wants to make a change.
//checking for valid id number
if(idnumber>length || idnumber<0)
{
cout<<"\nInvalid ID Number."<<endl;
}
//showing existing information about that specific record
cout<<"\nExisted information about this record.\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"Father\tCell no. "<<"DOB "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
student[idnumber].showData();
cout<<"\n\nEnter new data for above shown record.\n\n";
student[idnumber].setData(); //Inputting data for that specific record.
updateFile(student);
cout<<"\n\nRecord updated successfully."<<endl;
cout<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------Updated record Table---------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"DOB "<<"Phone no "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
for(int i=0; i<(length-1); i++) //Showing updated record Table
{
student[i].showData();
}
}
void search_student(){
Student* student = fetchFromFile();
int fileLenth = getFileSize() - 1;
int searchkey;
cout<<"Enter roll_no of student you want to search: ";
cin>>searchkey; //roll_no as the search key can be entered by user.
for(int i=1; i<fileLenth; i++)
{
if(searchkey==student[i].getRoll()) //checking for roll no
{
student[i].showData();
}
}
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------------FINISH-----------------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
system("pause");
}
//FILE HANDLING
void addToFile(const Student& obj)
{
ofstream fout;
fout.open("records.txt", std::ofstream::app | std::ofstream::binary);
fout.write((char*)&obj, sizeof(obj));
cout<<"Added to file successfully!"<<endl;
fout.close();
}
Student* fetchFromFile()
{
int i=0;
Student obj;
Student* returnObj = new Student[MAX];
ifstream fin;
fin.open("records.txt", std::ifstream::binary);
while(!fin.eof())
{
fin.read((char*)&obj, sizeof(obj));
returnObj[i] = obj;
i++;
}
fin.close();
delete[] returnObj;
return returnObj;
}
int getFileSize()
{
int i=0;
Student obj;
ifstream fin;
fin.open("records.txt", std::ifstream::binary);
while(!fin.eof())
{
fin.read((char*)&obj, sizeof(obj));
i++;
}
fin.close();
return i;
}
void updateFile(Student* student)
{
ofstream fout;
fout.open("records.txt", std::ofstream::binary);
fout.write((char*)&student, sizeof(student));
fout.close();
}
student.h header file
// A student class that hold students attributes like id, name, address and class
// Object of this class will be craeted to store student details
class Student
{
int stdId;
int roll;
std::string name;
std::string dob;
std::string phone;
std::string address;
public:
static int id; //we will increase 'id' whenever student is added to the record
//Member functions declaration
void setData(); //this function will take input from user and set the data to attributes of class
void showData(); //This function will give student data to user when called
static void incrementId()
{
id++;
}
const int getRoll();
Student& operator = (const Student&);
};
Sample output 1
When I add a student object to file
Sample output 2
Reading all records from file
Problem1: Showing garbage value of id.
Sample output 3
Adding another object to file
Sample output 4
Reading all objects from file
Sample output 5
Now went back and chose to edit record
Problem2: See how the records are printing in unreadable form.
Why is this happening. Now if I close program and run it again then it is still showing in unreadable text.
Hope you get my issue. I want to have detailed explanation about this. Also, if I have done other miscellaneous mistakes, please let me know.
Thank you!
Student is too complicated to read with unformatted IO like read and write. In technical terms, it is not Trivially Copyable because it contain std::strings, and string is not Trivially Copyable.
The easiest thing to do is to abandon read and write. Most of your data is string data, so write << and >> overloads for Student and store everything as text.
friend std::ostream & operator<<(std::ostream & out,
const Student & stu)
{
out << stu.stdId << ',' <<stu.roll << ','<< stu.name... <<'\n';
return out;
}
Reading the data back in is a bit trickier
friend std::istream & operator>>(std::istream & in,
Student & stu)
{
std::string line;
if (std::getline(in, line))
{
std::stringstream strm(line);
if (!(strm >> stu.stdId >> comma >> stu.roll >> comma) ||
!std::getline(strm, stu.name, ',') ||
!std::getline(strm, stu.dob, ',') ||
...))
{ // If any read failed, mark the stream as failed so the caller knows.
out.setstate(std::ios_base::failbit);
}
}
return out;
}
First, a minor trick, add a empty constructor for class to initailial all members, integers{0}, and string{}, which will elminiate some unwanted gabages.
Student::Student() :stdId(0), roll(0), name{}, dob{}, phone{}, address{} {;}
Your major problem arised from the function fetchfomrfile() where you delete the fetched Student array, therefore the caller received a undefined data array:
Student* fetchFromFile()
{
int i=0;
Student obj;
Student* returnObj = new Student[MAX];
//reading records from file
fin.close();
delete[] returnObj;// <<<< youe deleted
return returnObj; // and return it as undefined
}
Since you are able to calculate the size of file, I suggest in the caller function:
void search_student(){
// Student* student = fetchFromFile();
Student *student = new Stduent [getFileSize()];
fecchFromFile(student); // use this array in fetch_file
// other things
}
Rewrite fetchFromFile as :
viod fetchFromFile(Stduent *ss)
{
// read file data to array ss[i];
}

Infinite loop in C++ why?

Im sorry about posting a super long code, but when I run this code all I see is this-
Heap size: 1638652
Getting int:
Getting int:
Getting int:
Getting int:
Getting int:
Heap size: 1638653
and it keeps going in a loop with the heapsize being incremented by one.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <exception>
#ifndef WX_REPORT_H
#define WX_REPORT_H
#include <string>
#include <sstream>
using std::string;
using std::stringstream;
typedef struct WX_REPORT
{
string unitType;
string stationName;
string time;
string gpsLoc;
int pressure;
int windSpeed;
int temperature;
int humidity;
int windDirection;
string toString()
{
stringstream str;
str << stationName << ": " << time << "\t" << gpsLoc << "\n";
str << pressure << "\n" << windSpeed << "\n" << temperature << "\n";
str << humidity << "\n" << windDirection;
return str.str();
}
}
WXReport;
#endif
/*
* Reports must be in the following format:
* M or I // Metric or imperial units
*/
using namespace std;
vector<WXReport*> heap;
bool compTime(const WXReport* a, const WXReport* b) {
if(a->time < b->time) { // timing
return false;
} else {
return true; // commands to return true
}
}
void heapAdd(WXReport* wx) {
heap.push_back(wx);
push_heap(heap.begin(), heap.end());
}
WXReport* heapPop() { // header popup
pop_heap(heap.begin(), heap.end());
WXReport* rep = heap.back();
heap.pop_back();
return rep;
}
void getInt(istream &input, int &i) {
string temp;
input>>temp;
cout<<"Getting int: "<<temp<<endl;
i = atoi(temp.c_str());
}
void readInFile(string filename) {
ifstream input(filename);
WXReport *report;
while(!input.eof()) {
report = new WXReport();
getline(input, report->unitType);
getline(input, report->stationName);
getline(input, report->time);
getline(input, report->gpsLoc);
getInt(input, report->pressure);
getInt(input, report->windSpeed);
getInt(input, report->temperature);
getInt(input, report->humidity);
getInt(input, report->windDirection);
heapAdd(report);
cout<<"Heap size: "<<heap.size()<<endl;
}
}
int menu() {
cout<<"\n\nPlease select one: "<<endl;
cout<<"1) Read in another file"<<endl;
cout<<"2) Display the fastest wind speed"<<endl;
cout<<"3) Display weather stations by name"<<endl;
cout<<"4) Display all weather reports"<<endl;
cout<<"5) Remove a weather report"<<endl;
cout<<"6) Write weather reports to file"<<endl;
cout<<"0) Exit"<<endl;
int choice;
cin>>choice;
return choice;
}
void printAllReports() {
cout<<"Printing all reports"<<endl;
for(WXReport* rep: heap) {
cout<<rep->toString()<<endl;
}
cout<<"Done printing reports"<<endl;
}
int main(int argc, char* argv[]) {
string filename = "report.txt";
readInFile(filename);
int choice = menu();
while(choice != 0) {
switch(choice) {
case 1:
cout<<"What file would you like to read in?"<<endl;
cin>>filename;
readInFile(filename);
break;
case 2:
cout<<"Has not been implemented"<<endl;
break;
case 3:
cout<<"Has not been implemented"<<endl;
break;
case 4:
printAllReports();
break;
case 5:
cout<<"Has not been implemented"<<endl;
break;
case 6:
cout<<"Has not been implemented"<<endl;
break;
default:
cout<<"Invalid choice, please try again."<<endl;
}
choice = menu();
}
cout<<"Thank you!"<<endl;
return 0;
}
Important part. If you read nothing else, read this: Always check the error codes and return values.
After ifstream input(filename); you have no idea if the file opened. Testing with input.is_open() gets past that.
If the file isn't open, all those calls to getline fail as does eof(). File not open, can't read end of file and can't exit loop. Even if the the file is open, if you don't check the output of getline, how do you know you read a line?
One of the fun parts of streams is if you test the stream, it tells you if it is in a bad state, so you can write code that looks like
if (getline(...) && getline(...) && ...)
So you don't have to make a massive block of if-else-if or a sea of nested ifs. First bad read and you are out.
The problem with if eof() is covered in the comments to the question. The basic is you don't know if you got the end of the file until you start reading. Also, what happen if you hit the end of the file in the middle of a bunch of reads?
So read a line. If it's good, read the next line, etc... until done.
getInt isn't necessary.
int val;
input >> val;
loads an integer into val, if the stream can be parsed into an int. If it can't, input is marked bad and you can check why. Could be unparsable. Could be end of file.
int val;
if (input >> val)
{
//do stuff
}
else
{
//no int here. Do other stuff
}
Just like above, you can chain the instructions and get
if (input >> val >> anotherval >> ...)

Output file overwriting incorrectly

This is just to go with my last question, someone asked me to upload the file so I'll cut out all the useless functions and have the main code especially that having to do with the output, this is my 3rd question on stack overflow so I still don't know much about how it works, if you want to answer please check my last (2nd) question for details. Here is the code:
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
const int MAX_SIZE = 1000;
struct Student
{
string studentID;
string firstName;
char midInitial;
string lastName;
};
void menu()
{
cout<<" CLASS ROSTER APPLICATION"<<endl;
cout<<"========================================="<<endl;
cout<<"ADD a student record..................[A]"<<endl;
cout<<"DELETE a student......................[D]"<<endl;
cout<<"EDIT a student record.................[E]"<<endl;
cout<<"INQUIRY about a student...............[I]"<<endl;
cout<<"LIST all students.....................[L]"<<endl;
cout<<"QUIT the system.......................[Q]"<<endl;
}
int linearSearch(const Student roster[], int numStuds, string sID)
{
int i;
for (i=0; i<numStuds; i++)
{
if (roster[i].studentID == sID)
return i;
}
return -1;
}
void selSort(Student roster[], int numStuds)
{
int minIDPos;
Student tempStudRecord;
int i,j;
for (i=0; i<numStuds-1; i++)
{
minIDPos = i;
for (j=i+1; j<numStuds; j++)
{
if (roster[j].studentID < roster[minIDPos].studentID)
minIDPos = j;
}
tempStudRecord = roster[i];
roster[i] = roster[minIDPos];
roster[minIDPos] = tempStudRecord;
}
}
void listStudents(const Student roster[], int numStuds)
{
cout<<"C L A S S R O S T E R"<<endl;
cout<<"Student ID # First Name M.I. Last Name"<<endl;
cout<<"---------------------------------------------"<<endl;
int i2=0; //just a counter.
while (i2<numStuds)
{
cout<<left;
cout<<setw(14)<<roster[i2].studentID<<setw(13)<<roster[i2].firstName;
cout<<roster[i2].midInitial<<". "<<roster[i2].lastName;
cout<<endl;
i2++;
}
cout<<right;
cout<<"---------------------------------------------"<<endl;
cout<<"Enrollment: "<<i2<<endl;
}
int main()
{
Student roster[MAX_SIZE];
fstream inFile;
fstream outFile;
string filename, sID;
Student newStudent;
int numStuds = 0;
char choice;
int i;
cout<<"Enter the name of the data file> ";
cin>>filename;
/** 7. open the data file for input **/
inFile.open(filename.c_str(), ios::in);
if (inFile)
{
/** 8. write a while loop to read the data from the file
into the roster array; the numStuds (number of Students)
must be updated as the records are read from the file.
Also, close the file after its contents are read into the
roster array.
**/
while (!inFile.eof() && numStuds < MAX_SIZE)
{
inFile>>roster[numStuds].studentID>>roster[numStuds].firstName;
inFile>>roster[numStuds].midInitial>>roster[numStuds].lastName;
numStuds++;
}
inFile.close();
}
do
{
cout<<endl;
menu();
cout<<endl;
cout<<"Select an option-> ";
cin>>choice;
cout<<endl;
switch(toupper(choice))
{
case 'A': cout<<"Enter the student ID #> ";
cin>>newStudent.studentID;
cout<<"Enter the student's first name> ";
cin>>newStudent.firstName;
cout<<"Enter the student's middle initial> ";
cin>>newStudent.midInitial;
cout<<"Enter the student's last name> ";
cin>>newStudent.lastName;
addStudent(roster,numStuds,newStudent);
break;
case 'D': /** 9. write code here to remove a student from the roster **/
cout<<"Enter the student ID Number: ";
cin>>sID;
deleteStudent(roster, numStuds, sID);
break;
case 'E': /** 10. write code to edit the record for a student with a specified ID # **/
cout<<"Enter the student ID Number: ";
cin>>sID;
editStudent(roster, numStuds, sID);
break;
case 'I': /** 11. write code to perform an inquiry (obtain full name) on a student with
with a specified ID # **/
cout<<"Enter the student ID Number: ";
cin>>sID;
studentInquiry(roster, numStuds, sID);
break;
case 'L': /** 12. write code to sort and then generate class roster **/
selSort(roster, numStuds);
listStudents(roster, numStuds);
break;
case 'Q': break;
default: cout<<"Invalid menu choice...try again!"<<endl;
}
}while(toupper(choice) != 'Q');
/** 13. open the data file in output mode and error-check to ensure
that it was successfully opened.
**/
outFile.open(filename.c_str(), ios::out);
if (!outFile)
{
cout<<"Unable to open "<<filename<<" for output. "<<endl;
return -1;
}
/** 14. overwrite the data file in the order:
student ID, firstname, middle initial and last name, one record per line.
make sure that you have spaces between the fields.
**/
for (i=0;i<numStuds;i++)
{
outFile<<roster[i].studentID<<" "<<roster[i].firstName<<" ";
outFile<<roster[i].midInitial<<" "<<roster[i].lastName<<endl;
}
/** 15. close the output file **/
outFile.close();
return 0;
}
This here
while (!inFile.eof() && numStuds < MAX_SIZE) {
inFile >> roster[numStuds].studentID >> roster[numStuds].firstName;
inFile >> roster[numStuds].midInitial >> roster[numStuds].lastName;
numStuds++;
}
Will leave the value of numStuds one higher than it should be, as inFile.eof() will only return true once the end of file has been reached, which won't occur until you have actually tried to read past the end of the file.
One way of fixing it would be to change it to
while (numStuds < MAX_SIZE &&
(inFile >> roster[numStuds].studentID >> roster[numStuds].firstName >>
roster[numStuds].midInitial >> roster[numStuds].lastName)
) {
numStuds++;
}
Although you're better off defining a function that reads the struct for you
std::istream& operator>>(std::istream& stream, Student& student)
{
stream >> student.studentID >> student.firstName
>> student.midInitial >> student.lastName;
return stream;
}
Which will work as follows:
while (inFile >> roster[numStuds]) {
numStuds++;
}
As suggested by #JoachimPileborg the following would be even better (once operator>> is defined for your struct):
std::vector<Student> roster;
//...
std::copy(
std::istream_iterator<Student>(inFile),
std::istream_iterator<Student>(),
std::back_inserter(roster)
);

String not returning to main function

I have just started with c++ and this is for a project that I'm working on. The problem is that I am not able to return a string from the SearchFunction to main. The search function itself is working perfectly and easily finding and displaying the row its supposed to find but the string temp remains empty despite me returning a string from Search Function. As a result, the DeleteFunction is not working because its not being passed the string that it's supposed to delete.
I have tried using pointers instead of returning value but still the result is same. Please help me understand where I'm going wrong.
#include<iostream>
#include<stdio.h>
#include<string>
#include<fstream>
using namespace std;
string data,temp;
string SearchFunction(string);
void DeleteFunction(string);
int main()
{
int choice=0,choice3=0;
char yn1;
string search;
cout<<"1. Press 1 to delete."<<endl;
cin>>choice;
cin.clear();
cin.ignore(1000,'\n');
if(choice==1)
{
cout<<"Enter RegNo. of record to be deleted: ";
getline(cin,search);
search="RegNo.: "+ search; //Concatenate with "RegNo: " to ensure that the search is done "by RegNo".
temp=SearchFunction(search);
cout<<"1. "<<temp<<"\n\n";
cout<<temp.length()<<endl;
cout<<"Are you sure you want to delete the above record of"<<search<<"? Y/N";
yn1=getchar();
cin.clear();
cin.ignore(1000,'\n');
if(!(yn1=='y' || yn1=='Y' || yn1=='n' || yn1=='N'))
{
do
{
cout<<"Enter 'Y' or 'N': ";
yn1=getchar();
}while(!(yn1=='y' || yn1=='Y' || yn1=='n' || yn1=='N'));
}
if(yn1=='y' || yn1=='Y')
{
DeleteFunction(temp); //Call delete function to delete record.
}
}
return 0;
}
string SearchFunction(string search)
{
int found=0, check=0; //Declare and initialize both variables to 0.
ifstream outfile; //Create object for reading file.
outfile.open("student.txt"); //Open file.
while(!outfile.eof()) //Continue loop until the end of file.
{
found=0, check=0; //Initialize both variables to 0 again in anticipation of repititions.
getline(outfile, data); //Input one row from file to string variable data.
found=data.find(search, found); //Search for the search term in string data.
if(found!=string::npos) //If search term found.
{
cout<<data<<endl; //Display row.
}
}
outfile.close();
return data;
}
void DeleteFunction(string temp)
{
string line;
ifstream in("student.txt");
if( !in.is_open())
{
cout << "Input file failed to open\n";
}
ofstream out("temp.txt");
while( getline(in,line) )
{
if(line != temp )
out << line << "\n";
}
in.close();
out.close();
remove("student.txt");
rename("temp.txt","student.txt");
}
You have stop reading the file after you found the row you are looking for. Maybe you want to change the function to:
string SearchFunction(string search)
{
int found=0, check=0; //Declare and initialize both variables to 0.
ifstream outfile; //Create object for reading file.
outfile.open("student.txt"); //Open file.
// Also check if found!!!
while(!outfile.eof() && !found) //Continue loop until the end of file.
{
found=0, check=0; //Initialize both variables to 0 again in anticipation of repititions.
getline(outfile, data); //Input one row from file to string variable data.
found=data.find(search, found); //Search for the search term in string data.
if(found!=string::npos) //If search term found.
{
cout<<data<<endl; //Display row.
}
}
outfile.close();
return data;
}
You need to break out of the while loop when you've found your data. A simple way is to just return at that point.
Don't use globals unless you have some very good reason. Globals used as scratch-pad variables, as above, are just Evilâ„¢.

Binary structure delete error

This is the whole program. Right now,the delete function does not write to the temp file. I'll try to change str array to string and see if it helps.
The program is supposed to read write edit search and sort binary file with structures.
#include <cstdlib>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include<string>
#include<limits>
#include<iomanip>
#include<stdio.h>
#include <errno.h>
using namespace std;
const int SIZE=40;
char typedef str[SIZE];
char fname[]="c:/solident.dat";
char tname[]="c:/temp.dat";
struct Rec{int id;str lname,fname;};
//prototypes
void menu(string&);
void engine(string&,Rec&,fstream&,fstream&,int,char[],char[]);
void openFile(char[]);
void addRec(Rec&,char[]);
void delAll(char[]);
void listAll(Rec&,fstream &,char[]);
void appRec(Rec&,fstream &,char[]);
void delRec(Rec&,fstream &, fstream &,char[],char []);
void srcRec(Rec&,fstream& ,char[]);
void modRec(Rec &J,fstream &outfile, char fname[]);
void sort();
int main(int argc, char *argv[])
{
string choice;
Rec Student;
fstream infile;
fstream outfile;
do
{
menu(choice);
engine(choice,Student,infile,outfile,SIZE,fname,tname);
} while(choice[0]!='0');
system("PAUSE");
return EXIT_SUCCESS;
}
//function menu
void menu(string &choice)
{
cout<<"\n\n\n\t\t========================";
cout<<"\n\n\t\tMENU \n";
cout<<"\n\t\t========================\n\n";
cout<<"\t\t[1] Open/check file\n";
cout<<"\t\t[2] Add records\n";
cout<<"\t\t[3] Append records\n";
cout<<"\t\t[4] Search for a record\n";
cout<<"\t\t[5] Delete a record\n";
cout<<"\t\t[6] Delete all records\n";
cout<<"\t\t[7] Modify a record\n";
cout<<"\t\t[8] List all records\n";
cout<<"\t\t[9] Sort all records\n";
cout<<"\t\t[0] Exit\n";
cout<<"\n\t\t========================= \n";
cout<<"\t\tYour choice :";
getline(cin,choice);
while (choice[0] !='1' && choice[0] !='2' &&choice[0] !='3' &&choice[0] !='4' &&choice[0] !='5' &&choice[0] !='6' &&choice[0] !='7' &&choice[0] !='8' &&choice[0] !='9' &&choice[0] !='0' )
{
cout<<"\n\t\t"<<choice<<" is invalid!";
cout<<"\n\t\tEnter correct choice: ";
getline(cin,choice);
}
cout<<"\n\t\t========================= \n\n";
}
//function
void engine(string &choice,Rec &J,fstream &infile,fstream &outfile,int SIZE,char fname[],char tname[])
{
switch (choice[0]){
case '1':
{
cout<<"Executing number "<<choice<<":"<<"Open/check file\n"<<endl;
openFile(fname);
break;
}
case '2':
{
cout<<"Executing number "<<choice<<":"<<"Add records\n"<<endl;
addRec(J,fname);
break;
}
case '3':
{
cout<<"Executing number "<<choice<<":"<<"Append records\n"<<endl;
appRec(J,outfile,fname);
break;
}
case '4':
{
cout<<"Executing number "<<choice<<":"<<"Search for a record\n"<<endl;
srcRec(J,infile,fname);
break;
}
case '5':
{
cout<<"Executing number "<<choice<<":"<<"Delete a record\n"<<endl;
delRec(J,infile, outfile,fname,tname);
break;
}
case '6':
{
cout<<"Executing number "<<choice<<":"<<"Delete all records\n"<<endl;
delAll(fname);
break;
}
case '7':
{
cout<<"Executing number "<<choice<<":"<<"Modify a record\n"<<endl;
modRec(J,outfile,fname);
break;
}
case '8':
{
cout<<"Executing number "<<choice<<":"<<"List all records\n"<<endl;
listAll(J,infile,fname);
break;
}
case '9':
{
cout<<"Executing number "<<choice<<":"<<"Sort all records\n"<<endl;
sort();
break;
}
default:exit(0);
}
}
//function
void openFile(char fname[])
{
cout<<"\nOpening file"<<fname<<"..."<<endl;
//confirm if file exists and opens
fstream infile;
fstream outfile;
infile.open(fname,ios::in|ios::binary);
if (infile.is_open())
{
cout<<"File "<<fname<<" exists, and was opened succesfully.";
}
infile.close();
//if fail ask to create
if (infile.fail())
{
cout<<"File does not exist. Create? [Y]/[N]";
char ch;
cin>>ch;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
//if yes then create file
if(ch=='y'|| ch=='Y')
outfile.open(fname,ios::out| ios::binary);
//if not created display error
if (outfile.fail())
{
cout<<"Error: File not created";
}
//else confirm creation of file
cout<<"File "<<fname<<" has been created.\n\n";
outfile.close();
}
}
//function
void addRec(Rec&J,char fname[])
{
fstream outfile;
outfile.open(fname,ios::out|ios::binary|ios::app);
char another[10];
do
{
cout<<"Please enter ID number :";
cin>>J.id;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout<<"\nPlease enter first name: ";
cin.getline(J.fname,SIZE);
cout<<"\nPlease enter lastname: ";
cin.getline(J.lname,SIZE);
outfile.write((char*) &J, sizeof(J));
cout<<"Add another record:[Y]/[N] ";
cin.get(another[0]);
cin.ignore(numeric_limits<streamsize>::max(), '\n');
} while(another[0]=='y'||another[0]=='Y');
cout<<"exiting to main menu.."<<endl;
}
//function
void delAll(char fname[])
{
fstream outfile;
cout<<"\n------------------\n"<<endl;
cout<<"\nDelete all records"<<fname<<"..."<<endl;
cout<<"\nAre you sure you want to delete all records in "<<fname<<" [Y]/[Any key for exit]?"<<endl;
char ch;
cin>>ch;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
if(ch=='y'||ch=='Y')
{
outfile.open(fname,ios::out|ios::binary|ios::trunc);
outfile.close();
}
else {cout<<"\nExiting to main menu..."<<endl;}
}
//function
void listAll(Rec&J,fstream &infile,char fname[])
{
infile.clear();
infile.open(fname,ios::in|ios::binary);
infile.read((char*)&J,sizeof(J));
cout<<"|=======================================================|"<<endl;
cout<<"| # | ID | FIRST | LAST |"<<endl;
cout<<"|=======================================================|"<<endl;
int count=1;
while(!infile.eof())
{
cout<<"| "<<setw(6)<<left<<count<<left<<"| "<<setw(9)<<J.id<<"| ";
cout<<left<<setw(14)<<J.fname<<"| ";
cout<<left<<setw(19)<<J.lname<<"|"<<endl;
infile.read((char*)&J,sizeof(J));
count=count+1;
cout<<"|-------------------------------------------------------|"<<endl;
}
infile.close();
}
//function
void appRec(Rec &J,fstream &outfile, char fname[])
{
outfile.open(fname,ios::out|ios::binary|ios::app);
outfile.clear();
cout<<"Please enter ID number :";
cin>>J.id;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout<<"\nPlease enter first name: ";
cin.getline(J.fname,SIZE);
cout<<"\nPlease enter lastname: ";
cin.getline(J.lname,SIZE);
outfile.write((char*) &J, sizeof(J));
outfile.close();
}
//----------------------------------------------------
void delRec(Rec&s,fstream &infile, fstream &outfile,char fname[],char tname[])
{
int current, request=1;
infile.open("c:/solident.dat",ios::in|ios::out|ios::binary);
if (!infile.is_open())
cout << "infile not open\n";
outfile.open("c:/temp.dat",ios::out|ios::binary|ios::trunc);
if (!outfile.is_open())
cout << "outfile not open\n";
for (;;)
{
infile.read((char*)&s, sizeof s);
if (infile.eof())
break;
current = s.id;
if (current != request)
outfile.write((char*)&s, sizeof s);
}
infile.close();
outfile.close();
infile.open("c:/temp.dat)",ios::in|ios::binary);
outfile.open("c:/solident.dat)", ios::out|ios::binary|ios::trunc);
for (;;)
{
infile.read((char*)&s, sizeof (s));
if (infile.eof())
break;
outfile.write((char*)&s, sizeof (s));
}
infile.close();
outfile.close();
}
void srcRec(Rec&Job,fstream &infile,char fname[])
{
cout << "Allowing the user to open a specific record.\n";
infile.open(fname, ios::in | ios::binary) ;
if(infile.fail())
{
cout << "Could not access file.\n";
}
else
{
int position; //user's position
//gets user's position
cout << "Please the record you would like to read: ";
cin >> position;
//ignore luki
cin.ignore(numeric_limits<streamsize>::max(), '\n');
//find the specific record, read it, and display it
infile.seekp((position - 1)*sizeof(Job));
infile.read((char*) &Job, sizeof(Job));
cout<<"|===============================================|"<<endl;
cout<<"| ID | FIRST | LAST |"<<endl;
cout<<"|===============================================|"<<endl;
cout<<left<<"| "<<setw(9)<<Job.id<<"| ";
cout<<left<<setw(14)<<Job.fname<<"| ";
cout<<left<<setw(19)<<Job.lname<<"|"<<endl;
}
//clears and closes the file
infile.clear();
infile.close();
}
void modRec(Rec &J,fstream &outfile, char fname[])
{
int position, //user's position
cntr = 0; //marks the current record within the file
cout << "Modifying a record.\n";
//open the two files
outfile.open(fname, ios::out | ios::in | ios::binary);
//get the user's desired position
cout << "please enter the record you would like to modify: ";
cin >> position;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << endl;
if(outfile.fail())
{
cout << "File could not be read.\n";
}
else
{
//find the desired record
outfile.seekp((position - 1)*(sizeof(J)));
//get the user's modification
cout<<"Please enter ID number :";
cin>>J.id;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout<<"\nPlease enter first name: ";
cin.getline(J.fname,SIZE);
cout<<"\nPlease enter lastname: ";
cin.getline(J.lname,SIZE);
//write over the desired record
outfile.write((char*) &J, sizeof(J));
}
//closes the files
outfile.close();
}
void sort()
{
int StructureSize, Idx1, Idx2;
FILE * binaryFile;
binaryFile = fopen("c:/solident.dat","rb+");
Rec Index, IndexTemp;
StructureSize = sizeof(Index);
fseek(binaryFile, 0, SEEK_END);
int fileSize = ftell(binaryFile);
rewind(binaryFile);
for (Idx1 = 0; Idx1 < fileSize; Idx1 += StructureSize)
{
for (Idx2 = 0; Idx2 < fileSize - StructureSize; Idx2 += StructureSize)
{
fread(&Index, StructureSize, 1, binaryFile);
fread(&IndexTemp, StructureSize, 1, binaryFile);
if (Index.id > IndexTemp.id)
{
fseek(binaryFile, -(StructureSize * 2), SEEK_CUR);
fwrite(&IndexTemp, StructureSize, 1, binaryFile);
fwrite(&Index, StructureSize, 1, binaryFile);
fseek(binaryFile, -StructureSize, SEEK_CUR);
}
else
{
fseek(binaryFile, -StructureSize, SEEK_CUR);
}
}
rewind(binaryFile);
}
fclose(binaryFile);
}
I don't know, there seem to be a few issues with this code. Here's just one of them though
int request=1,current;
...
while (!infile.eof())
{
s.id=current;
if (current!=request)
At no point in this code do you give current a value, but you are still using the variable. This is an uninitialised variable which is one reason your code isn't working.
I wonder if you meant to write
current=s.id;
instead? That would make a little more sense.
Try reading the file with a loop like this
infile.open("c:/solident.dat",ios::in|ios::out|ios::binary);
if (!infile.is_open())
cout << "infile not open\n";
outfile.open("c:/temp.dat",ios::out|ios::binary|ios::trunc);
if (!outfile.is_open())
cout << "outfile not open\n";
for (;;)
{
infile.read((char*)&s, sizeof s);
if (infile.eof())
break;
current = s.id;
if (current != request)
outfile.write((char*)&s, sizeof s);
}
infile.close();
outfile.close();
I wouldn't use fail() if I were you. I think it's extremely unlikely you'll detect a genuine read or write failure with it. It's much more likely to be an end of file error, or a failure to open a file.
#john .Thanks!
The first part works, but trying
rename(tempname,destination) does not work:
(the dest file exists)
Although the file temp.dat now contains the records minus the one deleted , the output is not written to the solident.dat file(it remains unchanged)
//So I tried to read every rec from file and write every record to dest file:
infile.open("c:/temp.dat)",ios::in|ios::binary);
outfile.open("c:/solident.dat)", ios::out|ios::binary|ios::trunc);
infile.read((char*)&s, sizeof s);
for (;;)
{
if (infile.eof())
break;
infile.read((char *)&s, sizeof (s));
outfile.write((char*)&s, sizeof (s));
}
infile.close();
outfile.close();
My understanding was, that outfile and infile are pretty straightforward: fstream.open, close , clear and it should work (I thought). It seems though that I'm missing something essential, because the simple delete binary struct function in the program seems to be a hit and miss and I've been going around in circles for a few days: parts of it work, then I add a few lines of code and either a function fails or the whole program fails.I tend to blame it on the compiler or devc++ :) but I'm certain it has to be the code that is invalid!
Thanks for help!