fread is reading garbage in file - c++

I am working on my assignment and faced a problem with fread() in C++. When I modify the name in my file it modifies it perfectly as I want but the problem occurs when I try to read the file after that, it reads the whole file but it does not stop after that it's running total 146 times whereas there are only 3 names.
My code:-
#include <bits/stdc++.h>
using namespace std;
struct person{
int id;
string fname;
}s;
void write(){
FILE *outfile;
struct person input;
int num,ident;
string sname[] = {"a","b","c"};
outfile = fopen ("C:\\Users\\Amritesh\\Desktop\\students.txt","wb");
if (outfile == NULL)
{
fprintf(stderr, "\nError opend file\n");
exit (1);
}
scanf("%d",&num);
for(int i=0;i<num;i++){
s.fname = sname[i];
cin >> s.id;
fwrite (&s, sizeof(s), 1, outfile);
}
fclose(outfile);
}
void read(){
FILE *file1;
int i=0;
file1 = fopen ("C:\\Users\\Amritesh\\Desktop\\students.txt","r");
while(fread(&s, sizeof(s), 1, file1) == 1) {
cout << "ID " << s.id << " Name " <<s.fname << endl;
}
fclose (file1);
}
void modify(){
FILE *file;
file = fopen ("C:\\Users\\Amritesh\\Desktop\\students.txt","r+");
while(fread(&s, sizeof(s), 1, file)) {
if(s.fname == "a"){
s.fname = "d";
fseek(file,-sizeof(s),SEEK_CUR);
fwrite (&s, sizeof(s), 1,file);
}
}
fclose (file);
}
int main(){
write();
modify();
read();
}
Edited code:-
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct person
{
int id;
string fname;
}s,temp;
void read()
{
int num;
ifstream fin;
fin.open("C:\\Users\\Amritesh\\Desktop\\student.txt",ios::in);
fin.seekg(0,ios::beg);
//scanf("%d",&num);
while(fin){
cout << s.fname << s.id << endl;
}
fin.close();
}
void write(){
int i=0;
ofstream fout;
fout.open("C:\\Users\\Amritesh\\Desktop\\student.txt");
while(i!=2) {
cin >> s.id >> s.fname;
fout << "ID " << s.id << " Name " <<s.fname << endl;
i++;
}
fout.close();
}
void modify(){
fstream mod;
mod.open ("C:\\Users\\Amritesh\\Desktop\\student.txt");
while(mod) {
if(s.fname == "a"){
s.fname = "d";
mod.seekg(-sizeof(s),ios::cur);
mod << s.fname;
}
}
mod.close();
}
int main(){
write();
read();
modify();
}
Thanks for any answer!

Here are three ideas based on our discussion. I'll start with free functions for reading and writing a person object since it looks like you're at that stage right now. I'll move on to adding member functions in your person class and end with adding stream operators for convenience.
An example of free (non-member) read and write functions:
#include <iostream>
#include <string>
#include <fstream>
struct person {
int id;
std::string fname;
};
std::ostream& write(std::ostream& os, const person& p) {
os << p.id << ',' << p.fname << '\n'; // stream out the properties of a person
return os; // look at the next example for an alternative doing the same thing
}
std::istream& read(std::istream& is, person& p) {
// extract "id" and if it succeeds, check if the next char is a , char
if(is >> p.id && is.peek() == ',') {
is.ignore(); // step over the , char
std::getline(is, p.fname); // read the rest of the line into p.fname
} else {
// we didn't get id or the , char, so set the stream in a failed state
is.setstate(is.failbit);
}
return is;
}
int main() {
// write to file
{
std::ofstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test1{10, "Foo Bar"};
person test2{20, "Apa Bepa"};
write(file, test1);
write(file, test2);
}
// read from file
{
std::ifstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test;
while(read(file, test)) {
std::cout << test.fname << '\n';
}
}
}
An example of making read and write member functions in person:
#include <iostream>
#include <string>
#include <fstream>
struct person {
int id;
std::string fname;
std::ostream& write(std::ostream& os) const {
// this does the same thing as in the first example
return os << id << ',' << fname << '\n';
}
std::istream& read(std::istream& is) {
if(is >> id && is.peek() == ',') {
is.ignore(); // step over the , char
std::getline(is, fname);
} else {
is.setstate(is.failbit); // we didn't get id or the , char
}
return is;
}
};
int main() {
// write to file
{
std::ofstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test1{10, "Foo Bar"};
person test2{20, "Apa Bepa"};
test1.write(file);
test2.write(file);
}
// read from file
{
std::ifstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test;
while(test.read(file)) {
std::cout << test.fname << '\n';
}
}
}
Member functions supported by stream operators:
#include <iostream>
#include <string>
#include <fstream>
struct person {
int id;
std::string fname;
std::ostream& write(std::ostream& os) const {
return os << id << ',' << fname << '\n';
}
std::istream& read(std::istream& is) {
if(is >> id && is.peek() == ',') {
is.ignore(); // step over the , char
std::getline(is, fname);
} else {
is.setstate(is.failbit); // we didn't get id or the , char
}
return is;
}
};
// stream operators calling member functions
std::ostream& operator<<(std::ostream& os, const person& p) { return p.write(os); }
std::istream& operator>>(std::istream& is, person& p) { return p.read(is); }
int main() {
// write to file
{
std::ofstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test1{10, "Foo Bar"};
person test2{20, "Apa Bepa"};
file << test1 << test2; // calling operator<< for each person object
}
// read from file
{
std::ifstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test;
while(file >> test) { // extract one person at a time using operator>>
std::cout << test.fname << '\n';
}
}
}

Related

Writing to an array class will not cout

The code runs, but I cannot get cout to work. Please help me, I am a beginner, and really struggling with getting the contents of my array to output.
cout << myArray[0].getSquareName(); is the line that never cout's.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class cSquare {
public:
string SquareName;
string getSquareName() const;
void setSquareName(string);
friend std::istream & operator >> (std::istream & is, cSquare & s);
};
// set method
void cSquare::setSquareName(string squareName)
{
squareName = SquareName;
}
//square name get method
string cSquare::getSquareName() const
{
return SquareName;
}
ostream & operator << (ostream & os, const cSquare & s)
{
os << s.getSquareName() << ' ';
return os;
}
istream & operator >> (istream & is, cSquare & s)
{
is >> s.SquareName;
return is;
}
int main()
{
string discard;
int i = 0;
const int MAX_SIZE = 26;
ifstream monopoly("monopoly.txt", ios::in);
if (monopoly.is_open())
{
cSquare myArray[MAX_SIZE];
getline(monopoly, discard);
string sname; //string to store what I read in from my file
while (i < MAX_SIZE && monopoly >> sname)
{
myArray[i].setSquareName(sname);//stores the string read in into the array
cout << myArray[0].getSquareName(); //it never cout's this
i++;
}
}
}
Your setSquareName() method is assigning the object's SquareName member to the input parameter, which is wrong. You need to do the opposite instead, eg:
void cSquare::setSquareName(string sname)
{
//sname = SquareName;
SquareName = sname;
}
Also, this line:
cout << myArray[0].getSquareName();
Should be this instead:
cout << myArray[i];
With those 2 changes, the code works.
Demo

C++ unable to open file by passing string or c_str() as reference

first post sorry if messy. I looked around for an answer to this and I tried using c_str() but that solution wasn't working. The problem I'm having is that this program triggers the !inFile if statement each time I run it. This program came from a textbook I have and I can't figure out why it isn't creating the files. I've tried using c_str(), I've tried typing in "foo.txt" for the file name, but nothing is working. If anybody can help thank you.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
class Encryption
{
protected:
ifstream inFile;
ofstream outFile;
public:
Encryption(const string& inFileName, const string& outFileName);
virtual ~Encryption();
virtual char transform(char ch) const = 0;
virtual void encrypt() final;
};
Encryption::Encryption(const string& inFileName, const string& outFileName)
{
inFile.open(inFileName.c_str());
outFile.open(outFileName.c_str());
if (!inFile)
{
cout << "The file " << inFileName << " cannot be opened.";
exit(1);
}
if (!outFile)
{
cout << "The file " << outFileName << " cannot be opened.";
exit(1);
}
}
Encryption:: ~Encryption()
{
inFile.close();
outFile.close();
}
void Encryption::encrypt()
{
char ch;
char transCh;
inFile.get(ch);
while (!inFile.fail())
{
transCh = transform(ch);
outFile.put(transCh);
inFile.get(ch);
}
}
class SimpleEncryption : public Encryption
{
public:
char transform(char ch) const override
{
return ch + 1;
}
SimpleEncryption(const string& inFileName, const string& outFileName) : Encryption(inFileName, outFileName)
{
}
};
int main()
{
string infileName, outFileName;
cout << "name of file to encrypt: ";
cin >> infileName;
cout << "enter file to write to: ";
cin >> outFileName;
SimpleEncryption cipher(infileName, outFileName);
cipher.encrypt();
system("pause");
return 0;
}

Read data from a file into struct and add struct to a vector (to create a vector of structs)

This question has been asked before but the other question/answers used concepts I'm not yet familiar with in C++.
I need to read data from a file into a vector of structs.
I have the following code but I'm confused about what to put in (....), that is if I have the correct logic.
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
struct Parts{
std::string partNum;
char partClass;
int stock;
float cost;
};
bool readFile(std::vector <Parts>&);
int displayMenu();
int main(){
std::vector <Parts> pVector;
readFile(pVector);
if (!readFile(pVector)){
std::cout << "Error reading file!" << std::endl;
}
else{
displayMenu();
}
return 0;
}
bool readFile(std::vector <Parts> &pVector){
std::ifstream inputFile("parts.txt");
if (inputFile.fail()){
std::cout << "Error reading file!" << std::endl;
return false;
}
else{
while (....){
pVector.emplace_back(....);
}
return true;
}
}
Sample lines from the file:
P-42936 A 18 129.79
P-43179 A 47 35.60
P-43264 B 31 103.81
P-43367 B 5 32.39
P-43378 A 46 6.38
P-43622 A 10 155.36
You want that :
bool readFile(std::vector <Parts> &pVector){
std::ifstream inputFile("parts.txt");
if (inputFile.fail()){
std::cout << "Error reading file!" << std::endl;
return false;
}
else {
Parts part;
while (inputFile >> part.partNum >> part.partClass >> part.stock >> part.cost)
pVector.emplace_back(part);
return true;
}
}
In main you call two time the read function :
readFile(pVector);
if (!readFile(pVector)){
very probably the first call must be removed
It can be also interesting to define the operator >> for Parts rather than to have the code doing that in readFile
So :
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
struct Parts{
std::string partNum;
char partClass;
int stock;
float cost;
};
std::istream & operator >>(std::istream & is, Parts & part) {
if (is >> part.partNum >> part.partClass >> part.stock)
is >> part.cost;
return is;
}
bool readFile(std::vector <Parts>&);
//int displayMenu();
int main(){
std::vector <Parts> pVector;
if (!readFile(pVector)){
std::cout << "Error reading file!" << std::endl;
}
else{
//displayMenu();
// to check, of course operator << can be defined too
for (auto p : pVector)
std::cout << p.partNum << '/' << p.partClass << '/' << p.stock << '/' << p.cost << std::endl;
}
return 0;
}
bool readFile(std::vector <Parts> &pVector){
std::ifstream inputFile("parts.txt");
if (inputFile.fail()){
std::cout << "Error reading file!" << std::endl;
return false;
}
else {
Parts part;
while (inputFile >> part)
pVector.emplace_back(part);
return true;
}
}
Compilation and execution:
pi#raspberrypi:/tmp $ g++ -Wall r.cc
pi#raspberrypi:/tmp $ cat parts.txt
P-42936 A 18 129.79
P-43179 A 47 35.60
P-43264 B 31 103.81
P-43367 B 5 32.39
P-43378 A 46 6.38
P-43622 A 10 155.36
pi#raspberrypi:/tmp $ ./a.out
P-42936/A/18/129.79
P-43179/A/47/35.6
P-43264/B/31/103.81
P-43367/B/5/32.39
P-43378/A/46/6.38
P-43622/A/10/155.36
pi#raspberrypi:/tmp $
I suggest adding overloads for operator>> and operator<<:
#include <iostream>
#include <string>
#include <vector>
struct Part { // I renamed it because it only holds info about one part
std::string partNum;
char partClass;
int stock;
float cost;
};
std::istream& operator>>(std::istream& is, Part& p) {
return is >> p.partNum >> p.partClass >> p.stock >> p.cost;
}
std::ostream& operator<<(std::ostream& os, const Part& p) {
return os << p.partNum << ' ' << p.partClass << ' ' << p.stock << ' ' << p.cost;
}
This makes extracting or printing one Part easy:
bool readFile(std::vector<Part>& pVector){
std::ifstream inputFile("parts.txt");
if(inputFile) {
Part tmp;
while(inputFile >> tmp) // extract one Part at a time using operator>>
pVector.emplace_back(tmp);
return true;
} else {
std::cout << "Error reading file!" << std::endl;
return false;
}
}

How to search line by line in a text file

123 Michael
456 Calimlim
898 Mykfyy
999 Kyxy
657 mykfyy
898 Help
I'm creating a student attendance keeper system. One of the features of my system is that the student need to register(his/her id and name) first to access the system (login with his/her id)
The problem is that i don't know and i don't want my student to have a similar ID number Like(e.g 898 Mykfyy and 898 Help)
I'm using fstream in my system. I've been thinking that if I want to avoid the duplication i need to Read(ifstream) the .txt file before register(oustream). But i dont know how to read line by line and check if the ID(898) is already use/existed
In C++ one wouldn't deal with lines, but with objects:
#include <limits>
#include <cstdlib>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <iterator>
#include <algorithm>
struct student_t
{
unsigned id;
std::string name;
};
bool operator==(student_t const &lhs, student_t const &rhs)
{
return lhs.id == rhs.id;
}
std::ostream& operator<<(std::ostream &os, student_t const &student)
{
return os << student.id << ' ' << student.name;
}
std::istream& operator>>(std::istream &is, student_t &student)
{
unsigned id;
if (!(is >> id))
return is;
std::string name;
if (!std::getline(is, name)) {
return is;
}
student = student_t{ id, name };
return is;
}
int main()
{
char const *filename{ "test.txt" };
std::ifstream input{ filename };
if (!input.is_open()) {
std::cerr << "Couldn't open \"" << filename << "\" for reading :(\n\n";
return EXIT_FAILURE;
}
std::vector<student_t> students{ std::istream_iterator<student_t>{ input }, std::istream_iterator<student_t>{} };
input.close();
std::copy(students.begin(), students.end(), std::ostream_iterator<student_t>{ std::cout, "\n" });
student_t new_student;
while (std::cout << "New Student?\n", !(std::cin >> new_student)) {
std::cerr << "Input error :(\n\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
auto it{ std::find(students.begin(), students.end(), new_student) };
if (it != students.end()) {
std::cerr << "Sorry, but a student with id " << new_student.id << " already exists :(\n\n";
return EXIT_FAILURE;
}
std::ofstream output{ filename, std::ios::app };
if (!output.is_open()) {
std::cerr << "Couldn't open \"" << filename << "\" for writing :(\n\n";
return EXIT_FAILURE;
}
output << new_student << '\n';
std::cout << "New student [" << new_student << "] added :)\n\n";
}
The easiest way to do it is probably using std::getline to get the current line as a string:
using namespace std;
ifstream in(fileName);
string line;
while(getline(in, line))
{
// --do something with the line--
}
You will then need to parse each line to get the correct ID
Edit: updated to remove eof()
Depends on how you implemented it.
I suppose the number of people isn't too large so I would just check the Id's before a new ID is added.
Something like
If ID exists, not add.

C++ read line to class vector

I have next c++ class called "Contact":
class Contact
{
private:
std::string contactName;
double subscriptionPrice;
int minutesIncluded;
public:
Contact(const std::string &contactName, double subscriptionPrice,
int minutesIncluded) : contactName(contactName), subscriptionPrice(subscriptionPrice), minutesIncluded(minutesIncluded)) {}
Contact() {
}
...gettetrs and setters
}
I have text file with one or more contacts in format:
asd,1.00000,1
In main method I have method that add properly vector of contacts in this text file. Problem is when I try to read from it. My target is to convert text file into vector of contacts. Method I use is next:
void phonebook_load(vector<Contact> &contacts)
{
string line;
ifstream phonebook_file;
vector<std::string> lines;
phonebook_file.open(phonebook_filename);
if(!phonebook_file.is_open())
cout << "Phonebook file could not be openned !!!" << endl;
else
{
while (phonebook_file.good())
{
for (string line; getline(phonebook_file, line, ','); )
lines.push_back(line);
}
phonebook_file.close();
}
}
I have two options:
Read line by line (which I cannot split by ",")
Split by "," which print every property of contact on new line, and I don't see how tho handle it from there.
What should I change in my method in order to read file line by line and properly convert it to vector<Contact>
Provide stream extraction and stream insertion operators for your type:
#include <string>
#include <vector>
#include <iterator>
#include <fstream>
#include <iostream>
class Contact
{
private:
std::string contactName;
double subscriptionPrice;
int minutesIncluded;
public:
Contact() {}
Contact(const std::string &contactName, double subscriptionPrice, int minutesIncluded)
: contactName { contactName },
subscriptionPrice { subscriptionPrice },
minutesIncluded { minutesIncluded }
{}
// declare the stream extraction and stream insertion operators as firends
// of your class to give them direct access to members without the need for
// getter and setter functions.
friend std::istream& operator>>(std::istream &is, Contact &contact);
friend std::ostream& operator<<(std::ostream &os, Contact const &contact);
};
std::istream& operator>>(std::istream &is, Contact &contact)
{
std::string contact_name;
if (!std::getline(is, contact_name, ',')) // use getline with a delimiter
return is; // to allow whitespace in names
// which >> doesn't
char seperator;
double subscription_price;
int minutes_included;
if (!(is >> subscription_price >> seperator >> minutes_included) || seperator != ',') {
is.setstate(std::ios::failbit);
return is;
}
contact = Contact{ contact_name, subscription_price, minutes_included };
return is;
}
std::ostream& operator<<(std::ostream &os, Contact const &contact)
{
os << contact.contactName << ", " << std::fixed << contact.subscriptionPrice
<< ", " << contact.minutesIncluded;
return os;
}
int main()
{
std::ifstream is{ "test.txt" };
std::vector<Contact> contacts{ std::istream_iterator<Contact>{ is },
std::istream_iterator<Contact>{} };
for (auto const &c : contacts)
std::cout << c << '\n';
}