I am trying to insert object in file and then read the object to display the student data but when It goes to display program just goes in infinite loop and starts displaying 0 which I have initialized in constructor.I am simply not getting what is happening. I am using visual studio 17 just in case anyones wondering. I even tried to create a new file named Student.txt in same directory as the program but it won't work. Can somone explain me what I am doing wrong?
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
//class to handle individual record
class Student
{
public:
char name[20];
int year;
char division;
char address[50];
int rollno;
Student()
{
strcpy_s(name," ");
strcpy_s(address, " ");
rollno = 0;
year = 0;
division = 0;
}
};
class operations
{
public:
void insertdata();
void printg();
};
void operations::insertdata()
{
int n;
cout << "\nEnter how many student data you want to insert:";
cin >> n;
fstream fin;
Student obj;
fin.open("Student.txt", ios::in | ios::out | ios::binary| ios::trunc);
if (!fin)
{
cout<<"\nFILE NOT Opened!";
}
for (int v = 0; v < n; v++)
{
cout << "\nEnter Roll no:";
cin >> obj.rollno;
cout << "\nEnter Name:";
cin.ignore();
cin >> obj.name;
cout << "\nEnter year:";
cin >> obj.year;
cout << "\nEnter division:";
cin >> obj.division;
cout << "\nEnter Address:";
cin.ignore();
cin >> obj.address;
fin.seekp(0, ios::end);
fin.write((char*)&obj, sizeof(obj));
}
fin.close();
}
void operations::printg()
{
Student obj;
fstream fin("Student.txt", ios::in | ios::out | ios::binary);
fin.seekg(0, ios::beg);
fin.read((char*)&obj, sizeof(obj));
if (!fin)
{
cout << "\n FIle doenst exist";
}
while (!fin.eof())
{
cout << "\n" << obj.name;
cout << "\n" << obj.year;
cout << "\n" << obj.division;
}
fin.close();
}
int main() {
operations obj;
obj.insertdata();
obj.printg();
system("pause");
return 0;
}
A few wrong things:
Writing objects like fin.write((char*)&obj, sizeof(obj)); is a bad idea. A compiler may decide to have different padding between members at any moment for your Student objects, so your file format is like a quantum particle: you don't really know how the file was laid out.
strcpy_s takes 3 parameters, not 2. Anyway, do not use them, they are not really portable (even if they are in the C standard).
Your paths are wrong, so the file will not open (as Sam explains in the comment).
Even if you succeeded in opening a file, in operations::printg() you are not reading the file, so you will not get any data.
Why do you have an operations class? I guess it is intended to be expanded in the future, but seems weird. If you do not intend to have state, use a namespace instead.
Related
I thought I had a decent understanding of fstreams and struct's, but for some reason I can't figure out what's wrong with my code. The file I'm reading from starts with an integer 'n' that represents the amount of students in the file, it's then used as the size of the dynamically allocated array of Students.
I go on to read each name, major, and grade from the file into the array of type Student. But for whatever reason, it's only reading the first "line" in the file (as in it reads the first name, major, and grade), and does that n times. I messed around with the code and I believe I've narrowed the problem down to the array not actually being of size n. It correctly reads the first int in the file, as I've printed it out to make sure that's working, and I've tried manually reading in each Student for the array from the file with the same issues.
This is an assignment, so I'm not looking for any straight forward answer, but a nudge in the right direction would be incredibly helpful.
Here's my code:
using namespace std;
struct Student {
string name, major;
double grade;
void display(Student);
void filterByMajor(Student[], int, string);
void filterByGrade(Student[], int, double);
};
int main() {
ifstream inputFile;
Student* students = nullptr;
string filename;
int n;
cout << “Enter an input file to read from: “;
cin >> filename;
inputFile.open(filename);
if (inputFile.fail()) {
cout << “ERROR: Could not open the file.” << endl;
}
else {
inputFile >> n;
students = new Student[n];
for (int i = 0; i < n; i++) {
inputFile >> students[i].name;
inputFile >> students[i].major;
inputFile >> students[i].grade;
}
cout << “ Student info” << endl;
students->display(students[0]);
cout << endl;
students->display(students[3]);
}
delete[] students;
inputFile.close();
return 0;
}
void Student::display(Student s) {
cout << “Name: “ << name << endl;
cout << “Major: “ << major << endl;
cout << “Grade: “ << grade << endl;
}
And the input file I'm reading from:
7
John CS 3.0
Joe Math 2.5
Jane Math 3.7
Mike CS 2.2
Carol CS 3.3
James Math 2.8
Mary CS 3.6
The problem is not with your reading code. That is actually reading the file data just fine. The real problem is in the display code. You are calling display() on the 1st entry in the array each time, and display() is ignoring the Student that is passed to it, instead displaying the data of the Student it is called on, so you see only the data of the 1st entry being printed each time.
Try this instead:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct Student {
string name, major;
double grade;
void display() const;
};
int main() {
ifstream inputFile;
Student* students = nullptr;
string filename;
int n;
cout << “Enter an input file to read from: “;
cin >> filename;
inputFile.open(filename);
if (inputFile.fail()) {
cout << “ERROR: Could not open the file.” << endl;
}
else {
inputFile >> n;
students = new Student[n];
for (int i = 0; i < n; i++) {
inputFile >> students[i].name;
inputFile >> students[i].major;
inputFile >> students[i].grade;
}
cout << “ Student info” << endl;
students[0].display();
cout << endl;
students[3].display();
}
delete[] students;
inputFile.close();
return 0;
}
void Student::display() const {
cout << “Name: “ << name << endl;
cout << “Major: “ << major << endl;
cout << “Grade: “ << grade << endl;
}
Hey I am trying to figure out how to access an a object out of the scope of the block. I defined Person personData in the For loop which writes data to the file. And after the loop I wanted to access the object again to update the values on the file but its giving me the error - personData is undefined identifier.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdlib>
#include "Person.h"
using namespace std;
int main() {
string lastName;
string firstName;
int age;
//file output and creation
ofstream outPerson("nameage.dat", ios::out | ios::binary);
Person randPerson;
randPerson.setLastName("unassigned");
randPerson.setFirstName("");
randPerson.setAge(0);
randPerson.setId(0);
//for loop to initialize the file with 100 records that store values lastName and firstName
for (int i = 0; i < 100; i++) {
outPerson.write(reinterpret_cast<const char*>(&randPerson), sizeof(Person)); //use write to output to file
}
cout << "File Created" << endl;
//file input and termination
ifstream inPerson("nameage.dat", ios::in | ios::out | ios::binary);
//loops through 10 times to input 10 values (RECORD VALUES)
for (int j = 0; j < 2; j++) {
int id = 0;
do {
cout << "Enter a valid id number: (1-100)" << endl;
cin >> id;
} while ((id<1)||(id>100)); //breaks do-while after it receives a valid input
Person personData;
inPerson.seekg((id - 1) * sizeof(Person));
inPerson.read(reinterpret_cast<char*>(&personData), sizeof(Person));
//checks to see if there is already data in that area, if not then proceed to record data onto file
if (personData.getId() == 0) {
cout << "Enter lastname: ";
cin >> lastName;
cout << "Enter firstname: ";
cin >> firstName;
cout << "Enter age: ";
cin >> age;
//sets data for the particular object
personData.setLastName(lastName);
personData.setFirstName(firstName);
personData.setAge(age);
personData.setId(id);
//seek position in file of user-specified record
outPerson.seekp((personData.getId() - 1) * sizeof(Person));
//write user-specified information in file
outPerson.write(reinterpret_cast<const char*>(&personData), sizeof(Person));
cout << "Record inserted" << endl;
}
else {
cout << "There is already data there. Try another ID number" << endl;
}//end if
}//end for loop
int idSearch;
do {
cout << "Enter a ID number: " << endl;
cin >> idSearch;
} while ((idSearch < 1) || (idSearch > 100));
if (personData.getId() != 0) {
cout << "Enter new Last name";
cin >> lastName;
cout << "Enter new first name";
cin >> firstName;
cout << "Enter age";
cin >> age;
//sets data for the particular object
personData.setLastName(lastName);
personData.setFirstName(firstName);
personData.setAge(age);
personData.setId(idSearch);
//seek position in file of user-specified record
outPerson.seekp((personData.getId() - 1) * sizeof(Person));
//write user-specified information in file
outPerson.write(reinterpret_cast<const char*>(&personData), sizeof(Person));
cout << "Record updated" << endl;
}
inPerson.read(reinterpret_cast<char*>(&personData), sizeof(Person));
system("pause");
return 0;
}
I'm assuming the problem is because the object cant be accessed when out of scope. So how would I go about accessing the object from the statement below the for loop. Thank you.
It's one of the core ideas of C++ data model: data is deleted as soon, as it leaves the scope.
For this to work, you'd need to change the scope of personData (for example, move variable definition outside of the loop).
But be cautious using something like that. In the very best case personData would store data left by the last iteration of the loop.
struct student{
char name[20];
char course[20];
int age;
float gpa;
};
using namespace std;
main()
{
ifstream infile;
infile.open("student data.txt");
ofstream outfile;
outfile.open("student data 2.txt");
if(!infile || !outfile)
{
cout << "error opening or creating file" << endl;
exit(1);
}
student stu[2];
infile.seekg(0, ios::beg);
while(!infile.eof())
{
int i;
for(i=0; i<=2; i++)
{
infile >> stu[i].name;
infile >> stu[i].course;
infile >> stu[i].age;
infile >> stu[i].gpa;
}
}
outfile.seekp(0, ios::beg);
int i =0;
while(i<3)
{
outfile << stu[i].name << endl;
outfile << stu[i].course << endl;
outfile << stu[i].age << endl;
outfile << stu[i].gpa << endl;
i++;
}
infile.close();
outfile.close();
}
I am trying to figure out why this code is not working... its not giving any compilation error but when i run the application it stops working.it says rough.exe (app name) is not working. can anyone help :(
Alright, so this is fortunately a very simple solution! The problem you are facing is related to memory management. This line is causing you all the trouble:
student stu[2];
AND
int i =0;
while(i<3)
Basically, you're initializing 2 structs (indexes 0-1) of type student, then expecting to iterate over 3 structs (from index 0-2). When attempting to read in the third struct, you can get a memory access violation error.
So I ran your code with this text in "student data.txt"
nasir CS201 23 3
Jamil CS201 31 4
Faisal CS201 25 3.5
When only two structs were initialized, "student data 2" remained blank. However, when increasing the value to student stu[3];, "student data 2.txt" gave the following output:
nasir
CS201
23
3
Jamil
CS201
31
4
Faisal
CS201
25
3.5
Here is the code I used to create a successful version of your program, with a couple of extra printf's for debugging purposes.
#include <iostream>
#include <fstream>
struct student {
char name[20];
char course[20];
int age;
float gpa;
};
using namespace std;
int main()
{
ifstream infile;
infile.open("student data.txt");
ofstream outfile;
outfile.open("student data 2.txt");
if (!infile || !outfile)
{
cout << "error opening or creating file" << endl;
exit(1);
}
student stu[3]; //NOTE THIS LINE NOW HAS 3 STRUCTS INITIALIZED
infile.seekg(0, ios::beg);
while (!infile.eof())
{
int i;
for (i = 0; i <= 2; i++)
{
infile >> stu[i].name;
infile >> stu[i].course;
infile >> stu[i].age;
infile >> stu[i].gpa;
printf("%s %s %d %f\n", stu[i].name, stu[i].course, stu[i].age, stu[i].gpa);
}
}
outfile.seekp(0, ios::beg);
int i = 0;
while (i<3)
{
outfile << stu[i].name << endl;
outfile << stu[i].course << endl;
outfile << stu[i].age << endl;
outfile << stu[i].gpa << endl;
printf("%s %s %d %f\n", stu[i].name, stu[i].course, stu[i].age, stu[i].gpa);
i++;
}
infile.close();
outfile.close();
return 1;
}
Hope this helps!
I have 2 c++ code: one is for write data into a binary file, another is for read that file.
write.cpp code is as below:
#include <iostream>
#include <fstream>
using namespace std;
const int NAME_SIZE = 51;
struct Data
{
char name[NAME_SIZE];
int age;
};
int main()
{
Data person;
char again;
fstream people("people.db", ios::out | ios::binary);
do
{
cout << "Enter the following data about a "<< "person:\n";
cout << "Name: ";
cin.getline(person.name, NAME_SIZE);
cout << "Age: ";
cin >> person.age;
cin.ignore();
people.write(reinterpret_cast<char *>(&person),sizeof(person));
cout << "Do you want to enter another record? ";
cin >> again;
cin.ignore();
} while (again == 'Y' || again == 'y');
people.close();
return 0;
}
read.cpp code is as below:
#include <iostream>
#include <fstream>
using namespace std;
const int NAME_SIZE = 51;
struct Data
{
char name[NAME_SIZE];
int age;
};
int main()
{
Data person;
char again;
fstream people;
people.open("people.db", ios::in | ios::binary);
if (!people)
{
cout << "Error opening file. Program aborting.\n";
return 0;
}
cout << "Here are the people in the file:\n\n";
people.read(reinterpret_cast<char *>(&person),sizeof(person));
while (!people.eof())
{
cout << "Name: ";
cout << person.name << endl;
cout << "Age: ";
cout << person.age << endl;
cout << "\nPress the Enter key to see the next record.\n";
cin.get(again);
people.read(reinterpret_cast<char *>(&person),sizeof(person));
}
cout << "That's all the data in the file!\n";
people.close();
return 0;
}
Above mentioned codes work fine. The problem arises when I use string type members in the structure:
new write.cpp:
#include <iostream>
#include <fstream>
using namespace std;
struct Data
{
string name;
int age;
};
int main()
{
Data person;
char again;
fstream people("people.db", ios::out | ios::binary);
do
{
cout << "Enter the following data about a "<< "person:\n";
cout << "Name: ";
cin>>person.name;
cout << "Age: ";
cin >> person.age;
cin.ignore();
people.write(reinterpret_cast<char *>(&person),sizeof(person));
cout << "Do you want to enter another record? ";
cin >> again;
cin.ignore();
} while (again == 'Y' || again == 'y');
people.close();
return 0;
}
new read.cpp:
#include <iostream>
#include <fstream>
using namespace std;
struct Data
{
string name;
int age;
};
int main()
{
Data person;
char again;
fstream people;
people.open("people.db", ios::in | ios::binary);
if (!people)
{
cout << "Error opening file. Program aborting.\n";
return 0;
}
cout << "Here are the people in the file:\n\n";
people.read(reinterpret_cast<char *>(&person),sizeof(person));
while (!people.eof())
{
cout << "Name: ";
cout << person.name << endl;
cout << "Age: ";
cout << person.age << endl;
cout << "\nPress the Enter key to see the next record.\n";
cin.get(again);
people.read(reinterpret_cast<char *>(&person),sizeof(person));
}
cout << "That's all the data in the file!\n";
people.close();
return 0;
}
Now when I run read.cpp the program can't read string and the program crashes. I must use string as a member of the structure. How to solve this problem?
The only way that comes to mind is to write the following data separately:
Length of the string.
The array of characters of the string.
The age.
and read them separately.
Create functions to write/read an instance of Data such that they are aware of each other's implementation strategy.
std::ostream& write(std::ostream& out, Data const& data)
{
size_t len = data.name.size();
out.write(reinterpret_cast<char const*>(&len), sizeof(len));
out.write(data.name.c_str(), len);
out.write(reinterpret_cast<char const*>(&data.age));
return out;
}
std::istream& read(std::istream& in, Data& data)
{
size_t len;
in.read(reinterpret_cast<char*>(&len), sizeof(len));
char* name = new char[len+1];
in.read(name, len);
name[len] = '\0';
data.name = name;
delete [] name;
in.read(reinterpret_cast<char*>(&data.age));
return in;
}
and use them similarly to your first approach.
Instead of using
people.write(reinterpret_cast<char *>(&person),sizeof(person));
use
write(people, person);
Instead of using
people.read(reinterpret_cast<char *>(&person),sizeof(person));
use
read(people, person);
One problem is that sizeof(person.Name) does not give what you think it does. It always gives the same size (28 bytes in my case) not matter what characters you assign to your person.Name string. This is because of std::string contains at least:
a pointer to the actual string
other data structure to hold the available size and the size used
Therefore, you cannot call people.write(reinterpret_cast<char *>(&person),sizeof(person));. The content of your string is not located at &person (its located wherever the pointer in std::string is pointing to)
So, what happens when you do cout << person.name << endl; after reading it from your file? You've actually read the address (not the content) where person.name's string pointer was pointing to, when you wrote person to people.db. This is of course not a valid memory location, after reading it from your file, again.
The following code snippet could be helpful in your case. Instead of writing the length of the string, it is possible to use a delimiter and a pre-defined string length.
constexpr char delimiter = '\0';
constexpr uint32_t maxStringSize = 1024;
struct Data
{
string name;
int age;
};
When writing the file, place a delimiter after the string.
Let's say we have a Data structure {"John", 42} then we would write as follows:
std::ofstream outStream(filename, std::ios::binary);
outStream << structure.name << delimiter << structure.age;
outStream.close();
Reading the file is not the mirror of the write (unfortunately).
We'll use the std::ifstream::getline to read the string without knowing the size of it. (Error checking omitted)
std::ifstream istrm(filename, std::ios::binary);
Data dataRead;
// string input - use a buffer and look for the next delimiter
char* buf = new char[maxStringSize];
istrm.getline(buf, maxStringSize, delimiter);
dataRead.name = std::string(buf);
// the number input
istrm >> dataRead.age;
For inspiration how to read/write a vector of this struct you can check my repository.
I'm trying to pass an fstream to a function which then writes struct to the file. I'm aware that you have to pass the stream by reference, but nothing is being written to the file at runtime. Heres what I have so far:
struct Record
{
char name [16];
char phoneNum [16];
float balance;
};
void newRec (fstream &);
int main()
{
fstream ref;
ref.open("prog2.dat", ios::in | ios::out | ios::app | ios::binary);
if(!ref.fail() )
{
int choice = menu(ref);
system("CLS");
while(choice != 6)
{
choice = menu(ref);
system("CLS");
}
}
else
cout << "Error opening file. " << endl;
return 0;
}
void newRec (fstream& ref)
{
Record rec;
cout << "Enter customer name: ";
cin.ignore();
cin.getline(rec.name, sizeof(rec.name));
cout << "Enter customer phone number: ";
cin >> rec.phoneNum;
cout << "Enter beginning account balance: ";
cin >> rec.balance;
ref.write(reinterpret_cast<char*>(&rec), sizeof(rec));
}
rec being just a 3 member struct. Any ideas why this wouldn't work? I appreciate any help.
Note: I do have to use .write() as opposed to << as per my assignment
If you are using Visual Studio: maybe you are looking in the wrong directory, the file will be created in Projects\Project_Name\Project_Name when debugging, not in Projects\Project_Name\Debug.
Streams work just like cout and cin. You would probably be better off using
ref << rec.name << "," << rec.phoneNum << "," << rec.balance << endl;