I'm having some seriously strange trouble writing multiple arrays of data to a file. Basically, I'm wanting to store all the array sizes at the top of the file, and then the array data following. This way I can just read the sizes and use that to construct arrays to hold the data on import, and I'll know exactly where each array begins and ends.
Here's the problem: I write the data, but it's different on import. Please take a look at my little test code. At the bottom there are comments about the values.
Thank you very much, fellow programmers! :)
#include <iostream>
#include <fstream>
int main()
{
int jcount = 100, // First item in file
kcount = 200,
in_jcount, // Third item in file. jcount is used to find where this ends.
in_kcount;
float *j = new float[jcount],
*k = new float[kcount],
*in_j,
*in_k;
for(int i = 0; i < jcount; ++i) // Write bologna data...
j[i] = (float)i;
for(int i = 0; i < kcount; ++i)
k[i] = (float)i;
std::ofstream outfile("test.dat");
outfile.write((char*)&jcount, sizeof(int)); // Good
outfile.tellp();
outfile.write((char*)&kcount, sizeof(int)); // Good
outfile.tellp();
outfile.write((char*)j, sizeof(float) * jcount); // I don't know if this works!
outfile.tellp();
outfile.write((char*)k, sizeof(float) * kcount); // I don't know if this works!
outfile.tellp();
outfile.close();
std::ifstream in("test.dat");
in.read((char*)&in_jcount, sizeof(int)); // == jcount == 100, good.
in.read((char*)&in_kcount, sizeof(int)); // == kcount == 200, good.
in_j = new float[in_jcount],
in_k = new float[in_kcount]; // Allocate arrays the exact size of what it should be
in.read((char*)in_j, sizeof(float) * in_jcount); // This is where it goes bad!
in.read((char*)in_k, sizeof(float) * in_kcount);
float jtest_min = j[0], // 0.0
jtest_max = j[jcount - 1], // this is 99.
ktest_min = k[0], // 0.0
ktest_max = k[kcount - 1], // this is 200. Why? It should be 199!
in_jtest_min = in_j[0], // 0.0
in_jtest_max = in_j[in_jcount - 1], // 99
in_ktest_min = in_k[0], // 0.0
in_ktest_max = in_k[in_kcount - 1]; // MIN_FLOAT, should be 199. What is going on here?
in.close();
delete k;
delete j;
delete in_j;
delete in_k;
}
There's nothing obviously wrong with this code (indeed, I don't see the errors you're encountering when I try running it), except for the fact that you are not checking for errors opening the input/output files.
For example, if you don't have permission to write to "test.dat", the open will silently fail, and you'll read back in whatever happened to be in the file before.
I've got the same bug, I fix it by using binary file:
ofstream outfile;
outfile.open ("test.dat", ios::out | ios::binary);
and
ifstream in;
in.open ("test.dat", ios::in | ios::binary);
Related
I have a script that dumps class info into a binary file, then another script that retrieves it.
Since binary files only accept chars, I wrote three functions for reading and writing Short Ints, Ints, and Floats. I've been experimenting with them so they're not overloaded properly, but they all look like this:
void writeInt(ofstream& file, int val) {
file.write(reinterpret_cast<char *>(&val), sizeof(val));
}
int readInt(ifstream& file) {
int val;
file.read(reinterpret_cast<char *>(&val), sizeof(val));
return val;
}
I'll put the class load/save script at the end of the post, but I don't think it'll make too much sense without the rest of the class info.
Anyway, it seems that the file gets saved properly. It has the correct size, and all of the data matches when I load it. However, at some point in the load process, the file.read() function starts returning 0xCCCCCCCC every time. This looks to me like a read error, but I'm not sure why, or how to correct it. Since the file is the correct size, and I don't touch the seekg() function, it doesn't seem likely that it's reaching the end of file prematurely. I can only assume it's an issue with my read/write method, since I did kind of hack it together with limited knowledge. However, if this is the case, why does it read all the data up to a certain point without issue?
The error starts occurring at a random point each run. This may or may not be related to the fact that all the class data is randomly generated.
Does anyone have experience with this? I'm not even sure how to continue debugging it at this point.
Anyway, here are the load/save functions:
void saveToFile(string fileName) {
ofstream dataFile(fileName.c_str());
writeInt(dataFile, inputSize);
writeInt(dataFile, fullSize);
writeInt(dataFile, outputSize);
// Skips input nodes - no data needs to be saved for them.
for (int i = inputSize; i < fullSize; i++) { // Saves each node after inputSize
writeShortInt(dataFile, nodes[i].size);
writeShortInt(dataFile, nodes[i].skip);
writeFloat(dataFile, nodes[i].value);
//vector<int> connects;
//vector<float> weights;
for (int j = 0; j < nodes[i].size; j++) {
writeInt(dataFile, nodes[i].connects[j]);
writeFloat(dataFile, nodes[i].weights[j]);
}
}
read(500);
}
void loadFromFile(string fileName) {
ifstream dataFile(fileName.c_str());
inputSize = readInt(dataFile);
fullSize = readInt(dataFile);
outputSize = readInt(dataFile);
nodes.resize(fullSize);
for (int i = 0; i < inputSize; i++) {
nodes[i].setSize(0); // Sets input nodes
}
for (int i = inputSize; i < fullSize; i++) { // Loads each node after inputSize
int s = readShortInt(dataFile);
nodes[i].setSize(s);
nodes[i].skip = readShortInt(dataFile);
nodes[i].value = readFloat(dataFile);
//vector<int> connects;
//vector<float> weights;
for (int j = 0; j < nodes[i].size; j++) {
nodes[i].connects[j] = readInt(dataFile); //Error occurs in a random instance of this call of readInt().
nodes[i].weights[j] = readFloat(dataFile);
}
read(i); //Outputs class data to console
}
read(500);
}
Thanks in advance!
You have to check the result of open, read, write operations.
And you need to open files (for reading and writing) as binary.
Can't seem to figure out why exactly this program won't work. It is supposed to store data from a csv file into a structure called SurnameInfo (when used with a loop that iterates through each line) but whenever I run it it gets to line 1280 of 151671 of the csv file, crashes, and gives the windows "program.exe has stopped working" popup. Anyone see anything that might cause this? Thanks!!
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
using namespace std;
const int MAXLINE = 1000;
const int MAXARRAY = 1000;
int numberOfNames;
struct SurnameInfo
{
char *name;
int count;
float pctrace[6];
};
SurnameInfo*surnames[MAXARRAY];
void processLine(char *line, int n)
{
surnames[n] = new SurnameInfo; //allocate memory
char * pch = strtok(line, ",");//start tokenizing
int len = strlen(pch); // name length
surnames[n]->name = new char[len+1]; //allocate memory
strcpy(surnames[n]->name, pch); // copy name
surnames[n]->count = atoi(strtok(NULL, ","));//get count
for (int i = 0; i < 6; i++)
{
pch = strtok(NULL, ",");
surnames[n]->pctrace[i] = pch[0] == '(' ? -1 : atof(pch);
}
}
void readLines()
{
char line[MAXLINE];
ifstream inputfile;
inputfile.open("names.csv");
if (!inputfile) return; // can't open
inputfile.getline(line, MAXLINE); //skip title
inputfile.getline(line, MAXLINE);
numberOfNames = 0;
while (!inputfile.eof()) //not end of file
{
processLine(line, numberOfNames++);
inputfile.getline(line, MAXLINE);
}
inputfile.close();
}
int main() {
readLines();
return 0;
}
I see a discrepancy in the code and the stuff that you are talking.
const int MAXARRAY = 1000; && SurnameInfo*surnames[MAXARRAY]; goes against 151671 of the csv file.
You are allocating 1000 and trying to push more to the heap unattended which means it starts eating the memory allocated to the program itself. Or it tries to access the area which it is not supposed to (may be program area of some other process is allocated), and thus pushes out a Segmentation Fault
Also, you need to have a way to destruct the Surnames that are dynamically fed.
My Suggestion :
Approach 1 : Read through the file first and get the number of lines. Allocate the respective memory to Surnames and proceed the way you are.
Though it requires one additional scan of file, but would solve your purpose. Time complexity goes very high if the file size is high.(May be you can cache stuff while reading , use vector?? (think on that))
Approach 2 : Implement a functionality similar to resize of vector.On every new addition to the Surnames, Free the previously allocated memory on heap and reallocate with the higher memory spec by deep copying and inserting new info.
Also,
surnames[n]->pctrace[i] = pch[0] == '(' ? -1 : atof(pch);
I am not very sure whether this would work correctly or not. Just for the sake of safety and more clear code, put that up in parenthesis . Something like this
surnames[n]->pctrace[i] = ((pch[0] == '(') ? -1 : atof(pch));
If this is your one of the first attempts on C++, this is nicely done. Cheers.
Hope the answer helps.
I am trying to read simple BMP file and without performing any operations I am writing it back again to file.
I don't know where the mistake is in reading the file or writing it back.
I have added padding while reading as well as while writing
-- File-Read --.
std::vector<char> tempImageData;
/*tempImageData.resize(m_bmpInfo->imagesize);
file.seekg(m_bmpHeader->dataoffset);
file.read(&tempImageData[0], m_bmpInfo->imagesize);
file.close();*/
tempImageData.resize(m_bmpInfo->imagesize);
int padding = 0;
while (((m_bmpInfo->width*3+padding) % 4) != 0 )
padding++;
for(unsigned int i = 0 ; i < m_bmpInfo->height ; i++)
{
file.seekg(m_bmpHeader->dataoffset + i*(m_bmpInfo->width*3 + padding));
file.read(&tempImageData[i*m_bmpInfo->width*3], i*m_bmpInfo->width*3);
}
file.close();
//bitmaps are stored as BGR -- lets convert to RGB
assert(m_bmpInfo->imagesize % 3 == 0);
for (auto i = tempImageData.begin(); i != tempImageData.end(); i+=3)
{
m_data_red.push_back(*(i+2));
m_data_green.push_back(*(i+1));
m_data_blue.push_back(*(i+0));
}
-- write code
file.write(reinterpret_cast<const char*>(m_bmpHeader), sizeof(BITMAPFILEHEADER));
file.write(reinterpret_cast<const char*>(m_bmpInfo), sizeof(BITMAPINFOHEADER));
// this is wrong.. format asks for bgr.. we are putting all r, all g, all b
std::vector<char> img;
img.reserve(m_data_red.size() + m_data_green.size() + m_data_blue.size());
for(unsigned int i = 0 ; i < m_data_red.size() ; i++)
{
img.push_back(m_data_blue[i]);
img.push_back(m_data_green[i]);
img.push_back(m_data_red[i]);
}
char bmppad[3] = {0};
for(unsigned int i = 0 ; i < m_bmpInfo->height ; i++)
{
// maybe something is wrong
file.write(reinterpret_cast<const char*>(&img[i*m_bmpInfo->width*3]), m_bmpInfo->width * 3 * sizeof(unsigned char));
file.write(bmppad, 1 * ((4-(m_bmpInfo->width*3)%4)%4) * sizeof(char));
}
file.close();
But the results are weird.
Output image------Input image
As the padding is added to every row, I think you need to change this line:
file.seekg(m_bmpHeader->dataoffset + i*m_bmpInfo->width*3 + padding);
to this:
file.seekg(m_bmpHeader->dataoffset + i*(m_bmpInfo->width*3 + padding));
It also might be easier to save the calculated padding rather than calculating it in two different ways.
Edit:
Without all the code to debug through, it is a bit hard to pinpoint, but there is an error on this line:
file.read(&tempImageData[i*m_bmpInfo->width*3], i*m_bmpInfo->width*3);
you should not have the i* part in the amount you are reading. This means at row 200 you are reading 200 rows worth of data into the array, possibly overwriting the end of the array. once you are more than half way through the image, which is interesting given your output.
I have a research project I'm working on. I am a beginner in C++ and programming in general. I have already made a program that generates interacting particles that move on continuous space as time progresses. The only things my program outputs are the XY coordinates for each particle in each time-step.
I want to visualize my findings, to know if my particles are moving as they should. My professor said that I must use gnuplot. Since I could not find a way to output my data in one file so that gnuplot would recognize it, I thought of the following strategy:
a) For each time-step generate one file with XY coordinates of the form "output_#.dat".
b) Generate a .png file for each one of them in gnuplot.
c) Make a movie of the moving particles with all the .png files.
I am going to worry about b and c later, but up to now, I am able to output all my data in one file using this code:
void main()
{
int i = 0;
int t = 0; // time
int j = 0;
int ctr = 0;
double sumX = 0;
double sumY = 0;
srand(time(NULL)); // give system time as seed to random generator
Cell* particles[maxSize]; // create array of pointers of type Cell.
for(i=0; i<maxSize; i++)
{
particles[i] = new Cell(); // initialize in memory
particles[i]->InitPos(); // give initial positions
}
FILE *newFile = fopen("output_00.dat","w"); // print initial positions
for(i=0; i<maxSize; i++)
{
fprintf(newFile, "%f %3 ", particles[i]->getCurrX());
fprintf(newFile, "%f %3 \n", particles[i]->getCurrY());
}
fclose(newFile);
FILE *output = fopen("output_01.dat","w");
for(t = 0; t < tMax; t++)
{
fprintf(output, "%d ", t);
for(i=0; i<maxSize; i++) // for every cell
{
sumX = 0;
sumY = 0;
for(j=0; j<maxSize; j++) // for all surrounding cells
{
sumX += particles[i]->ForceX(particles[i], particles[j]);
sumY += particles[i]->ForceY(particles[i], particles[j]);
}
particles[i]->setVelX(particles[i]->getPrevVelX() + (sumX)*dt); // update speed
particles[i]->setVelY(particles[i]->getPrevVelY() + (sumY)*dt);
particles[i]->setCurrX(particles[i]->getPrevX() + (particles[i]->getVelX())*dt); // update position
particles[i]->setCurrY(particles[i]->getPrevY() + (particles[i]->getVelY())*dt);
fprintf(output, " ");
fprintf(output, "%f %3 ", particles[i]->getCurrX());
fprintf(output, "%f %3 \n", particles[i]->getCurrY());
}
}
fclose(output);
}
This indeed generates 2 files, output_00.dat and output01.dat with the first one containing the initial randomly generated positions and the second one containing all my results.
I can feel that in the nested for loop, where I'm updating the speed and position for the XY coordinates, I can have a FILE* that will store the coordinates for each time step and then close it, before incrementing time. In that way, I will not need multiple pointers to be open at the same time. At least that is my intuition.
I do not know how to generate incrementing filenames. I have stumbled upon ofstream, but I don't understand how it works...
I think what I would like my program to do at this point is:
1) Generate a new file name, using a base name and the current loop counter value.
2) Open that file.
3) Write the coordinates for that time-step.
4) Close the file.
5) Repeat.
Any help will be greatly appreciated. Thank you for your time!
Using ofstream instead of fopen would be a better use of the C++ standard library, whereas now you are using C standard library calls, but there is nothing wrong per se with what you are doing doing now.
It seems like your real core question is how to generate a filename from an integer so you can use it in a loop:
Here is one way:
// Include these somewhere
#include <string>
#include <sstream>
// Define this function
std::string make_output_filename(size_t index) {
std::ostringstream ss;
ss << "output_" << index << ".dat";
return ss.str();
}
// Use that function with fopen in this way:
for (size_t output_file_number=0; /* rest of your for loop stuff */) {
FILE *file = fopen(make_output_filename(output_file_number).c_str(), "w");
/* use the file */
fclose(file);
}
This uses a std::ostringstream" to build a filename using stream operations, and returns the built std::string. When you pass it to fopen, you have to give it a const char * rather than a std::string, so we use the .c_str() member which exists just for this purpose.
I'm working to create a rudimentary file system in c++ and am having issues assigning names to files in my directory table. Here is the definition of a directoryEntry struct.
typedef struct{
char name[112];
unsigned int index;
unsigned int size;
unsigned int type;
unsigned int creation;
} directoryEntry;
Here is some code where I create a new blank file.
if(canFit){
for ( int i = 0; i < numClusters; ++i){
if (directoryTable[i].name[0] == 0x00){
//directoryTable[i].name = *newFile;
strcpy(directoryTable[i].name, newFile);
printf("%s %d ", directoryTable[i].name, i);
directoryTable[i].index = location;
directoryTable[i].size = 0;
directoryTable[i].type = 0x0000;
directoryTable[i].creation = time(NULL);
return 0;
}
}
What is happening here is I'm scanning the directory table for entries that contain a null byte as the first character of the filename. This tells me that that particular directory entry is not occupied. Then I use strcpy to assign the newFile (which is declared as a parameter as char newFile[112]).
The problem is the directory name prints properly in the above printf (printf("%s %d ", directoryTable[i].name, i);) but it appears that the data contained in directoryTable[i].name is deleted. The above code is contained in a method called touch. When the code executes I get something like the following:
touch("file1");
file1 0
touch("file2);
file2 0
which means that the value associated to index 0 is temporarily changed to file1, but is then changed back to several null bytes (Which is how it is originally allocated.) So my question is, why doesn't the value of directoryTable[i] stay the same through multiple calls to touch? directoryTable is a global variable so if the value is assigned it shouldn't disappear when out of scope.
It should also be noted that directoryTable is defined as directoryEntry* directoryTable if that has any bearing on my problem.
My professor will not allow us to use most of the standard libraries in C++. Strings, for example, are illegal. So if you are wondering, that is why I'm not using strings.
Thank you for your time.
EDIT:
Here is code where the directoryEntrys that make up the directoryTable are allocated and added to the directoryTable. They are also added to a file but I feel that is irrelevant to this particular question:
fseek(fp, clusterSize * root, SEEK_SET);
for (int i = 0; i < bootRecord[0] / 128 ; ++i){
fseek(fp, clusterSize * root + 128 * i, SEEK_SET);
directoryEntry * newEntry = (directoryEntry *)malloc(sizeof(directoryEntry));
//newEntry->name = (char *)malloc(112);
//memset(newEntry->name, 0x00, 112);
newEntry->size = 0;
newEntry->type = 0;
newEntry->creation = 0x0000;
newEntry->index = 0;
fwrite(newEntry->name, 112, 1, fp);
fwrite(&newEntry->size, sizeof(int), 1, fp);
fwrite(&newEntry->type, sizeof(int), 1, fp);
fwrite(&newEntry->creation, sizeof(int), 1, fp);
fwrite(&newEntry->index, sizeof(int), 1, fp);
directoryTable[i] = *newEntry;
}
You'll need some sort of actual storage defined for your directory table:
#define NUM_FILES 15
DirectoryEntry directoryTable[NUM_FILES]
The pointer you've defined just points to random memory. I'm surprised it doesn't segfault.
Edit
You malloc the DirectoryEntries, but you're not storing them anywhere valid. You have no storage for your pointers, so you're losing them as soon as you assign them to the directoryTable You'll either need to create an array of DirectoryEntry*:
DirectoryEntry* directoryTable[MAX_ENTRIES]
Where you can put your malloc'd pointers or, just create the whole table at runtime:
DirectoryEntry* directoryTable;
int newFS(int size, int clusterSize) {
//Use C++ 'new' instead of malloc
directoryTable = new DirectoryEntry[size / clusterSize];
//Make sure to 'delete directoryTable' at program completion.
}