I need some help - next piece of code writes a long double dynamic array into the file
int nx = 10, ny = 10;
long double **data = new long double *[nx];
long double **data_read = new long double *[nx];
for (int i = 0; i < nx; i++) {
data[i] = new long double [ny];
data_read[i] = new long double [ny];
}
data[4][4] = 10.0;
printf("%LF\n", data[4][4]);
FILE *file = fopen("data", "wb");
fwrite(data, nx * ny * sizeof(data), 1, file);
fclose(file);
file = fopen("data", "rb");
fread(data, nx * ny * sizeof(data_read), 1, file );
fclose(file);
printf("%LF\n", data_read[4][4]);
But data[4][4] != data_read[4][4]
, because after reading from file data_read[4][4]=0.0
.
Anybody knows what am I doing wrong?
Until the end of the text file is reached perform the following steps: Read a line from the input text file, into 3 variables using fscanf(). The structure variable is set to values for elements(to write the structure variable into the output file. Write that structure variable to the output binary file using fwrite().
To write a binary file in C++ use write method. It is used to write a given number of bytes on the given stream, starting at the position of the "put" pointer. The file is extended if the put pointer is currently at the end of the file.
Binary files can be used to store any data; for example, a JPEG image is a binary file designed to be read by a computer system. The data inside a binary file is stored as raw bytes, which is not human readable.
You need to write each row in your pointer array individually. A mass write will not work for pointer-to-pointer implementations of a fake 2D array (or nD).
For writing:
for (int i=0; i<nx; ++i)
fwrite(data[i], sizeof(data[i][0]), ny, file);
For reading:
for (int i=0; i<nx; ++i)
fread(data[i], sizeof(data[i][0]), ny, file);
Frankly, you're (un)fortunate the process didn't crash outright, as you were writing a bunch of memory addresses to your disk file (which a hex dump would have showed you), and were likely walking off the end of your pointer-array allocation during both operations.
That said, I'd start learning about the standard C++ IO library rather than using C-code in a C++ world (or fix the tag on this question).
Single Block Write/Read
You asked if it is possible to do this as a single block read/write. The answer is yes, but you must allocate the memory contiguously. If you still want a pointer-to-pointer array you can certainly use one. Though I recommend using std::vector<long double>
for the data buffer, the following will demonstrate what I refer to:
int main()
{
int nx = 10, ny = 10;
long double *buff1 = new long double[nx * ny];
long double *buff2 = new long double[nx * ny];
long double **data = new long double *[nx];
long double **data_read = new long double *[nx];
for (int i = 0; i < nx; i++)
{
data[i] = buff1 + (i*ny);
data_read[i] = buff2 + (i*ny);
}
data[4][4] = 10.0;
printf("%LF\n", data[4][4]);
FILE *file = fopen("data.bin", "wb");
fwrite(buff1, sizeof(*buff1), nx * ny, file);
fclose(file);
file = fopen("data.bin", "rb");
fread(buff2, sizeof(*buff2), nx * ny, file );
fclose(file);
printf("%LF\n", data_read[4][4]);
// delete pointer arrays
delete [] data;
delete [] data_read;
// delete buffers
delete [] buff1;
delete [] buff2;
}
Output
10.000000
10.000000
Using a std::vector<>
for an RAII Solution
All those allocations can get messy, and frankly prone to problems. Consider how this is different:
#include <iostream>
#include <fstream>
#include <vector>
int main()
{
int nx = 10, ny = 10;
// buffers for allocation
std::vector<long double> buff1(nx*ny);
std::vector<long double> buff2(nx*ny);
// holds pointers into original
std::vector<long double*> data(nx);
std::vector<long double*> data_read(nx);
for (int i = 0; i < nx; i++)
{
data[i] = buff1.data() + (i*ny);
data_read[i] = buff2.data() + (i*ny);
}
data[4][4] = 10.0;
std::cout << data[4][4] << std::endl;
std::ofstream ofp("data.bin", std::ios::out | std::ios::binary);
ofp.write(reinterpret_cast<const char*>(buff1.data()), buff1.size() * sizeof(buff1[0]));
ofp.close();
std::ifstream ifp("data.bin", std::ios::in | std::ios::binary);
ifp.read(reinterpret_cast<char*>(buff2.data()), buff2.size() * sizeof(buff2[0]));
ifp.close();
std::cout << data_read[4][4] << std::endl;
return 0;
}
Change your code to (see comments for details):
...
data[4][4] = 10.0;
printf("%Lf\n", data[4][4]); // use %Lf to print long double, not %LF
FILE *file = fopen("data", "wb");
for (int i=0; i<nx; ++i) // must write row-by-row as data are not continuous
fwrite(data[i], sizeof(long double), ny, file);
// cannot use sizeof(data) here as data is a pointer here, will always return 4
fclose(file);
file = fopen("data", "rb");
for (int i=0; i<nx; ++i) // read row-by-row
fread(data_read[i], sizeof(long double), ny, file);
// 1. read to data_read, not data
// 2. cannot use sizeof(data) here as data is a pointer here, will always return 4
fclose(file);
printf("%Lf\n", data_read[4][4]); // use %Lf to print long double, not %LF
...
Edit:
If you want to format the data in a continuous memory, use vector<long double>
or long double data[nx*ny]
instead. Then you can easily write or read by:
fwrite(data, nx * ny * sizeof(long double), 1, file);
...
fread(data_read, nx * ny * sizeof(long double), 1, file );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With