File I/O Binary Dynamic Array Crashed
up vote
1
down vote
favorite
#include iostream
#include cmath
#include fstream
#include cstdlib
#include string
using namespace std;
class Device {//Input and store Device Description and Serial Numbers
protected:
string serial_number;
string device_description;
public:
Device() {
serial_number = ("6DCMQ32");
device_description = ("TheDell");
}
};
class Test {//Input and store Test Description, recent day, and month;
Calculate the next day
protected:
string Test_Description;
static int recent_month, recent_day, recent_year, new_month;
static int nmonth, next_month, next_day, next_year, max_day;
public:
Test() {
Test_Description = ("Virtual");
}
static void getMonth(ostream & out) {//Calculates the next/new month
next_month = recent_month + nmonth;
new_month = next_month % 12;
if (next_month >= 12) {
cout << "The next Date: " << new_month << " / ";
}
else {
out << "The next Date: " << next_month << " / ";
}
}
static void getDay(ostream & out) { //Calculates day of next month
if (new_month == 4 || new_month == 6 || new_month == 9 || new_month == 11) {
max_day = 30;
}
else if (new_month == 2) {
max_day = 29;
}
else {
max_day = 31;
}
if (recent_day > max_day) {
out << max_day << " / ";
}
else {
out << recent_day << " / ";
}
}
static void getYear(ostream & out) {// Calculate the year of next month
next_year = recent_year + next_month;
if (next_year >= 12) {
out << recent_year + (next_month / 12) << endl;
}
else {
out << next_year << endl;
}
}
static void getDate(ostream & out) {// Collects the output of each element of next date
getMonth(out), getDay(out), getYear(out);
}
};
int Test::recent_month;
int Test::recent_day;
int Test::recent_year;
int Test::new_month;
int Test::nmonth;
int Test::next_month;
int Test::next_day;
int Test::next_year;
int Test::max_day;
class Lab : public Device, public Test {
protected:
static int n;
public:
friend istream & operator>>(istream & in, Lab & lab) {// Inputs
cout << "Enter Device Desciption and Serial Number: ";
getline(cin, lab.device_description);
getline(cin, lab.serial_number);
cout << "Enter Test Desciption: ";
getline(cin, lab.Test_Description);
cout << "Enter the Number of months: ";
in >> nmonth;
cout << "Enter the Most Recent Date(mm/dd/yyyy): ";
in >> recent_month >> recent_day >> recent_year;
return in;
}
friend ostream & operator<<(ostream & out, Lab & lab) {//Outputs everything in Device Class
out << lab.device_description << endl;
out << lab.serial_number << endl;
out << lab.Test_Description << endl;
getDate(out);
return out;
}
static void getN() {
cout << "Enter the number of devices: ";
cin >> n;
}
static void getWrite() {
Lab *obj = new Lab[n];
if (obj == 0) {
cout << "Memory Error";
exit(1);
}
for (int i = 0; i<n; i++) {
cin >> obj[i];
cout << endl;
}
ofstream myfile("Device.dat", ios::binary);
myfile.write((char*) obj, n * sizeof(Lab));
delete obj;
}
static void getRead() {
ifstream file2("Device.dat", ios::binary);
Lab *obj2 = new Lab[n];
if (obj2 == 0) {
cout << "Memory Error";
exit(1);
}
file2.read((char*) obj2, n * sizeof(Lab));
for (int i = 0; i < n; i++) {
cout << obj2[i];
cout << endl;
}
delete obj2;
}
};
int Lab::n;
void main() {
Lab L;
L.getN();
L.getWrite();
L.getRead();
getchar();
getchar();
system("pause");
}
The program keeps on crashing after outputting the values
Purpose: is to enter the number of months for the next test date of device with input of serial number,
Device Description, Test Description, recent date, and the number of months of two tests. At the end the
program must be searched by having the user to input the serial number and the next date, if these two are
valid everything in the device is listed out.
I am using Microsoft Visual Studios 2017
c++ file oop file-writing file-read
|
show 3 more comments
up vote
1
down vote
favorite
#include iostream
#include cmath
#include fstream
#include cstdlib
#include string
using namespace std;
class Device {//Input and store Device Description and Serial Numbers
protected:
string serial_number;
string device_description;
public:
Device() {
serial_number = ("6DCMQ32");
device_description = ("TheDell");
}
};
class Test {//Input and store Test Description, recent day, and month;
Calculate the next day
protected:
string Test_Description;
static int recent_month, recent_day, recent_year, new_month;
static int nmonth, next_month, next_day, next_year, max_day;
public:
Test() {
Test_Description = ("Virtual");
}
static void getMonth(ostream & out) {//Calculates the next/new month
next_month = recent_month + nmonth;
new_month = next_month % 12;
if (next_month >= 12) {
cout << "The next Date: " << new_month << " / ";
}
else {
out << "The next Date: " << next_month << " / ";
}
}
static void getDay(ostream & out) { //Calculates day of next month
if (new_month == 4 || new_month == 6 || new_month == 9 || new_month == 11) {
max_day = 30;
}
else if (new_month == 2) {
max_day = 29;
}
else {
max_day = 31;
}
if (recent_day > max_day) {
out << max_day << " / ";
}
else {
out << recent_day << " / ";
}
}
static void getYear(ostream & out) {// Calculate the year of next month
next_year = recent_year + next_month;
if (next_year >= 12) {
out << recent_year + (next_month / 12) << endl;
}
else {
out << next_year << endl;
}
}
static void getDate(ostream & out) {// Collects the output of each element of next date
getMonth(out), getDay(out), getYear(out);
}
};
int Test::recent_month;
int Test::recent_day;
int Test::recent_year;
int Test::new_month;
int Test::nmonth;
int Test::next_month;
int Test::next_day;
int Test::next_year;
int Test::max_day;
class Lab : public Device, public Test {
protected:
static int n;
public:
friend istream & operator>>(istream & in, Lab & lab) {// Inputs
cout << "Enter Device Desciption and Serial Number: ";
getline(cin, lab.device_description);
getline(cin, lab.serial_number);
cout << "Enter Test Desciption: ";
getline(cin, lab.Test_Description);
cout << "Enter the Number of months: ";
in >> nmonth;
cout << "Enter the Most Recent Date(mm/dd/yyyy): ";
in >> recent_month >> recent_day >> recent_year;
return in;
}
friend ostream & operator<<(ostream & out, Lab & lab) {//Outputs everything in Device Class
out << lab.device_description << endl;
out << lab.serial_number << endl;
out << lab.Test_Description << endl;
getDate(out);
return out;
}
static void getN() {
cout << "Enter the number of devices: ";
cin >> n;
}
static void getWrite() {
Lab *obj = new Lab[n];
if (obj == 0) {
cout << "Memory Error";
exit(1);
}
for (int i = 0; i<n; i++) {
cin >> obj[i];
cout << endl;
}
ofstream myfile("Device.dat", ios::binary);
myfile.write((char*) obj, n * sizeof(Lab));
delete obj;
}
static void getRead() {
ifstream file2("Device.dat", ios::binary);
Lab *obj2 = new Lab[n];
if (obj2 == 0) {
cout << "Memory Error";
exit(1);
}
file2.read((char*) obj2, n * sizeof(Lab));
for (int i = 0; i < n; i++) {
cout << obj2[i];
cout << endl;
}
delete obj2;
}
};
int Lab::n;
void main() {
Lab L;
L.getN();
L.getWrite();
L.getRead();
getchar();
getchar();
system("pause");
}
The program keeps on crashing after outputting the values
Purpose: is to enter the number of months for the next test date of device with input of serial number,
Device Description, Test Description, recent date, and the number of months of two tests. At the end the
program must be searched by having the user to input the serial number and the next date, if these two are
valid everything in the device is listed out.
I am using Microsoft Visual Studios 2017
c++ file oop file-writing file-read
1
std::string
is far too complicated a data structure to simplywrite
to a file unfortunately. At it's simplest, astring
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness.
– user4581301
Nov 20 at 1:11
Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code.
– user4581301
Nov 20 at 1:12
1
Use youroperator <<
overloads to serialize the structure to the file rather than trying to binarywrite
. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.
– user4581301
Nov 20 at 1:15
I don't know what to do. Can you please help me?
– Goodzone Lo
Nov 20 at 1:15
1
@GoodzoneLomyfile.write((char*) obj, n * sizeof(Lab))
-- This would never work. Thesizeof(Lab)
remains the same value, regardless of how many characters thestd::string
members had in them. That alone makes this attempt futile. You're supposed to write the data that the object represents to a file so that when reading the data, you recreate the object. So you have to take that object, see what the pieces of data that makes up the object represents, and write that to a file (i.e. the characters in the strings, not thestd::string
itself).
– PaulMcKenzie
Nov 20 at 1:54
|
show 3 more comments
up vote
1
down vote
favorite
up vote
1
down vote
favorite
#include iostream
#include cmath
#include fstream
#include cstdlib
#include string
using namespace std;
class Device {//Input and store Device Description and Serial Numbers
protected:
string serial_number;
string device_description;
public:
Device() {
serial_number = ("6DCMQ32");
device_description = ("TheDell");
}
};
class Test {//Input and store Test Description, recent day, and month;
Calculate the next day
protected:
string Test_Description;
static int recent_month, recent_day, recent_year, new_month;
static int nmonth, next_month, next_day, next_year, max_day;
public:
Test() {
Test_Description = ("Virtual");
}
static void getMonth(ostream & out) {//Calculates the next/new month
next_month = recent_month + nmonth;
new_month = next_month % 12;
if (next_month >= 12) {
cout << "The next Date: " << new_month << " / ";
}
else {
out << "The next Date: " << next_month << " / ";
}
}
static void getDay(ostream & out) { //Calculates day of next month
if (new_month == 4 || new_month == 6 || new_month == 9 || new_month == 11) {
max_day = 30;
}
else if (new_month == 2) {
max_day = 29;
}
else {
max_day = 31;
}
if (recent_day > max_day) {
out << max_day << " / ";
}
else {
out << recent_day << " / ";
}
}
static void getYear(ostream & out) {// Calculate the year of next month
next_year = recent_year + next_month;
if (next_year >= 12) {
out << recent_year + (next_month / 12) << endl;
}
else {
out << next_year << endl;
}
}
static void getDate(ostream & out) {// Collects the output of each element of next date
getMonth(out), getDay(out), getYear(out);
}
};
int Test::recent_month;
int Test::recent_day;
int Test::recent_year;
int Test::new_month;
int Test::nmonth;
int Test::next_month;
int Test::next_day;
int Test::next_year;
int Test::max_day;
class Lab : public Device, public Test {
protected:
static int n;
public:
friend istream & operator>>(istream & in, Lab & lab) {// Inputs
cout << "Enter Device Desciption and Serial Number: ";
getline(cin, lab.device_description);
getline(cin, lab.serial_number);
cout << "Enter Test Desciption: ";
getline(cin, lab.Test_Description);
cout << "Enter the Number of months: ";
in >> nmonth;
cout << "Enter the Most Recent Date(mm/dd/yyyy): ";
in >> recent_month >> recent_day >> recent_year;
return in;
}
friend ostream & operator<<(ostream & out, Lab & lab) {//Outputs everything in Device Class
out << lab.device_description << endl;
out << lab.serial_number << endl;
out << lab.Test_Description << endl;
getDate(out);
return out;
}
static void getN() {
cout << "Enter the number of devices: ";
cin >> n;
}
static void getWrite() {
Lab *obj = new Lab[n];
if (obj == 0) {
cout << "Memory Error";
exit(1);
}
for (int i = 0; i<n; i++) {
cin >> obj[i];
cout << endl;
}
ofstream myfile("Device.dat", ios::binary);
myfile.write((char*) obj, n * sizeof(Lab));
delete obj;
}
static void getRead() {
ifstream file2("Device.dat", ios::binary);
Lab *obj2 = new Lab[n];
if (obj2 == 0) {
cout << "Memory Error";
exit(1);
}
file2.read((char*) obj2, n * sizeof(Lab));
for (int i = 0; i < n; i++) {
cout << obj2[i];
cout << endl;
}
delete obj2;
}
};
int Lab::n;
void main() {
Lab L;
L.getN();
L.getWrite();
L.getRead();
getchar();
getchar();
system("pause");
}
The program keeps on crashing after outputting the values
Purpose: is to enter the number of months for the next test date of device with input of serial number,
Device Description, Test Description, recent date, and the number of months of two tests. At the end the
program must be searched by having the user to input the serial number and the next date, if these two are
valid everything in the device is listed out.
I am using Microsoft Visual Studios 2017
c++ file oop file-writing file-read
#include iostream
#include cmath
#include fstream
#include cstdlib
#include string
using namespace std;
class Device {//Input and store Device Description and Serial Numbers
protected:
string serial_number;
string device_description;
public:
Device() {
serial_number = ("6DCMQ32");
device_description = ("TheDell");
}
};
class Test {//Input and store Test Description, recent day, and month;
Calculate the next day
protected:
string Test_Description;
static int recent_month, recent_day, recent_year, new_month;
static int nmonth, next_month, next_day, next_year, max_day;
public:
Test() {
Test_Description = ("Virtual");
}
static void getMonth(ostream & out) {//Calculates the next/new month
next_month = recent_month + nmonth;
new_month = next_month % 12;
if (next_month >= 12) {
cout << "The next Date: " << new_month << " / ";
}
else {
out << "The next Date: " << next_month << " / ";
}
}
static void getDay(ostream & out) { //Calculates day of next month
if (new_month == 4 || new_month == 6 || new_month == 9 || new_month == 11) {
max_day = 30;
}
else if (new_month == 2) {
max_day = 29;
}
else {
max_day = 31;
}
if (recent_day > max_day) {
out << max_day << " / ";
}
else {
out << recent_day << " / ";
}
}
static void getYear(ostream & out) {// Calculate the year of next month
next_year = recent_year + next_month;
if (next_year >= 12) {
out << recent_year + (next_month / 12) << endl;
}
else {
out << next_year << endl;
}
}
static void getDate(ostream & out) {// Collects the output of each element of next date
getMonth(out), getDay(out), getYear(out);
}
};
int Test::recent_month;
int Test::recent_day;
int Test::recent_year;
int Test::new_month;
int Test::nmonth;
int Test::next_month;
int Test::next_day;
int Test::next_year;
int Test::max_day;
class Lab : public Device, public Test {
protected:
static int n;
public:
friend istream & operator>>(istream & in, Lab & lab) {// Inputs
cout << "Enter Device Desciption and Serial Number: ";
getline(cin, lab.device_description);
getline(cin, lab.serial_number);
cout << "Enter Test Desciption: ";
getline(cin, lab.Test_Description);
cout << "Enter the Number of months: ";
in >> nmonth;
cout << "Enter the Most Recent Date(mm/dd/yyyy): ";
in >> recent_month >> recent_day >> recent_year;
return in;
}
friend ostream & operator<<(ostream & out, Lab & lab) {//Outputs everything in Device Class
out << lab.device_description << endl;
out << lab.serial_number << endl;
out << lab.Test_Description << endl;
getDate(out);
return out;
}
static void getN() {
cout << "Enter the number of devices: ";
cin >> n;
}
static void getWrite() {
Lab *obj = new Lab[n];
if (obj == 0) {
cout << "Memory Error";
exit(1);
}
for (int i = 0; i<n; i++) {
cin >> obj[i];
cout << endl;
}
ofstream myfile("Device.dat", ios::binary);
myfile.write((char*) obj, n * sizeof(Lab));
delete obj;
}
static void getRead() {
ifstream file2("Device.dat", ios::binary);
Lab *obj2 = new Lab[n];
if (obj2 == 0) {
cout << "Memory Error";
exit(1);
}
file2.read((char*) obj2, n * sizeof(Lab));
for (int i = 0; i < n; i++) {
cout << obj2[i];
cout << endl;
}
delete obj2;
}
};
int Lab::n;
void main() {
Lab L;
L.getN();
L.getWrite();
L.getRead();
getchar();
getchar();
system("pause");
}
The program keeps on crashing after outputting the values
Purpose: is to enter the number of months for the next test date of device with input of serial number,
Device Description, Test Description, recent date, and the number of months of two tests. At the end the
program must be searched by having the user to input the serial number and the next date, if these two are
valid everything in the device is listed out.
I am using Microsoft Visual Studios 2017
c++ file oop file-writing file-read
c++ file oop file-writing file-read
asked Nov 20 at 1:03
Goodzone Lo
103
103
1
std::string
is far too complicated a data structure to simplywrite
to a file unfortunately. At it's simplest, astring
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness.
– user4581301
Nov 20 at 1:11
Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code.
– user4581301
Nov 20 at 1:12
1
Use youroperator <<
overloads to serialize the structure to the file rather than trying to binarywrite
. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.
– user4581301
Nov 20 at 1:15
I don't know what to do. Can you please help me?
– Goodzone Lo
Nov 20 at 1:15
1
@GoodzoneLomyfile.write((char*) obj, n * sizeof(Lab))
-- This would never work. Thesizeof(Lab)
remains the same value, regardless of how many characters thestd::string
members had in them. That alone makes this attempt futile. You're supposed to write the data that the object represents to a file so that when reading the data, you recreate the object. So you have to take that object, see what the pieces of data that makes up the object represents, and write that to a file (i.e. the characters in the strings, not thestd::string
itself).
– PaulMcKenzie
Nov 20 at 1:54
|
show 3 more comments
1
std::string
is far too complicated a data structure to simplywrite
to a file unfortunately. At it's simplest, astring
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness.
– user4581301
Nov 20 at 1:11
Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code.
– user4581301
Nov 20 at 1:12
1
Use youroperator <<
overloads to serialize the structure to the file rather than trying to binarywrite
. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.
– user4581301
Nov 20 at 1:15
I don't know what to do. Can you please help me?
– Goodzone Lo
Nov 20 at 1:15
1
@GoodzoneLomyfile.write((char*) obj, n * sizeof(Lab))
-- This would never work. Thesizeof(Lab)
remains the same value, regardless of how many characters thestd::string
members had in them. That alone makes this attempt futile. You're supposed to write the data that the object represents to a file so that when reading the data, you recreate the object. So you have to take that object, see what the pieces of data that makes up the object represents, and write that to a file (i.e. the characters in the strings, not thestd::string
itself).
– PaulMcKenzie
Nov 20 at 1:54
1
1
std::string
is far too complicated a data structure to simply write
to a file unfortunately. At it's simplest, a string
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness.– user4581301
Nov 20 at 1:11
std::string
is far too complicated a data structure to simply write
to a file unfortunately. At it's simplest, a string
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness.– user4581301
Nov 20 at 1:11
Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code.
– user4581301
Nov 20 at 1:12
Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code.
– user4581301
Nov 20 at 1:12
1
1
Use your
operator <<
overloads to serialize the structure to the file rather than trying to binary write
. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.– user4581301
Nov 20 at 1:15
Use your
operator <<
overloads to serialize the structure to the file rather than trying to binary write
. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.– user4581301
Nov 20 at 1:15
I don't know what to do. Can you please help me?
– Goodzone Lo
Nov 20 at 1:15
I don't know what to do. Can you please help me?
– Goodzone Lo
Nov 20 at 1:15
1
1
@GoodzoneLo
myfile.write((char*) obj, n * sizeof(Lab))
-- This would never work. The sizeof(Lab)
remains the same value, regardless of how many characters the std::string
members had in them. That alone makes this attempt futile. You're supposed to write the data that the object represents to a file so that when reading the data, you recreate the object. So you have to take that object, see what the pieces of data that makes up the object represents, and write that to a file (i.e. the characters in the strings, not the std::string
itself).– PaulMcKenzie
Nov 20 at 1:54
@GoodzoneLo
myfile.write((char*) obj, n * sizeof(Lab))
-- This would never work. The sizeof(Lab)
remains the same value, regardless of how many characters the std::string
members had in them. That alone makes this attempt futile. You're supposed to write the data that the object represents to a file so that when reading the data, you recreate the object. So you have to take that object, see what the pieces of data that makes up the object represents, and write that to a file (i.e. the characters in the strings, not the std::string
itself).– PaulMcKenzie
Nov 20 at 1:54
|
show 3 more comments
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
std::string
is far too complicated a data structure to simply write to a file unfortunately. At it's simplest, a string
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string
back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness. Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code. Either way accessing memory that has not been assigned to the pointer invokes Undefined Behaviour, and with UB anything can happen. Don't count on crashes or consistency.
Generally you would use your operator <<
overloads to serialize the structure to the file rather than trying to binary write. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.
The protocol is going to be a set of functions that convert simpler data types to and from their file equivalents.
A typical method for writing a string
is to first write the length of the string
and then write the contents of the string
. Something like
uint32 len = str.length(); //fixed width length
len = htonl(len); // fixed endian
myfile.write((char*) &len, sizeof(len)); //write length
myfile.write(str.data(), str.length()); //write string
And reading
uint32 len; //fixed width length
myfile.read((char*) &len, sizeof(len)); //read length
len = ntohl(len); // unfix endian
std::string str(len, ' '); //string and allocate size
myfile.write(str.data(), len); //read string C++17 or
//myfile.write(&str[0], len); //read string before C++17
bundle these up inside functions and you've started on your protocol. Add to them functions for other data types you need to store.
These functions are then called by functions that convert larger datatypes and on up until you reach the most complex of the structures you need to write. For an array, use a loop. If you have a length of variable size, prefix the length just like with a string
.
Side note: When reading or writing numbers care must be taken to ensure the number is a known, fixed size. int
, for example, can be any size 16 bits or greater so long at it's not larger than
long. You don't necessarily know that the file reader will be using the same sized
int`, so you should prefer a Fixed Width Integer large enough to store the values required. Different computers also may store their binary information in different orders. This is called Byte Order or Endian. Make sure everyone is using the same endian.
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
std::string
is far too complicated a data structure to simply write to a file unfortunately. At it's simplest, a string
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string
back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness. Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code. Either way accessing memory that has not been assigned to the pointer invokes Undefined Behaviour, and with UB anything can happen. Don't count on crashes or consistency.
Generally you would use your operator <<
overloads to serialize the structure to the file rather than trying to binary write. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.
The protocol is going to be a set of functions that convert simpler data types to and from their file equivalents.
A typical method for writing a string
is to first write the length of the string
and then write the contents of the string
. Something like
uint32 len = str.length(); //fixed width length
len = htonl(len); // fixed endian
myfile.write((char*) &len, sizeof(len)); //write length
myfile.write(str.data(), str.length()); //write string
And reading
uint32 len; //fixed width length
myfile.read((char*) &len, sizeof(len)); //read length
len = ntohl(len); // unfix endian
std::string str(len, ' '); //string and allocate size
myfile.write(str.data(), len); //read string C++17 or
//myfile.write(&str[0], len); //read string before C++17
bundle these up inside functions and you've started on your protocol. Add to them functions for other data types you need to store.
These functions are then called by functions that convert larger datatypes and on up until you reach the most complex of the structures you need to write. For an array, use a loop. If you have a length of variable size, prefix the length just like with a string
.
Side note: When reading or writing numbers care must be taken to ensure the number is a known, fixed size. int
, for example, can be any size 16 bits or greater so long at it's not larger than
long. You don't necessarily know that the file reader will be using the same sized
int`, so you should prefer a Fixed Width Integer large enough to store the values required. Different computers also may store their binary information in different orders. This is called Byte Order or Endian. Make sure everyone is using the same endian.
add a comment |
up vote
1
down vote
accepted
std::string
is far too complicated a data structure to simply write to a file unfortunately. At it's simplest, a string
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string
back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness. Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code. Either way accessing memory that has not been assigned to the pointer invokes Undefined Behaviour, and with UB anything can happen. Don't count on crashes or consistency.
Generally you would use your operator <<
overloads to serialize the structure to the file rather than trying to binary write. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.
The protocol is going to be a set of functions that convert simpler data types to and from their file equivalents.
A typical method for writing a string
is to first write the length of the string
and then write the contents of the string
. Something like
uint32 len = str.length(); //fixed width length
len = htonl(len); // fixed endian
myfile.write((char*) &len, sizeof(len)); //write length
myfile.write(str.data(), str.length()); //write string
And reading
uint32 len; //fixed width length
myfile.read((char*) &len, sizeof(len)); //read length
len = ntohl(len); // unfix endian
std::string str(len, ' '); //string and allocate size
myfile.write(str.data(), len); //read string C++17 or
//myfile.write(&str[0], len); //read string before C++17
bundle these up inside functions and you've started on your protocol. Add to them functions for other data types you need to store.
These functions are then called by functions that convert larger datatypes and on up until you reach the most complex of the structures you need to write. For an array, use a loop. If you have a length of variable size, prefix the length just like with a string
.
Side note: When reading or writing numbers care must be taken to ensure the number is a known, fixed size. int
, for example, can be any size 16 bits or greater so long at it's not larger than
long. You don't necessarily know that the file reader will be using the same sized
int`, so you should prefer a Fixed Width Integer large enough to store the values required. Different computers also may store their binary information in different orders. This is called Byte Order or Endian. Make sure everyone is using the same endian.
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
std::string
is far too complicated a data structure to simply write to a file unfortunately. At it's simplest, a string
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string
back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness. Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code. Either way accessing memory that has not been assigned to the pointer invokes Undefined Behaviour, and with UB anything can happen. Don't count on crashes or consistency.
Generally you would use your operator <<
overloads to serialize the structure to the file rather than trying to binary write. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.
The protocol is going to be a set of functions that convert simpler data types to and from their file equivalents.
A typical method for writing a string
is to first write the length of the string
and then write the contents of the string
. Something like
uint32 len = str.length(); //fixed width length
len = htonl(len); // fixed endian
myfile.write((char*) &len, sizeof(len)); //write length
myfile.write(str.data(), str.length()); //write string
And reading
uint32 len; //fixed width length
myfile.read((char*) &len, sizeof(len)); //read length
len = ntohl(len); // unfix endian
std::string str(len, ' '); //string and allocate size
myfile.write(str.data(), len); //read string C++17 or
//myfile.write(&str[0], len); //read string before C++17
bundle these up inside functions and you've started on your protocol. Add to them functions for other data types you need to store.
These functions are then called by functions that convert larger datatypes and on up until you reach the most complex of the structures you need to write. For an array, use a loop. If you have a length of variable size, prefix the length just like with a string
.
Side note: When reading or writing numbers care must be taken to ensure the number is a known, fixed size. int
, for example, can be any size 16 bits or greater so long at it's not larger than
long. You don't necessarily know that the file reader will be using the same sized
int`, so you should prefer a Fixed Width Integer large enough to store the values required. Different computers also may store their binary information in different orders. This is called Byte Order or Endian. Make sure everyone is using the same endian.
std::string
is far too complicated a data structure to simply write to a file unfortunately. At it's simplest, a string
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string
back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness. Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code. Either way accessing memory that has not been assigned to the pointer invokes Undefined Behaviour, and with UB anything can happen. Don't count on crashes or consistency.
Generally you would use your operator <<
overloads to serialize the structure to the file rather than trying to binary write. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.
The protocol is going to be a set of functions that convert simpler data types to and from their file equivalents.
A typical method for writing a string
is to first write the length of the string
and then write the contents of the string
. Something like
uint32 len = str.length(); //fixed width length
len = htonl(len); // fixed endian
myfile.write((char*) &len, sizeof(len)); //write length
myfile.write(str.data(), str.length()); //write string
And reading
uint32 len; //fixed width length
myfile.read((char*) &len, sizeof(len)); //read length
len = ntohl(len); // unfix endian
std::string str(len, ' '); //string and allocate size
myfile.write(str.data(), len); //read string C++17 or
//myfile.write(&str[0], len); //read string before C++17
bundle these up inside functions and you've started on your protocol. Add to them functions for other data types you need to store.
These functions are then called by functions that convert larger datatypes and on up until you reach the most complex of the structures you need to write. For an array, use a loop. If you have a length of variable size, prefix the length just like with a string
.
Side note: When reading or writing numbers care must be taken to ensure the number is a known, fixed size. int
, for example, can be any size 16 bits or greater so long at it's not larger than
long. You don't necessarily know that the file reader will be using the same sized
int`, so you should prefer a Fixed Width Integer large enough to store the values required. Different computers also may store their binary information in different orders. This is called Byte Order or Endian. Make sure everyone is using the same endian.
answered Nov 20 at 2:58
user4581301
19.2k51831
19.2k51831
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53384784%2ffile-i-o-binary-dynamic-array-crashed%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
std::string
is far too complicated a data structure to simplywrite
to a file unfortunately. At it's simplest, astring
is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness.– user4581301
Nov 20 at 1:11
Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code.
– user4581301
Nov 20 at 1:12
1
Use your
operator <<
overloads to serialize the structure to the file rather than trying to binarywrite
. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.– user4581301
Nov 20 at 1:15
I don't know what to do. Can you please help me?
– Goodzone Lo
Nov 20 at 1:15
1
@GoodzoneLo
myfile.write((char*) obj, n * sizeof(Lab))
-- This would never work. Thesizeof(Lab)
remains the same value, regardless of how many characters thestd::string
members had in them. That alone makes this attempt futile. You're supposed to write the data that the object represents to a file so that when reading the data, you recreate the object. So you have to take that object, see what the pieces of data that makes up the object represents, and write that to a file (i.e. the characters in the strings, not thestd::string
itself).– PaulMcKenzie
Nov 20 at 1:54