c++ munmap_chunk(): invalid pointer: - c++

I'm trying to read and write to a binary file, it mostly works however
upon returning 0 in main ill get munmap_chunk(): invalid pointer: error
ill get a memory dump and a stack trace when the program closes
https://imgur.com/a/CSBg8
here is a screenshot of the memory dump and stack trace, I don't know how to read this
#include <fstream>
#include <iostream>
using namespace std;
struct player{
string name;
};
bool WriteTest(player playerData){
// Create our objects.
fstream filestream;
//attempt to open file and then read first player
filestream.open ("file.bin", ios::binary | ios::out);
filestream.write(reinterpret_cast <char *> (&playerData),
sizeof(playerData));
if(filestream.fail()){
//create file if there is no file
cout << "write open failed" << endl;
filestream.close();
return false;
}
filestream.close();
cout << "write sucsess" << endl;
return true;
}
player ReadTest(){
player playerData;
// Create our objects.
fstream filestream;
//attempt to open file and then read first player
filestream.open ("file.bin", ios::binary | ios::in);
filestream.read(reinterpret_cast <char *> (&playerData),
sizeof(playerData));
if(filestream.fail()){
//create file if there is no file
cout << "read open failed" << endl;
filestream.close();
return playerData;
}
filestream.close();
cout << "read sucsess" << endl;
return playerData;
}
void displayPlayerData(player playerData){
cout << " Name :" << playerData.name << endl;
}
int main(){
player source;
source.name = "bap";
displayPlayerData(source);
WriteTest(source);
getchar();
player playerData = ReadTest();
displayPlayerData(playerData);
return 0;
}

Your player struct contains a std::string, thus the type is not C-layout compatible.
Thus using functions such as:
filestream.write(reinterpret_cast <char *> (&playerData), sizeof(playerData));
and
filestream.read(reinterpret_cast <char *> (&playerData), sizeof(playerData));
will not work correctly.
The std::string contains a pointer to a buffer of characters (leaving aside the short string buffer if the string class is implemented that way), and writing std::string directly to a file will totally miss those characters since you will only be writing a pointer value.
Additionally, reading into playerData will not initialize the std::string with the data. Instead you'll just be corrupting the std::string object with garbage you read from the file. This is more than likely where your program fails -- you are trying to use a corrupted std::string object.
But the tell-tale sign why this could never work is that sizeof(player) is a fixed, compile-time value, and it is the third parameter in the read and write functions. When run here, the sizeof(player) is 32. So you will always be reading / writing 32 bytes of data. What if the std::string name; member holds 1,000 characters? How will you be able to read/write 1,000 characters by specifying you only want to read/write 32 bytes? That could never work.
The correct way to handle this is either:
1) Change the std::string member to an array of char. Then the player class will be C-layout compatible and can be read and written using your techniques of binary file reading / writing
or
2) Properly serialize the string data to the file. You can overload operator >> and operator << to read/write the string data, or use a library such as Boost::Serialize.

Related

c++ read file in binary mode into object failed but is ok in stdin and file read in text

It may be a easy problem...
the method read in stdin or file read in text has been proved be right. Things go wrong in binary read.
Here I have a class named Laptop and a file named laptop.txt, which is written by the code followed. I have reloaded the >> and <<
using namespace std;
class Laptop
{
private:
string brand;
string cpu;
string ram;
string disk;
int reserve;
public:
Laptop() {}
Laptop(string aBrand, string aCpu, string aRam, string aDisk, int aReserve)
{
this->brand = aBrand;
this->cpu = aCpu;
this->ram = aRam;
this->disk = aDisk;
this->reserve = aReserve;
}
friend ostream &operator<<(ostream &os, const Laptop &laptop)
{
os << laptop.brand << " " << laptop.cpu
<< " " << laptop.ram << " " << laptop.disk << " " << laptop.reserve;
return os;
}
friend istream &operator>>(istream &is, Laptop &laptop)
{
is >> laptop.brand >> laptop.cpu >> laptop.ram >> laptop.disk >> laptop.reserve;
return is;
}
};
int main()
{
fstream file("laptop.txt", ios::out | ios::binary);
vector<Laptop> laptops;
Laptop aLaptop;
for (int i = 0; i < 5; i++)
{
cin >> aLaptop;
laptops.push_back(aLaptop);
}
for (vector<Laptop>::iterator i = laptops.begin(); i != laptops.end(); i++)
{
file.write((char *)(&i), sizeof(*i));
}
return 0;
}
But things doesn't go right in binary read. Here comes to the exception from class Laptop when I try to push aLaptop to the vector. I really don't know why. It's horrible.
int main()
{
fstream file("laptop.txt", ios::in);
vector<Laptop> laptops;
Laptop aLaptop;
while (file.peek() != EOF)
{
file.read((char *)(&aLaptop), sizeof(aLaptop));
laptops.push_back(aLaptop);
}
return 0;
}
enter image description here
You have a class consisting of four strings and an int, and you cast a pointer to it to a character pointer and try to read it in binary mode from a text file.
A string consists of a length and a pointer. The pointer is pointing to a variable-sized block of memory containing characters. sizeof returns the size of the length and the pointer, but not the block of characters. So when you read the file, you get the length and the pointer, but not the characters that compose the string. The pointer is thus pointing to garbage.
The correct way to do this is either:
If you know that the string will never contain a null character, read characters, appending them to the string, until you get a null character or the end of file.
Read the length of the string, then read that many characters. If you hit the end of file in the middle of this, throw.
You will also need a function to write the string in the same way.
Reading an integer from a binary file works, as long as the integer was written binarily. For portability, it's better to read and write integers in a consistent endianness.

I'm getting Read access violation while accessing objects from file C++.

In the below class error is in the init function where i load the class object I stored in the file to the vector Items.
class Item
{
std::string item_code;
std::string item_name;
std::string unit_name;
unsigned int price_per_unit;
double discount_rate;
static std::vector<Item> Items;
friend std::ostream& operator<< (std::ostream&, Item&);
public:
static void PrintAll();
static void Init();
~Item();
};
Default constructor is the one which reads data from user and writes into file. Below is the code of default constructor.
Item::Item(int a)
{
std::cout << "Item name : ";
std::getline(std::cin, item_name);
std::cout << "Unit (Kg/g/Qty) : ";
std::getline(std::cin, unit_name);
std::cout << "Price per unit : ";
std::cin >> price_per_unit;
std::cout << "Discount Rate : ";
std::cin >> discount_rate;
std::cin.ignore();
std::cout << "Product code (has to be unique) : ";
std::getline(std::cin, item_code);
std::ofstream outfile;
outfile.open("Files\\Items.txt", std::ios::out | std::ios::app);
outfile.write((char*)&(*this), sizeof(Item));
outfile.close();
}
Below is the Init() function for which read access violation is thrown at.
void Item::Init()
{
std::ifstream infile("Files\\Items.txt", std::ios::in);
if (!infile.is_open())
{
std::cout << "Cannot Open File \n";
infile.close();
return;
}
else
{
Item temp;
while (!infile.eof())
{
infile.read((char*)&temp, sizeof(temp));
Item::Items.push_back(temp);
}
}
infile.close();
}
Even though i am checking for eof, read access violation is thrown. Please give me some advice on this issue.
infile.read((char*)&temp, sizeof(temp));
This fills the temp object with junk from the file. It's supposed to contain valid std::string objects and whatever is in the file, it can't possibly be a valid std::string object. If you don't see why, consider that creating a valid std::string object requires allocating memory to hold the string data -- that's what the std::string constructor does. Reading data from a file can't possibly do this.
A file is a stream of bytes. To write data to a file, you need to define some way to represent that data as a stream of bytes. You need to encode its length if it is variable length. To read it back in, you need to handle the variable length case as well. You need to convert the file data to an appropriate internal representation, such as std::string. This is called "serialization".
std::string size is variable, you can try the following definition
char item_code[20];
char item_name[20];
char unit_name[20];

Weird behavior with ifstreams and rdbuf()

I've noticed that using .rdbuf() on an ifstream seems to change it somehow. The following code should show the problem.
#include <fstream>
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
ifstream ifs("Sample.csv");
cout << "Reading buffer: " << endl;
cout << ifs.rdbuf(); // Outputs buffer as expected
cout << "Reading buffer again: " << endl;
cout << ifs.rdbuf(); // Returns nothing
return 0;
}
The reason this is bothering me is that I'm currently trying to copy the contents of one text file into another using ofstream ofs; ofs << ifs.rdbuf(). This works fine but makes reading from ifs using getline(ifs, str) fail, effectively "breaking" the stream.
This isn't particularly "weird"; it's the same stream behaviour you see every day. rdbuf isn't like std::stringstream::str() and it isn't magic — it's a pointer to the buffer, that your cout is then reading from just as you would read from the original stream yourself:
std::stringstream ss("1");
int x;
if (ss >> x)
cout << x;
if (ss >> x) // doesn't work a second time; "1" is already extracted
cout << x;
As your stream is a file stream, you can seek it back to the beginning to start from scratch (which will inherently do the same to its underlying buffer).
ifs.rdbuf() returns a pointer to the ifs's corresponding stream buffer object. Sending it to std::cout via << overload pulls information from the stream until the end of the buffer is reached (eof). Calling .rdbuf() again returns "nothing" because there's nothing to read at the end of the buffer. The buffer seek position be explicitly reset to zero by calling ifs.seekg (0);.

fstream using formatted data

i am new to this site , and this my first question !
i have a question about fstream function .
fstream f("new.dat",ios::out|ios::in);
fstream is for both input and output , so when we use it like this , and there is a new.dat file before it will output and input both . but it is strange , when i do that , it will output data correctly , but it is unable to input .
i found out if you close it , and reopen it , it will input . why it is like that??
int main()
{
fstream writeFile("newFile.dat", ios::out|ios::in);
char i[3];
char u[3]="HI";
if (!writeFile)
{
cerr << "error" << endl;
}
writeFile << u <<endl;
writeFile >> i;
cout << i << endl;
}
this is my full code , and result is an empty line.
The fstream object has a position in its output file, and since you opened it just for output and input without any position or writing modifiers, that position is at the end of the file. When you output i to the file, writeFile writes i to the file, and then moves its position past i so when you ask it to write more, you don't overwrite i.
You can reset the position to the start of the file with a call to writeFile.seekg(0), which places that internal position at the 0 position in the file (at the start).
If you're curious about stream manipulation, I'd suggest a look at cppreference.com and specifically its documentation on c++'s input and output libraries here.
Couple things going on here:
You can't open a file for reading if it doesn't exist, this includes a file you want to read and write. No file, no open.
Once you manage to open a file, the stream keeps track of where it is in the file. As you read or write, obviously the location moves.
There is only one location marker in the stream, so you can read to where you want to write, then write. Unfortunately this means any further reading will pick up after the write. If that's not what you want, get and store the current location (with tellg) before writing, and seek (with seekg) to the stored location after writing.
This has some problems such as what if the block of data you wish to insert is longer or shorter than the block of data you want to overwrite? The simple solution to this problem is read into buffer, edit buffer, write buffer back to file.
When you open a file and start writing into it, you overwrite whatever was in the file. If you want to add to a file, open with ios::app. This sets the stream's location to the end of the file. I am unaware of any sort of insert that pushes existing data along as you write in new data.
Some simple file handling example code
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
fstream f1("filename", ios::out);
if (f1.is_open())
{
if (f1 << "Hi")
{
cout << "wrote"<<endl;
}
f1.close();
}
fstream f2("filename", ios::out|ios::app);
if (f2.is_open())
{
if (f2 << " there!")
{
cout << "appended"<<endl;
}
f2.close();
}
fstream f3("filename", ios::in);
if (f3.is_open())
{
cout << f3.rdbuf()<< endl;
f3.close();
}
fstream f4("filename", ios::in|ios::out);
if (f4.is_open())
{
f4.seekg(3);
if (f4 << "Fred!")
{
cout << "overwrote"<<endl;
}
f4.close();
}
fstream f5("filename", ios::in);
if (f5.is_open())
{
cout << f5.rdbuf()<< endl;
f5.close();
}
// note the extra ! on the end left over from Hi there! I do not know how
// to get rid of this. I have always just done stuff like this to get around it.
fstream f6("filename", ios::in);
stringstream s1;
string token;
f6 >> token;
s1 << token << " Tim!";
f6.close();
fstream f7("filename", ios::out);
f7 << s1.rdbuf();
f7.close();
// and then moved temp over filename.
fstream f8("filename", ios::in);
cout << f8.rdbuf()<< endl;
f8.close();
}

C++ Fstream Only Prints One Word

This is a very strange issue. I'm trying to print a large text file, it's a Wikipedia entry. It happens to be the page on Velocity. So, when I tell it to print the file, it prints "In", when it should print "In physics, velocity is etc, etc etc".
Here's the code I'm using to print out:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream wiki;
wiki.open("./wiki/velocity.txt");
char* wikiRead;
wiki >> wikiRead;
cout << wikiRead << endl;
wiki.close();
}
Please help.
wiki >> wikiRead;
The default delimiter for stream is space, so when the stream encounters a space, it simply stops reading, that is why it reads only one word.
If you want the stream to read all words, the you've to use a loop as:
char* wikiRead = new char[1024]; //must allocate some memory!
while(wiki >> wikiRead)
{
cout << wikiRead << endl;
}
wiki.close();
delete []wikiRead; //must deallocate the memory
This will print all the words in the file, each on a new line. Note if any of the word in the file is more than 1024 character long, then this program would invoke undefined behavior, and the program might crash. In that case, you've to allocate a bigger chunk of memory.
But why use char* in the first place? In C++, you've better choice: Use std::string.
#include<string>
std::string word;
while(wiki >> word)
{
cout << word << endl;
}
wiki.close();
Its better now.
If you want to read line-by-line, instead of word-by-word, then use std::getline as:
std::string line;
while(std::getline(wiki, line))
{
cout << line << endl;
}
wiki.close();
This will read a complete line, even if the line contains spaces between the words, and will print each line a newline.
You ask the stream to read the (binary) value of a pointer (probably 4 bytes, depending on your machine architecture), then you ask it to print the text pointed to by those 4 bytes!
I wonder why you ignored the compiler warning (most of the modern compiler warns you about using uninitialized variables). How about this?
ifstream wiki;
wiki.open("./wiki/velocity.txt");
char wikiRead[255];
wiki >> wikiRead;
cout << wikiRead << endl;
wiki.close();
Alternatively I'd suggest you to use string object with getline to get a single line of text.
string str;
getline(wiki, str);
The >> operator applied to a char * reads only one word. Moreover, you're reading into an uninitialized pointer, which is not valid. Usually std::string, not char *, is used for string processing in C++.
If you only want to print the file's contents, you can hook the file's buffer directly to std::cout:
int main() {
std::ifstream wiki("./wiki/velocity.txt");
std::cout << wiki.rdbuf() << '\n';
}
If you want to put the contents into an automatically-allocated string, use std::getline with the delimiter disabled.
int main() {
std::ifstream wiki("./wiki/velocity.txt");
std::string wiki_contents;
getline( wiki, wiki_contents, '\0' /* do not stop at newline */ );
std::cout << wiki_contents << '\n'; // do something with the string
}
Since you want to read a large file, reading it block by block is a better way.
ifstream wiki;
wiki.open("./wiki/velocity.txt");
const int buf_size = 1024;
char* wikiRead = 0;
int cnt = 1;
do
{
wikiRead = realloc( wikiRead, bufsize*cnt );
wiki.Read( wikiRead + (bufSize*(cnt-1)), buf_size ); //appends to reallocated memory
cnt++;
}while( !wiki.eof())
wikiRead[(bufSize*(cnt-2)) + wiki.gcount() + 1] = '\0'; // null termination.
wiki.Close();
cout << wikiRead;
delete[] wikiRead;
The operator>> is designed to only read one word at a time. If you want to read lines, use getline.
#include <iostream>
#include <fstream>
#include<string>
using namespace std;
int main()
{
ifstream wiki;
wiki.open("./wiki/velocity.txt");
string wikiRead;
while (getline(wiki, wikiRead))
{
cout << wikiRead << endl;
}
wiki.close();
}