How to create a valid write to a binary file [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have created student data to be stored in a binary file but this file is completely broken.
What am I doing wrong?
there was no problem with the text file stored in the notepad.
now after entering after starting the program, it only writes this:
& Ô LC_CTYPE = C; LC_M0 & Ô RIC = C; LC_TIME = C
Is there someone able to help me with this? Have a nice day:)
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
struct Student{
string imie;
string nazwisko;
int nrAlbumu;
int wiek;
float srOcen;
} dane;
int main(){
Student dane;
cout << "Podaj imie:" << endl;
cin >> dane.imie;
cout << "Podaj nazwisko:" << endl;
cin >> dane.nazwisko;
cout << "Podaj nrAlbumu:" << endl;
cin >> dane.nrAlbumu;
cout << "Podaj wiek:" << endl;
cin >> dane.wiek;
cout << "Podaj srednia ocen:" << endl;
cin >> dane.srOcen;
cout << "Student " << dane.imie <<" "<< dane.nazwisko << " o numerze albumu: " << dane.nrAlbumu << " ma lat " << dane.wiek << " ma srednia ocen rowna: " << dane.srOcen << endl;
//-------writing to the file starts here-------------------------
ofstream ofs("dane.bin", ios::binary);
Student* student = new Student;
student->imie;
student->nazwisko;
student->nrAlbumu;
student->wiek;
student->srOcen;
ofs.write((char*)(student), sizeof(Student));
ofs.close();
delete student;
//-------------reading starts here ---------------------------
ifstream ifs("dane.bin", ios::binary);
char* temp = new char[sizeof(Student)];
ifs.read(temp, sizeof(Student));
Student* student2 = (Student*)(temp);
cout << "Student " << dane.imie <<" "<< dane.nazwisko << " o numerze albumu: " << dane.nrAlbumu << " oraz ma lat " << dane.wiek << " ma srednia ocen rowna: " << dane.srOcen <<" Potwierdzenie do zapisu i odczytu!" << endl;
delete student;
return 0;
}

The Student object contains std::string members. That is an object that is not trivially-copyable, thus the Student class is not trivially-copyable, so you cannot simply read and write this type to a binary file by merely copying the bytes to and from the file.
If you want more proof, what does sizeof do? What value does it return? The sizeof is a compile-time value. Now let's say that std::string has a size() of 1000 characters. The sizeof had no idea how many characters at runtime the std::string will have. Thus that entire line makes no sense and will not work.
If you did the following, given that there would be 1000 characters in one of the std::string members:
std::cout << sizeof(Student);
what value do you get? I bet it isn't 1000 or greater.
Here is a quick program illustrating the problem:
#include <type_traits>
#include <string>
#include <iostream>
struct Student{
std::string imie;
std::string nazwisko;
int nrAlbumu;
int wiek;
float srOcen;
};
struct Student2{
char imie[20];
char nazwisko[20];
int nrAlbumu;
int wiek;
float srOcen;
};
int main()
{
Student s;
s.imie = std::string(1000, ' ');
std::cout << "The number of characters is: " << s.imie.size() << "\n";
std::cout << "The sizeof(Student) is: " << sizeof(s) << "\n";
std::cout << "Is Student trivially copyable? " << (std::is_trivially_copyable<Student>()?"Yes":"No") << "\n";
std::cout << "Is Student2 trivially copyable? " << (std::is_trivially_copyable<Student2>()?"Yes":"No") << "\n";
}
Output:
The number of characters is: 1000
The sizeof(Student) is: 80
Is Student trivially copyable? No
Is Student2 trivially copyable? Yes
Note that if you used char arrays instead of std::string, then the struct becomes trivially copyable and then can be used to write to a binary file in the way you're currently doing it now.
However the disadvantage is that you are limited to the number of characters (20 in my example). If you still want to use std::string, you have to write the struct in individual pieces, taking care of each std::string accordingly as specified by this answer.

Related

Using += operator on a string in order to add .txt for file output

I'm currently taking the first CompSci class in college and one of my assignments wants me to take a name as input, then use that name in order to make a file with that same name, but with ".txt" at the end.
It prints out what it should be named as, but I can't find any file under the name I tried inputting.
Does anyone know what went wrong?
#include<iostream>
#include<fstream>
#include<iomanip>
#include<math.h>
using namespace std;
int main()
{
string des_name;
string ship_name;
float ship_mass;
float e_thrust;
const float g0 = 9.8;
cout << "Designer name: " << endl;
getline(cin , des_name);
cout << "Ship Name: " << endl;
cin >> ship_name;
ship_name += ".txt";
cout << "Ship Mass: " << endl;
cin >> ship_mass;
cout << "Engine Thrust: " << endl;
cin >> e_thrust;
cout << "File written for " << ship_name;
ofstream output_file;
output_file.open(des_name.c_str());
output_file << "##########" << ship_name << "##########" << endl << endl;
output_file << "Designed by: " << setw(10) << des_name;
}
Hmm, you open a file based on des_name, yet it's ship_name that you appended .txt to:
ship_name += ".txt";
:
output_file.open(des_name.c_str());
I'd be looking at that anomaly as a starting point :-)

issues with getline overload function

I am having issues with cin.getline(). When I put it into the below program, it is giving an error:
no instance of overload function (ect) matches the argument list
I am also having an issue with my variable nx. The compiler says that it cannot be a constant, but I'm not sure how it is.
Here is my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//create a class for one book
class Book
{
//member variables
public:
string title;
string author;
int year;
//function to print the book details
void print()
{
cout << "Title: " << title << endl;
cout << "Authot: " << author << endl;
cout << "Year: " << year << endl;
}
};
int main()
{
std::string filename, temp;
//prompt the user to enter the file name
cout << "Enter filename: ";
cin >> filename;
//open the file
fstream file;
file.open(filename.c_str());
int nx;
//read the first line of the file to know the number of books
file >> nx;
//move to the next line of the file
std::cin.getline(file, temp);
//allocate an array of n Book
Book books[nx];
//read the data for n books from the file
for (int i = 0; i < nx; i++)
{
//read file and initialize the books array
std::cin.getline(file, books[i].title);
std::cin.getline(file, books[i].author);
file >> books[i].year;
//move to the next line of the file
getline(file, temp);
}
//Display the output
cout << "Books found: " << nx << endl;
for (int i = 0; i < nx; i++)
{
cout << "\nBook " << i + 1 << ":" << endl;
cout << "Title: " << books[i].title << endl;
cout << "Author: " << books[i].author << endl;
cout << "Year: " << books[i].year << endl;
}
}
The 2-parameter std::cin.getline() method does not take a std::fstream or a std::string as parameters. It takes a char* and a std::streamsize instead, as it is meant to fill a char[] buffer. To fill a std::string from a stream, you need to use the standalone std::getline() function instead, eg:
std::getline(file, temp);
...
std::getline(file, books[i].title);
...
As for the "constant" error relating to your nx variable, the problem is on this line:
Book books[nx];
You are trying to declare a fixed-sized array using a size that is not known until runtime. You can't do that in standard C++, an array's size must be known at compile-time instead. Otherwise, you have to use new[] or std::vector to allocate the array dynamically at runtime instead, eg:
Book* books = new Book[nx];
...
delete[] books;
Or:
#include <vector>
std::vector<Book> books(nx);
Demo
On a side note:
When you want to discard content from an istream up to the next '\n' character, you can use the stream's ignore() method instead of std::getline(), that way you are not wasting memory unnecessarily for an unused std::string, eg:
#include <limits>
//move to the next line of the file
//std::getline(file, temp);
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Also, you have defined a print() method in Book, but you are not actually using it. Your final display loop can do this instead:
//Display the output
cout << "Books found: " << nx << endl;
for (int i = 0; i < nx; i++)
{
cout << "\nBook " << i + 1 << ":" << endl;
/*
cout << "Title: " << books[i].title << endl;
cout << "Author: " << books[i].author << endl;
cout << "Year: " << books[i].year << endl;
*/
books[i].print();
}

C++: output with extra zero in struct

I am the beginner of C++, just start to learn struct.
I create the struct and read the data from a file.
Here is my file:
John Smith 26832904 1657 Commerce st Flushing NY 11204 7183942833 company01 962 51
I successfully input the data to the struct. The output is perfect but just having a zero at the end, which can drive me crazy.
This is my entire code:
#include<iostream>
#include<string>
#include<fstream>
#include<iomanip>
using namespace std;
struct nametype
{
string first;
string last;
};
struct addresstype
{
string address1;
string address2;
string address3;
string city;
string state;
string zip;
};
struct contacttype
{
string home;
string person;
};
struct employeeType
{
nametype name;
string id;
addresstype address;
contacttype contact;
string worklocate;
double basewage;
int carsale;
};
int main()
{
ifstream infile;
infile.open("employeeInfor.txt");
if (!infile)
{
cout << "Error." << "\n";
}
employeeType employee;
employee.basewage = 0.0;
employee.carsale = 0;
infile >> employee.name.first >> employee.name.last
>> employee.id
>> employee.address.address1 >> employee.address.address2
>> employee.address.address3 >> employee.address.city
>> employee.address.state >> employee.address.zip
>> employee.contact.home >> employee.contact.person
>> employee.worklocate
>> employee.basewage >> employee.carsale;
cout << employee.name.first <<" "<<employee.name.last
<< " " << employee.id
<< " " << employee.address.address1 << " " << employee.address.address2
<< " " << employee.address.address3 << " " << employee.address.city
<< " " << employee.address.state << " " << employee.address.zip
<< " " << employee.contact.home << " " << employee.contact.person
<< " " << employee.worklocate
<< " " << employee.basewage << " " << employee.carsale << "\n";
infile.close();
system("pause");
return 0;
}
I output the data. That's what I got:
The end of the extra 0 is not my expectation.
By the way. I want to put the struct within the array. To make this function work for more than one employee. I know should be create the struct like, employeeType employees[5];
I just stuck from reading the file. Can't keep moving.
You try to read 14 values, but your input file contains only 13. So the last value you output, employee.carsale is 0 as in the initialization.
You read 14 parameters but your file only provides 13. Maybe you forgot to add a column in employeeInfor.txt.

Getline not recognized by compiler

I have just started C++ after working with C for almost a year. I'm writing a program for a user to input info about a song. I read that I should use getline() to read strings with spaces. Here is my code:
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
int main()
{
typedef struct Song
{
char title[20];
char album[20];
char artist[20];
int year;
} song;
//store song info
Song Input;
char inputStr[20];
int inputYear;
cout << "Enter the name of a song: ";
getline(cin, inputStr);
strcpy(Input.title, inputStr);
cout << "Enter the album of your song: ";
getline(cin, inputStr);
strcpy(Input.album, inputStr);
cout << "Enter the artist of your song: ";
getline(cin, inputStr);
strcpy(Input.artist, inputStr);
cout << "Enter the year your song was released: ";
cin >> inputYear;
Input.year = inputYear;
//print
cout << "Song title: " << Input.title << endl;
cout << "From album: " << Input.album << endl;
cout << "Artist: " << Input.artist << endl;
cout << "Released: " << Input.year << endl;
return 0;
}
My compiler1 throws 3 errors, one for each of the getline() calls, not recognizing getline() despite the fact I have #include <string>. I have looked up sample usage of the getline() function.
Thanks for any help.
1I have wondered if this problem might concern an issue with the standard of C++ that my compiler supports. I did a bit of research and I did not find anything that helped me learn which standard I am using. Here's some info:
I'm using Terminal on Mac.
After g++ version:
Configured with: --prefix=/Applications/Xcode.app/Cont.../usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.42)
These lines seem to be the only ones of use here, but I could give more info. If someone has any idea which standard of C++ this is, whether it's C++11, or C++14, or otherwise, that would also be very helpful. Thanks again.
UPDATE:
started from scratch, tried to take as much of your advice as possible while still sticking to some of what I know. No errors and works just as I hoped. Thanks for all your help.
New code:
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
struct Song
{
string title;
string artist;
string album;
string year;
}song;
int main()
{
Song Input;
cout << "Song? ";
getline(cin, Input.title);
cout << "Artist? ";
getline(cin, Input.artist);
cout << "Album? ";
getline(cin, Input.album);
cout << "Year? ";
getline(cin, Input.year);
cout << "Song: " << Input.title << endl;
cout << "Artist: " << Input.artist << endl;
cout << "Album: " << Input.album << endl;
cout << "Year: " << Input.year << endl;
return 0;
}
The version of getline you are using takes a std::string as a parameter, not an array of char. If you want to use an array of char (and you shouldn't), you need to use the member function version:
cin.getline( some_char_array, array_size );
I would switch from using char arrays to using string's everywhere. For example I would do your code like this:
#include <string>
#include <iostream>
struct Song{
std::string title;
std::string album;
std::string artist;
int year;
};
int main()
{
//store song info
Song Input;
int inputYear;
std::cout << "Enter the name of a song: ";
getline(std::cin, Input.title);
std::cout << "Enter the album of your song: ";
getline(std::cin, Input.album);
std::cout << "Enter the artist of your song: ";
getline(std::cin, Input.artist);
std::cout << "Enter the year your song was released: ";
std::cin >> Input.year;
//print
std::cout << "Song title: " << Input.title << '\n';
std::cout << "From album: " << Input.album << '\n';
std::cout << "Artist: " << Input.artist << '\n';
std::cout << "Released: " << Input.year << std::endl;
return 0;
}
My preference is to not use using namespace std; but there's nothing wrong with it. Notice that using strings directly I don't need to copy things. I can use getline to do all that for me. I also don't need to worry about overrunning the size of the char array because string does that for me as well.

Reading a text file and saving every line as a string (C++)

I have a little question. I'm currently doing a school assignment in c++ and the task is to have something similar to a small library, where the user can ask to look at a book and then the program will print out the release year, author, how many pages etc etc. The assignment is focused on vectors and arrays, but I thought a smart way of doing it could be to have the release years in a text file and then save those years in an array. When I first it, everything was saved in characters, (meaning "1","8","8","5"), when I'd actually like it to save every line in the text document as a string in the array, or something similar (like this: "1885",). I couldn't really figure out how to split them up into strings then. I then talked a bit to a friend and this is where I am with my code now, it's not really working and at the moment I have no idea how I am supposed to solve it. Main problem is I don't know how to read and save every line in the text document as a string, however I am grateful for any help that would make me be able to print out a single year from the text document, in any other way.
This is what my code looks like:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
#include <istream>
using namespace std;
void book();
void readFile(int input);
void oddEven();
void stringLiner();
void factorial();
int main()
{
int input;
while (input != 0)
{
cout << "Hello. Welcome to the first, truly big, assignment in this programming course." << endl;
cout << "Which part do you wish to access?" << endl;
cout << "1. Book program" << endl;
cout << "2. 2 arrays - One EVEN ~ One ODD" << endl;
cout << "3. The one at a time string" << endl;
cout << "4. Factorial array" << endl;
cout << "0. Exit " << endl;
cin >> input;
switch (input)
{
case 1:
book();
break;
}
}
}
void book() //This is the function used to do the book thing
{
cout << string( 100, '\n' );
int input;
string year[5] = {"1883"/*Treasure Island*/ }; //Array for the years the books were written
string author[5] = {"Robert Louis Stevenson"/*Treasure Island*/, "yollo"}; //Array for the authors
string pages[5] = {"304"/*Treasure Island*/,"420" }; //Array for the number of pages
string books[5] = {"Treasure Island", "Swagolo" }; //Array for the name of the books
cout << "You have chosen to look at books." << endl;
cout << "These are the books in the library. Pick one to see what year it was written in, what author wrote it and how many pages it contains. " << endl;
cout << "These are the books in the library: " << endl;
for (int i = 0; i<5; i++) //Loop to display all the books + what number to press to access them.
{
cout << i+1 << " " << books[i] << endl;
};
cout << "Please type a number to look at that book. " << endl;
cin >> input;
int TresIsl = input-1;
switch (input) //Switch case to chose which book to look at.
{
case 1: //Info about Treasure Island
cout << "This is " << books[TresIsl] << " and this is some info. " << endl << endl;
cout << books[TresIsl] << " was released in " ;
readFile(input);
cout << " and it was written by " << author[TresIsl] << ". ";
cout << "This book contains " << pages[TresIsl] << " pages. " << endl;
break;
case 2:
cout << "This is " << books[TresIsl] << " and this is some info. " << endl << endl;
cout << books[TresIsl] << " was released in " ;
readFile(input);
cout << " and it was written by " << author[TresIsl] << ". ";
cout << "This book contains " << pages[TresIsl] << " pages. " << endl;
break;
}
}
void readFile(int input)
{
ifstream file("year.txt");
int numlines = 0;
int numMaxLines = 5;
vector<string> lines (numMaxLines);
while(numlines < numMaxLines && !file.eof())
{
getline(file, lines);
numlines++;
}
cout << lines[input];
}
The other void functions are for other tasks in this assignment which I didn't include now, I just copy pasted the code where they were included. Also please don't mind the slightly childish stuff in the code.
Also I am very sorry if this breaks any rules for the forum or something similar. I tried to find another topic like this for c++, but I couldn't find anything helpful.
It's not clear what exactly your problem is, but assuming that you want to read a file line-by-line and get a vector of those lines, something like this would do it:
std::vector<std::string> readLines(const std::string& filename)
{
std::vector<std::string> lines;
std::ifstream input(filename);
std::string line;
while (std::getline(input, line))
{
lines.push_back(line);
}
return lines;
}
if any one's still got a question, a friend and me discussed it and he helped me a bit, and we got a code that works in my case at least, so I thought I'd show it to you:
void readFile(int input)
{
ifstream file("year.txt");
string in;
vector<string> lines;
if (file.is_open())
{
while ( getline (file, in) )
{
lines.push_back(in);
}
cout << in;
}
file.close();
cout<<lines[input-1]<<endl;
}
The cout in the end I guess is unnecessary in some cases, but this worked for me and my homework. Thanks for everyone's help anyways.