Understanding File Handling I/O - c++

I have written a simple program in two ways. The program is for getting data from a user, storing it in a txt file, retrieving the data and displaying it. The problem is that one approach works while the other does not. I dont understand why.
The one that works is this:
#include <iostream>
#include <fstream>
using namespace std;
class customer{
public:
// Declaring member variables and functions
string name, address, telNo;
int age;
void createCustomer();
void displayInfo(string inputName);
};
// Member function of customer to enter new customer details
void customer::createCustomer(){
customer c;
ofstream file;
file.open("customers.txt", ios::out);
cout << "Enter Name: ";
cin >> c.name;
cout << "Enter Age: ";
cin >> c.age;
cout << "Enter Address: ";
cin >> c.address;
cout << "Enter Telephone Number: ";
cin >> c.telNo;
file.write((char*)&c, sizeof(c));
file.close();
cout << "\n";
}
// Member function of customer to display customer information
void customer::displayInfo(string inputName){
customer c;
ifstream file;
file.open("customers.txt", ios::in);
if(!file){
cout << "Could Not Open customers.txt File\n";
return;
}
while(!file.eof()){
file.read((char*)&c, sizeof(c));
if (inputName == c.name){
cout << "\n";
cout << "Name-------------> " << c.name << endl;
cout << "Age--------------> " << c.age << endl;
cout << "Telephone Number-> " << c.telNo << endl;
cout << "Address----------> " << c.address << endl;
cout << "\n";
break;
}
}
file.close();
}
int main(){
customer c;
c.createCustomer();
c.displayInfo("name");
return 0;
}
It gives the following output:
Enter Name: name
Enter Age: 21
Enter Address: add
Enter Telephone Number: telno
Name-------------> name
Age--------------> 21
Telephone Number-> telno
Address----------> add
The one that doesnt work is this:
#include <iostream>
#include <fstream>
using namespace std;
class customer{
public:
// Declaring member variables and functions
string name, address, telNo;
int age;
void createCustomer();
void displayInfo();
};
// Member function of customer to enter new customer details
void customer::createCustomer(){
customer c;
ofstream file;
file.open("customers.txt", ios::out);
cout << "Enter Name: ";
cin >> c.name;
cout << "Enter Age: ";
cin >> c.age;
cout << "Enter Address: ";
cin >> c.address;
cout << "Enter Telephone Number: ";
cin >> c.telNo;
file.write((char*)&c, sizeof(c));
file.close();
cout << "\n";
}
// Member function of customer to display customer information
void customer::displayInfo(){
string inputName = "name";
customer c;
ifstream file;
file.open("customers.txt", ios::in);
if(!file){
cout << "Could Not Open customers.txt File\n";
return;
}
while(!file.eof()){
file.read((char*)&c, sizeof(c));
if (inputName == c.name){
cout << "\n";
cout << "Name-------------> " << c.name << endl;
cout << "Age--------------> " << c.age << endl;
cout << "Telephone Number-> " << c.telNo << endl;
cout << "Address----------> " << c.address << endl;
cout << "\n";
break;
}
}
file.close();
}
int main(){
customer c;
c.createCustomer();
c.displayInfo();
return 0;
}
All I have done is put the string inputName variable inside the function instead of passing it as an argument.
It gives only the following output:
Enter Name: name
Enter Age: 21
Enter Address: add
Enter Telephone Number: telno
If I remove the if condition:
while(!file.eof()){
file.read((char*)&c, sizeof(c));
//if (inputName == c.name){
cout << "\n";
cout << "Name-------------> " << c.name << endl;
cout << "Age--------------> " << c.age << endl;
cout << "Telephone Number-> " << c.telNo << endl;
cout << "Address----------> " << c.address << endl;
cout << "\n";
break;
//}
}
i get the following output:
Enter Name: name
Enter Age: 21
Enter Address: add
Enter Telephone Number: telno
Name-------------> 0∙⌂┼
Age--------------> 21
Telephone Number-> name
Address----------> §
Why are the name and address fields outputting random symbols and the telephone number field outputting value of the name field?

Neither program is correct. It's an error use read on a type like customer because it contains sub-objects that need constructing, namely the string members name, address and telNo. Calling read does not call any constructor for the objects you are reading and so this is invalid.
Since read does not work for strings it doesn't make any sense to use write on a class containing a string either because you won't be able to read back what you have written.
If you want to write a customer to a file you can do it something like this
file << c.name << ' ' << c.age << ' ' << c.telNo << ' ' << c.address << '\n';
and then something similar for reading (although you then you would have to be careful of any spaces in your data).

Related

Reading from text file until EOF infinite loop

I am working at my programming project for school and i came up with idea of "Student Manager Program".
The: name, roll, year, group, course, adress, email, contact, grade are stored as variables in class named Student.
Student's data is written by user keyboard input and saved in studentRecord.txt file, by object.
How can i prevent this while loop to be a not infinite loop. I can't find solution to this problem.
'''
//Displaying Students Record Table
void Student::display() {
system("cls");
ifstream file;
int total = 1;
int x;
cout << "\n-----------------------------Students Record Table-----------------------------" << endl;
file.open("studentRecord.txt");
if (!file) {
cout << "\n\t\t\tNo Data Is Present.";
file.close();
}
else {
file >> name >> roll >> year >> group >> course >> adress >> email >> contact >> grade;
while(!file.eof()) {
cout << "\n\n\t\t\t Student Consecutive Number: " << total++ << endl;
cout << "\t\t\t Student's Name: " << name << endl;
cout << "\t\t\t Student's ID Number: " << roll << endl;
cout << "\t\t\t Student's Year: " << year << endl;
cout << "\t\t\t Student's Group: " << group << endl;
cout << "\t\t\t Student's Course: " << course << endl;
cout << "\t\t\t Student's Adress: " << adress << endl;
cout << "\t\t\t Student's Email: " << email << endl;
cout << "\t\t\t Student's Contact: " << contact << endl;
cout << "\t\t\t Student's Final Grade: " << grade << endl;
file >> name >> roll >> year >> group >> course >> adress >> email >> contact >> grade;
}
if (total == 0) {
cout << "\n\t\t\tNo Data Is Present.";
}
}
do {
cout << "\n\t\t\t If You Want to Back at previous page press 0 and Enter: ";
cin >> x;
if (x == 0) {
file.close();
}
} while (x != 0);
}
'''

How to create a function to read/write data to struct members?

I'm trying to create a program that read and print students' data with c++. for that, I've created a struct Student, a function to read data from the user and assign it to a struct instance s1 and a function to print students' data on the screen, and I think the problem is with the function that read/write data.
Here is the my code:
#include<iostream>
#include<string>
using namespace std;
struct Student
{
char name[30];
int age;
double gpa;
string department;
};
Student read_data(Student x)
{
cout << "Name (30 characters maximum): ";
cin.get(x.name, 30);
cout << "Age: ";
cin >> x.age;
cout << "Department: ";
cin >> x.department;
cout << "GPA: ";
cin >> x.gpa;
return x;
}
void print_data(Student x)
{
cout <<
"\n***************************************************************" << endl;
cout << "Name: " << x.name << endl;
cout << "Age: " << x.age << endl;
cout << "Department: " << x.department << endl;
cout << "GPA: " << x.gpa << endl;
}
int main()
{
Student s1, s2, s3;
cout << "This program stores -Temporarily- data of three students\n" << endl;
cout << "Enter 1st student's data" << endl;
read_data(s1);
print_data(read_data(s1));
system("pause");
return 0;
}
The output of this code is:
This program stores data of three students
Enter 1st student's data
Name (30 characters maximum): Ahmed Maysara
Age: 22
Department: CS
GPA: 3.5
Name (30 characters maximum): Age: Department: GPA:
***************************************************************
Name:
Age: -858993460
Department:
GPA: -9.25596e+61
Press any key to continue . . .
As you see, the output is out of my expectations :) ..
Any help ?!
Both CinCout and David are correct.
There are a couple of problems with your code as it now stands.
The first problem is that while you successfully call the function read_data(s1), s1 is a just a copy. So, when the function sets all of the values for the student using cin, it is really just setting a copy's values. You can either make it so that you are passing in the original, or you can return the student (which you are doing) and set s1 equal to the result (which you are not).
To make sure that you pass in the original, you can go to where you declared read_data. Instead of saying Student read_data(Student x), you should place an ampersand after the parameter that you don't want to copy Student read_data(Student &x). This is called passing by reference (you reference the original instead of referencing by copy)
Alternatively, you could con just set s1 to the result where you call it in main. You could say s1 = read_data(s1); and that would work fine, though a bit more inefficiently.
Lastly, the other glaring error in the code is that you accidentally call read_data again when you say print_data(read_data(s1)). Instead, say print_data(s1).
Instead of passing and returning the structure object each time on call of read_data and print_data we could add those inside the structure itself, We could create object of Student and call the functions read and print within the same.
struct Student
{
char name[30];
int age;
double gpa;
string department;
Student(): age(0), gpa(0)
{
memset( name, 0, 30 );
}
void read()
{
cout << "\nName (30 characters maximum): ";
cin.get(name, 30);
cout << "\nAge: ";
cin >> age;
cout << "\nDepartment: ";
cin >> department;
cout << "\nGPA: ";
cin >> gpa;
}
void print()
{
cout << "\n***************************************************************" << endl;
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Department: " << department << endl;
cout << "GPA: " << gpa << endl;
}
};
int main()
{
Student s1;
s1.read();
s1.print();
return 0;
}
You are passing copy of s1 into the read_data function, but not bothering to update the value based on the return arg. i.e. something like this should work.
s1 = read_data(s1);
print_data(s1);
Alternatively, pass by reference instead of value:
void read_data(Student& x)
{
cout << "Name (29 characters maximum): "; // requires null terminator
cin >> x.name; // just read into the buffer directly
cout << "Age: ";
cin >> x.age;
cout << "Department: ";
cin >> x.department;
cout << "GPA: ";
cin >> x.gpa;
}
And then later:
read_data(s1);
print_data(s1);
change you read_data with something like this
void read_data(Student& x)
{
cout << "Name (30 characters maximum): ";
///cin.get(x.name, 30);
cin.getline(x.name, 30);
cout << "Age: ";
cin >> x.age;
cin.ignore();
cout << "Department: ";
std::getline(cin, x.department);
///cin >> x.department;
cout << "GPA: ";
cin >> x.gpa;
cin.ignore();
// return x; can't return a value from a void function
}
and in main function or where you are calling the read_data function use
Student s1, s2, s3;
cout << "This program stores -Temporarily- data of three students\n" << endl;
cout << "Enter 1st student's data" << endl;
read_data(s1);
read_data(s2);
read_data(s3);
the reason you are getting weird values in return is that you capture buffer with cin >> instead getline
see
description of getline function
description of cin.ignore function

How to pass struct as parameter to other function for input, then output back at the original function

This is part of my project codes.
About the struct customer that I did, from welcomeScreen function I call the getInfo function for user to input the details (as you can see) and then return back the value to welcomeScreen function for output.
I can compile the codes, but the problem is there is no output for all the details after I input it (just blank)? Sorry if this is a dumb question cause im still a student.
struct customer
{
string name;
string email;
int number;
};
void welcomeScreen(); //prototype
void getInfo(struct customer cust); //prototype
void welcomeScreen()
{
struct customer cust; // struct declaration
const int SIZE=5;
system("CLS");
cout << setfill ('-') << setw (55) << "-" << endl;
cout << "\tWelcome to Computer Hardware Shop" << endl;
cout << setfill ('-') << setw (55) << "-" << endl;
cout << endl << "Type of hardwares that we sell:" << endl;
string item[SIZE]={"Monitor","CPU","RAM","Solid-State Drive","Graphic Card"};
for(int i=0;i<SIZE;i++)
cout << "\t" << i+1 << ". " << item[i] << endl;
getInfo(cust);
cout << endl;
cout << fixed << showpoint << setprecision (2);
cout << "Name: "<< cust.name << endl; // struct output
cout << "Email: "<< cust.email << endl;
cout << "Phone Number: " << cust.number << endl;
cout << endl;
}
void getInfo(struct customer cust)
{
cout << endl << "Enter name: ";
cin >> cust.name;
cout << "Enter email: ";
cin >> cust.email;
cout << "Enter phone number: ";
cin >> cust.number;
}
You probably want to pass a pointer or a reference, in this case recommend a reference because it means fewer changes to your code:
void getInfo(struct customer &cust); //prototype
Remember to change your function parameter as well.

when running program it has me enter two lines after name? help please

my program seems to want to enter two inputs for name variable instead of just entering one thing and moving on to phone number?
i'm sure its simple but can someone help me fix this please? is it something it do with the getline?
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//define Car struct
struct Speaker
{
string name;
string phoneNumber;
string emailAddress;
string theme;
double fee;
};
Speaker *getSpeaker();
int main()
{
Speaker thespeaker;
thespeaker = *getSpeaker();
cout << "The speaker entered is!" << endl;
cout << thespeaker.name << endl;
cout << "phone number: " << thespeaker.phoneNumber << endl;
cout << "email: " << thespeaker.emailAddress << endl;
cout << "theme: " << thespeaker.theme << endl;
cout << "fees: " << thespeaker.fee << endl;
}
Speaker *getSpeaker()
{
Speaker *theSpeaker;
theSpeaker = new Speaker;
cout << "Please enter Speakers information" << endl;
cout << "name: " ;
getline(cin, theSpeaker->name);
cin.ignore(100, '\n');
cin.clear();
cout << theSpeaker->name;
cout << "\nphone number: ";
cin >> theSpeaker->phoneNumber;
cout << "\nEmail Address: ";
cin >> theSpeaker->emailAddress;
cout << "\nTheme: ";
cin >> theSpeaker->theme;
cout << "\nFee: ";
cin >>theSpeaker->fee;
return theSpeaker;
}
There's no need for cin.ignore();
Simply write it as:
Speaker *getSpeaker()
{
Speaker *theSpeaker;
theSpeaker = new Speaker;
cout << "Please enter Speakers information" << endl;
cout << "name: " ;
getline(cin, theSpeaker->name);
cout << theSpeaker->name;
cout << "\nphone number: ";
cin >> theSpeaker->phoneNumber;
cout << "\nEmail Address: ";
cin >> theSpeaker->emailAddress;
cout << "\nTheme: ";
cin >> theSpeaker->theme;
cout << "\nFee: ";
cin >>theSpeaker->fee;
return theSpeaker;
}

Error with fstream in C++

I'm writing a simple program to enter student records and store them in a coma delimited file. Everything looks good but when I run the program I get an error:
Error 1 error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>' c:\program files\microsoft visual studio 10.0\vc\include\fstream 1116 1 project1
Here's the code:
#include <cstring>
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
void closeOrNewRecordMenu(string enterAnotherRecord)
{
if (enterAnotherRecord == "Q" && enterAnotherRecord == "q")
{
exit(0);
}
}
void newStudentRecord(double studentNumber, string firstName, string lastName, string campus, string course1, string course2, string course3, string seniorPracticum, ofstream writeToRecordsFile)
{
int campusChoice;
do {
cout << "Student's six digit number: (Numeric only)";
cin >> studentNumber;
cin.ignore();
}
while (studentNumber < 100000 && studentNumber > 999999);
cout << "Student's first name: " << "\n";
cin >> firstName;
cin.ignore();
cout << "Student's last name: " << "\n";
cin >> lastName;
cin.ignore();
while (campusChoice < 1 || campusChoice > 3)
cout << "Which campus will " << firstName << " " << lastName << " be attending class at: " << "\n";
cout << "For the North campus enter 1" << "\n";
cout << "For the South campus enter 2" << "\n";
cout << "For the Seaside campus enter 3" << "\n";
cin >> campusChoice;
cin.ignore();
if (campusChoice == 1)
{
campus = "North Campus";
}
else if (campusChoice == 2)
{
campus = "South Campus";
}
else if (campusChoice == 3)
{
campus = "Seaside Campus";
}
else {
cout << "Please enter a valid choice." << "\n" << "\n";
}
cout << "Student's first course: " << "\n";
getline (cin, course1);
cin.ignore();
cout << "Student's second course: " << "\n";
getline (cin, course2);
cin.ignore();
cout << "Student's third course: " << "\n";
getline (cin, course3);
cin.ignore();
do {
cout << "Is " << firstName << " " << lastName << " a senior this year? Please enter \"Y\" for yes and \"N\" for no." << "\n";
cin >> seniorPracticum;
cin.ignore();
} while (seniorPracticum != "y" && seniorPracticum != "Y" && seniorPracticum != "n" && seniorPracticum != "N");
writeToRecordsFile << studentNumber << "," << firstName << "," << lastName << "," << campus << "," << course1 << "," << course2 << "," << course3 << "," << seniorPracticum << "\n";
cout << "The student record for " << firstName << " " << lastName << " has been saved." << "\n" << "\n";
}
int main()
{
cout << "Hello there! Welcome to the student record manager. From here you can enter new student information and save it to a file!!!! (More exciting to the developer than the user)." << "\n" << "\n";
string enterAnotherRecord;
ofstream writeToRecordsFile;
writeToRecordsFile.open("cop2224_proj1.txt");
while (enterAnotherRecord != "Q" && enterAnotherRecord != "q") {
cout << "Press \"N\" to create a new student record or press \"Q\" to quit." << "\n" << "\n";
cin >> enterAnotherRecord;
closeOrNewRecordMenu(enterAnotherRecord);
string firstName, lastName, seniorPracticum, campus, course1, course2, course3;
double studentNumber;
newStudentRecord(studentNumber, firstName, lastName, campus, course1, course2, course3, seniorPracticum, writeToRecordsFile);
}
writeToRecordsFile.close();
}
Streams are not copyable, and even if they were, you wouldn't want to do so here – pass by reference instead. Change your newStudentRecord signature to:
void newStudentRecord(double studentNumber, string firstName, string lastName, string campus, string course1, string course2, string course3, string seniorPracticum, ofstream& writeToRecordsFile);
That being said, why are you passing in all those arguments when you don't care about their initial values and you don't use them as output parameters? Simplify your signature to the following:
void newStudentRecord(ofstream& writeToRecordsFile);
and declare the other arguments as local variables inside of newStudentRecord.
As an aside, you're reading campusChoice before initializing it, which will yield undefined behavior.