C++ Reading Objects from File Error - c++

fstream file;
Patient Obj("XXX",'M',"XXX");
file.open("Patients.dat",ios::in|ios::out|ios::app);
file.seekg(ios::end);
file.write((char*)&Obj,sizeof(Obj));
file.seekg(ios::beg);
Patient x;
file.read((char*)&x,sizeof(x));
x.printallInfo();
file.close();
I'm writing objects to files using this code but when i reading data VC++ 6 Crashes and thows a exception 'Access violation' .(Writing is successful)
Entire Code
#include <iostream>
#include<fstream>
#include <iomanip.h>
#include "Patient.cpp"
using namespace std;
int main(){
fstream file;
Patient Obj("XXX",'M',"XXX");
file.open("Patients.dat",ios::in|ios::out|ios::app);
file.seekg(ios::end);
file.write((char*)&Obj,sizeof(Obj));
file.seekg(ios::beg);
Patient x;
file.read((char*)&x,sizeof(x));
file.close();
return 0;
}

That seems like a brittle and non-portable way to marshal classes. One thing that could be happening with the way you do this is that you aren't making a deep copy of the data you're serializing. for instance, if one of the members of your Patient class is a std::string, a bare pointer is written to the file, but no string data is written. Worse, when you read that back in, the pointer points... somewhere...
A better way to deal with this issue is to actually implement a class specific method that knows exactly how to serialize and unserialize each member.

I'm not a C++ guru. Onething it doesn't seem correct here is that Object x in your code is not initialized.

Here's how you can read and write strings:
void writestring(std::ostream & out, const std::string & s)
{
std::size_t size = s.size();
out.write((char*)&size,sizeof(size));
out << s;
}
std::string readstring(std::istream & in)
{
std::size_t size;
in.read((char*)&size,sizeof(size));
char* buf = new char[size+1];
in.read(buf,size);
buf[size] = 0;
std::string s(buf);
delete [] buf;
return s;
}

If patient has pointers (e.g. to strings as I think it does based on its constructor) then your saving saves just the pointers, not values they point to. So loading initializes pointers to places in memory which might well be deleted or moved.
ok, here is the code I could not add to the comment below
class Patient : public Person{
.....
bool savePerson(fstream& stream) const
{
// you should do to Person the same thing I did for Patient
return true;
}
bool saveMedicalDetails(fstream& stream) const
{
for(int i=0;i<5;i++)
{
stream<<mD[i].number<<endl;
// we suppose here that the strings cannot contain 'end-of-line'
// otherwise you should save before any data of a string
// the number of characters in that string, like
// stream<<mD[i].doctors_name.size()<<" "<<mD[i].doctors_name<<endl;
stream<<mD[i].doctors_name<<endl;
stream<<mD[i].diognosis<<endl;
stream<<mD[i].medicine<<endl;
stream<<mD[i].date<<endl;
}
return stream;
}
bool savePaymentDetails(fstream& stream)const
{
stream<<pD.admisson<<endl;
stream<<pD.hospital_charges<<endl;
stream<<pD.doctor_charges<<endl;
return stream;
}
bool save(fstream& stream) const
{
return savePerson(stream) ||
saveMedicalDetails(stream) ||
savePaymentDetails(stream);
}
bool loadPerson(fstream& stream)
{
// you should do to Person the same thing I did for Patient
return true;
}
bool loadMedicalDetails(fstream& stream)
{
for(int i=0;i<5;i++)
{
stream>>mD[i].number;
// we suppose here that the strings cannot contain 'end-of-line'
// otherwise you should load before any data of a string
// the number of characters in that string, like
// int size;
// stream>>size;
// char *buffer=new char[size+1];
// stream.read(buffer,size);
// *(buffer+size)=0;
// mD[i].doctors=buffer;
// delete [] buffer;
getline(stream,mD[i].doctors);
getline(stream,mD[i].diognosis);
getline(stream,mD[i].medicine);
getline(stream,mD[i].date);
}
return stream;
}
bool loadPaymentDetails(fstream& stream)
{
stream>>pD.admisson;
stream>>pD.hospital_charges;
stream>>pD.doctor_charges;
return stream;
}
bool load(fstream& stream) const
{
return savePerson(stream) ||
saveMedicalDetails(stream) ||
savePaymentDetails(stream);
}
};

I figured it out using char arrays instead of strings will solve this problem , thanks all for your great help !

Related

Call C API with vector of strings from C++

In my C++ application, I use an external library that exposes a C API. Some of the C functions take arrays of strings as input and use char** for that:
void c_api_function(char** symbols, int count);
(Note: I think a pointer to const would be more appropriate, but it seems as if const correctness was not important for the library authors.)
The strings must use a specific encoding.
Currently, in order to call the API, I first convert the strings to the correct encoding and store the result in a vector<string>. Then I create a vector<char*> that can be passed to the C API:
std::string encode(std::string const& symbol);
void call_api(std::vector<std::string> const& symbols)
{
std::vector<std::string> encoded_symbols;
for (auto const& s : symbols)
{
encoded_symbols.push_back(encode(s));
}
std::vector<char*> encoded_symbol_ptrs;
for (auto const& s : encoded_symbols)
{
encoded_symbols_ptrs.push_back(s.data());
}
c_api_function(encoded_symbols_ptrs.data(), (int)encoded_symbols_ptrs.size());
}
I dont like this approach, because I need two vectors. The first vector ensures that the strings are kept alive, the second vector can be passed to the API. Is there a way that only uses a single container, but still uses automatic memory management? If necessary, I can freely change the signature of the encode function, for example, using std::unique_ptr as return value.
//
// This is how to do this with the smallest number of allocations as possible (best performance)
//
// I guess: if string contains only ascii encode has no job to do and then input == output,
// then allocation isn't necessary and input string can be used to pass to c_api_function()
// I would recommend to change the encode() to do not generate output string if encode has nothing to do
// in that case if encode() returns true (encoding was made: input != output) and output will be store in 'out'
// if encode() returns false then input == output and 'out' isn't used
//
bool encode(const std::string& symbol_in, std::string& out);
void call_api(const std::vector<std::string>& symbol_in) {
const size_t c = symbol_in.size(); // size usually have cost in operation: end - begin :)
if (c > 0x7FFFFFFF) { // good idea if you must convert from size_t to int further
throw std::overflow_error("..we have a problem here..");
}
auto it_in = symbol_in.cbegin(); // const iterator for input
auto it_end = symbol_in.cend(); // const iterator for input end
std::vector<std::string> encoded_symbols(c); // allocate array of string, but some std::string items may not be used if encode will return false
std::vector<const char*> encoded_symbols_raw(c); // array of C raw pointers
auto it_out = encoded_symbols.begin(); // iterator for std::string objects output
auto raw_out = encoded_symbols_raw.begin(); // iterator for raw output
for (; it_in != it_end; ++it_in, ++it_out, ++raw_out) {
if (encode(*it_in, *it_out)) { // if *it_out contains encoding result:
*raw_out = it_out->c_str(); // set std::string buffer as raw pointer
}
else {
*raw_out = it_in->c_str(); // no encoding needed - just pass input string buffer
}
}
c_api_function((char**)encoded_symbols_raw.data(), (int)c);
}
Since encoded_symbols only exists within your call_api() function, I would prefer to have an object that contains the all the encoded symbols and a member function which acts upon them. As an executable example:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
void c_api_function(char** symbols, int count)
{
for(int x = 0; x < count; ++x)
{
std::cout << symbols[x] << '\n';
}
}
std::string encode(std::string const& symbol)
{
return symbol;
}
class EncodedSymbols
{
friend void call_api(EncodedSymbols& symbols);
friend void call_api(std::vector<std::string> const& symbols);
public:
EncodedSymbols(const EncodedSymbols& other) = delete;
EncodedSymbols(EncodedSymbols&& other) = default;
~EncodedSymbols()
{
for(int x = 0; x < number_of_encoded_symbols; ++x)
{
delete[] encoded_symbol_array[x];
}
}
static EncodedSymbols create_from(const std::vector<std::string>& symbols)
{
EncodedSymbols obj;
obj.encoded_symbol_array = std::make_unique<char*[]>(symbols.size());
obj.number_of_encoded_symbols = symbols.size();
for(int x = 0; x < symbols.size(); ++x)
{
const std::string encoded = encode(symbols[x]);
obj.encoded_symbol_array[x] = new char[encoded.length() + 1];
std::copy(encoded.begin(), encoded.end(), obj.encoded_symbol_array[x]);
obj.encoded_symbol_array[x][encoded.length()] = '\0';
}
return obj;
}
void call_api()
{
c_api_function(encoded_symbol_array.get(), number_of_encoded_symbols);
}
private:
EncodedSymbols() = default;
std::unique_ptr<char*[]> encoded_symbol_array;
int number_of_encoded_symbols;
};
void call_api(EncodedSymbols& symbols)
{
c_api_function(symbols.encoded_symbol_array.get(),
symbols.number_of_encoded_symbols);
}
void call_api(std::vector<std::string> const& symbols)
{
auto encoded = EncodedSymbols::create_from(symbols);
c_api_function(encoded.encoded_symbol_array.get(),
encoded.number_of_encoded_symbols);
}
int main()
{
std::vector<std::string> symbols{"one", "two"};
auto encoded_symbols = EncodedSymbols::create_from(symbols);
encoded_symbols.call_api();
call_api(encoded_symbols);
call_api(symbols);
return 0;
}
If there are other functions in your C library that act upon encoded symbols then (in my mind) it makes more sense to put them in a class. All the manual memory management can be hidden behind a nice interface.
If you prefer, you can also have a bare function which acts upon an EncodedSymbols instance. I have included that variant too.
As a third alternative, you could keep your current function prototype and use the EncodedSymbols type for RAII. I have shown that too in my example.

C++ How to read data file to struct or vectors and return struct or vectors?

I already did this in MATLAB and want to do it in C++. The file I want to read from looks similar to:
0,397 0,372 0,385 0,354 0,397 0,384
0,389 0,347 0,385 0,317 0,397 0,380
0,379 0,308 0,381 0,285 0,395 0,361
Since the data is represented like that I had to choose a way to store it. I made a Class called OrlData which should have a function that read the text file and put the data into a array or a struct like:
struct DATA
{
float a[400];
string line;
} orldata[1200];
This struct should work like a normal array, orldata[1].a[2] = 0,347 and so on. But while searching for a better solution I figured that it was bad practice to return an array and it would be better to use vectors. (But I havent really had the breakthrough with those so I continued with structs)
My code is as below and is actually working. This is not implemented in the Class OrlData and is in the main until now. It is loading the file into the struct orldata:
struct DATA
{
float a[400];
string line;
} orldata[MAX];
int main()
{
int counter = 0;
int index = 0;
std::string Filename = "orl/orl_data.txt";
std::ifstream input(Filename);
std::string line;
while (std::getline(input, line)) {
counter++;
orldata[counter].line = line;
}
for (int i = 0; i < MAX; i++) {
std::istringstream iss(orldata[i].line);
for (std::string s; iss >> s; ) {
orldata[i].a[index] = strtof((s).c_str(), 0);
index++;
}
index = 0;
}
std::cout << orldata[2].a[5];
return 0;
}
But when I tried to put this code into a function which should return the struct it crashed:
DATA ORLData::create_orl_data() {
DATA orldata[1200];
....
return orldata[1200];
}
...
int main(){
ORLData orltemp;
ORLData::DATA orlstruct = orltemp.create_orl_data();
....
}
Until now I understood that it's bad practice to return struct arrays like this. And I learned that it's better to use vectors but I havent figured out how to actually use them as matrices.
So my problem can be summed to: I want to read from a text file that looks like the above and then load them into an array like array[0].a[2] which should store all the data. How can I do this?
Please ask if you want me to elaborate on the issues I have.
DATA ORLData::create_orl_data() {
DATA orldata[1200];
....
return orldata[1200];
}
is wrong on couple of accounts.
It can return only one element of the array.
The valid ranges for the index of orldata is 0-1199. return orldata[1200] accesses the array using an out of bounds index, and causes undefined behavior. In your case, that results in a crash.
Change that function to return a std::vector<DATA>.
std::vector<DATA> ORLData::create_orl_data() {
std::vector<DATA> orldata;
....
return orldata;
}

vector<string> doesnt work when using seperate classes

I have a txt file which has a rogue-like level
I load it like so:
void File::LoadLevel()
{
ifstream input_file;
input_file.open("Level_1.txt");
if (input_file.fail())
{
perror("Level_1.txt");
}
while (input_file >> _level)
{
_level_instance.push_back(_level);
}
}
variables:
string _level;
vector<string> _level_instance;
I print it out like this:
for (int i = 0; i < _level_instance.size(); i++)
{
cout << _level_instance[i] << endl;
}
which works fine.
however I have a vector in another class as well and i use a getter like this:
vector<string>GetlevelData(){ return _level_data; }
and I change the LoadLevel() from this:
_level_instance.push_back(_level);
to this:
Level Lvl;
Lvl.GetLevelData().pushback(_level);
I make an method in 'Level' class which prints it out to the screen same as before
it compiles but it doesnt print out anything why?
By the way in the int main() neccesary methods are executed which is OpenLevel() from File class and Print() from Level class
EDIT:
passing it &by reference didnt work
here are both methods in Level.h:
void SetLevelData(const std::string &string) {
_level_data.push_back(string);
}
//Getters
vector<string>& GetlevelData(){ return _level_data; }
in File.cpp:
void File::LoadLevel()
{
ifstream input_file;
Level lvl;
input_file.open("Level_1.txt");
if (input_file.fail())
{
perror("Level_1.txt");
}
while (input_file >> _level)
{
lvl.GetlevelData().push_back(_level);
}
}
it doesnt work it prints nothing, even though i added '&'
the result is same when i try it with 'push_back' method in Level.h
Here is int main() just in case:
int main()
{
File f;
Level lvl;
f.LoadLevel();
lvl.PrintLevel();
system("PAUSE");
return 0;
}
And PrintLevel() in Level.cpp:
void Level::PrintLevel()
{
for (int i = 0; i < _level_data.size(); i++)
{
cout << _level_data[i] << endl;
}
}
The GetlevelData function returns its vector by value which means a whole new copy of it is created. Anything you push into that vector will be lost when the copy goes out of scope (which happens when the expression Lvl.GetLevelData().pushback(_level) is done).
You should return it by reference instead:
vector<string>& GetlevelData(){ return _level_data; }
// ^
// |
// Return by reference
vector<string>GetlevelData() returns a copy of the vector and not a reference to it.
So your Lvl.GetLevelData().push_back(_level); returns a copy adds data to the vector and then deletes that copy again. So you add it to a vector that will be immediately be deleted again.
You would need to return it either by reference:
vector<string>& GetlevelData(){ return _level_data; }
Or write a method to push back the data:
void push_back( const std::string &string) {
_level_data.push_back(string);
}

Access violation writing location when using pointers

I'm trying to write a program that allows a user to input data into a text file to organize class assignments. The user can display the list of assignments, enter an assignment into the file, and search for specific course work that is due. I am having a problem where I get an access violation writing location error and I'm not entirely sure how to fix it. I have looked at previous discussions that are posted but can't quite figure out where I am going wrong in my code.
This is taskList.cpp.
The header file taskList.h is posted after it.
I'm using VS2013.
When I debug the error is posted at line 55 in the taskList.cpp file below
list = new Task[capacity];
#include "taskList.h"
#include "mytools.h"
TaskList::TaskList()
{
capacity = CAP;
list = new Task[capacity];
size = 0;
}
TaskList::TaskList(char filename[])
{
capacity = CAP;
list = new Task[capacity];
size = 0;
//load from file.
ifstream inData;
Task aTask;
char tempName[MAXCHAR];
char tempDescription[MAXCHAR];
char tempDate[MAXCHAR];
inData.open("task.txt");
if (!inData){
cout << "cannot open file";
exit(0);
}
inData.getline(tempName, MAXCHAR, ';');
while (!inData.eof())
{
inData.getline(tempDescription, MAXCHAR, '\n');
inData.getline(tempDate, MAXCHAR, '\n');
aTask.setName(tempName);
aTask.setDescription(tempDescription);
aTask.setDate(tempDate);
addTask(aTask);
inData.getline(tempName, MAXCHAR, ';');
}
inData.close();
;
TaskList::~TaskList()
{
if (list)
{
delete [] list;
list = NULL;
}
}
//Adds a video item to the list
void TaskList::addTask(Task aTask)
{
list[size++] = aTask;
}
//displays the list of videos
void TaskList::showList()
{
int i = 0;
for (i = 0; i < size; i++)
{
list[i].printTask();
}
}
void TaskList::searchList()
{
char searchName[MAXCHAR];
char tempName[MAXCHAR];
int i;
bool found = false;
cout << "Enter the name of the course to search for: ";
cin.getline(searchName, MAXCHAR);
for (i = 0; i < size; i++)
{
list[i].getName(tempName);
if (strstr(searchName, tempName) != NULL)
{
list[i].printTask();
found = true;
}
}
if (found == false)
cout << "No search results." << endl;
}
void TaskList::writeData()
{
ofstream outData;
outData.open("task.txt");
if (!outData)
{
cout << "cannot open file";
exit(0);
}
for (int i = 0; i < size; i++)
list[i].printToFile(outData);
outData.close();
}
//expand array function
void TaskList::expand()
{
char tempName[MAXCHAR];
char tempDescription[MAXCHAR];
char tempDate[MAXCHAR];
capacity += GROWTH;
Task *temp = new Task[capacity];
//copy from old array to new array
for (int i = 0; i < size; i++)
{
list[i].getName(tempName);
list[i].getDescription(tempDescription);
list[i].getDate(tempDate);
temp[i].setName(tempName);
temp[i].setDescription(tempDescription);
temp[i].setDate(tempDate);
}
//delete old array
delete [] list;
list = NULL;
//point ptr to temp
list = temp;
//set temp to NULL
temp = NULL;
}
The header file (taskList.h)
#include <iostream>
#include <fstream>
using namespace std;
const int CAP = 2;
const int GROWTH = 2;
//define class VideoList for array of Videos and its size.
class TaskList
{
private:
Task *list;
int size;
int capacity;
void expand();
public:
//constructors
TaskList();
TaskList(char filename[]);
//destructor
~TaskList();
//database functions
void addTask(Task aTask);
void showList();
void searchList();
void writeData();
};
#endif
Just to be sure that everything is made clear because there are 3 header files, 4 source files, and a text file, I am include the task.h header file and task.cpp source file.
Here is task.h:
#ifndef TASK_H
#define TASK_H
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string.h>
using namespace std;
const int MAXCHAR = 101;
class Task
{
private:
char *name;
char *description;
char *date;
public:
//defult constructor
Task();
//constructor with parameters
Task(char newName[], char newDescription[], char newDate[]);
//copy constructor
Task(const Task &otherTask);
//Accessor funct
void getName(char returnName[]);
void getDescription(char returnDescription[]);
void getDate(char returnDate[]);
//mutator function
void setName(char newName[]);
void setDescription(char newDescription[]);
void setDate(char newDate[]);
//print function to print a video
void printTask();
void printToFile(ofstream &outFile);
const Task& operator= (const Task& anItem);
};
#endif
Here is the task.cpp file, not sure if this is necessary but I am adding it for clarity:
#include "task.h"
#include <iostream>
using namespace std;
//defult constructor
Task::Task()
{
strcpy(name, "no course name");
strcpy(description, "no task description");
strcpy(date, "no due date");
}
//constructor with parameters
Task::Task(char newName[], char newDescription[], char newDate[])
{
name = new char[strlen(newName) + 1];
description = new char[strlen(newDescription) + 1];
date = new char[strlen(newDate) + 1];
strcpy(name, newName);
strcpy(description, newDescription);
strcpy(date, newDate);
}
//copy constructor
Task::Task(const Task &otherTask)
{
//allocate memory and then copy name
this->name = new char[strlen(otherTask.name) + 1];
strcpy(name, otherTask.name);
//allocate memory and then copy description
this->description = new char[strlen(otherTask.description) + 1];
strcpy(description, otherTask.description);
//allocate memory and then copy date
this->date = new char[strlen(otherTask.date) + 1];
strcpy(date, otherTask.date);
}
//Accessor functions
void Task::getName(char returnName[])
{
strcpy(returnName, name);
}
void Task::getDescription(char returnDescription[])
{
strcpy(returnDescription, description);
}
void Task::getDate(char returnDate[])
{
strcpy(returnDate, date);
}
//mutator functions
void Task::setName(char newName[])
{
strcpy(name, newName);
}
void Task::setDescription(char newDescription[])
{
strcpy(description, newDescription);
}
void Task::setDate(char newDate[])
{
strcpy(date, newDate);
}
//prints a video item
void Task::printTask()
{
cout << name << ';' << description << ';' << date << endl;
}
void Task::printToFile(ofstream &outFile)
{
outFile << name << ';' << description << ';' << date << endl;
}
//assignment operator overloaded
const Task& Task::operator= (const Task& aTask)
{
strcpy(this->name, aTask.name);
this->description = aTask.description;
strcpy(this->description, aTask.description);
this->date = aTask.date;
strcpy(this->date, aTask.date);
return *this;
}
Here is the problem:
char *name;
// ...
strcpy(name, "no course name");
The first line creates a pointer which currently does not point anywhere. Then you tell strcpy to copy that string to where the pointer is pointing, so it writes the string to "nowhere" (in practice: a semi-random memory location). This causes your access violation.
To fix this, replace the code with:
std::string name;
// ...
name = "no course name";
Do the same for description and date. Note that this means you don't need a copy-constructor or copy-assignment operator or destructor; because the default ones behave correctly.
Of course you will need to change your accssor functions (but they were badly designed anyway since the caller cannot prevent a buffer overflow):
std::string getName() const { return name; }
Also, change Task *list; to std::vector<Task> list; and stop using new and delete. The vector correctly manages memory for you.
It is simplest and easiest to do this task without using pointers or manual memory management or C-library functions such as strcpy. You'll halve your code size (at least) and it will be much less prone to error.
You may need #include <string> and #include <vector>.
Since the erroe happens at allocation if an array (list = new Task[capacity]) i guess your problem is in default constructor of Task class. try playing with this constructor a liitle , i suggest allocating yor char arrays (names , descriptions and data) befor filling them.
somecode like name = new Char[14]; (and of course same for the other two)
You have failed to follow the rule-of-five or the rule-of-zero.
The correct thing (rule-of-zero) would be to implement TaskList in terms of std::vector<Task>.
Seeing as your assignment demands that you use a "dynamic array", perhaps they don't want you to use std::vector. This means that you are stuck with manual memory management. This means that you need to correctly implement or remove the following functions:
//You have these
TaskList::TaskList();
TaskList::TaskList(char filename[]);
TaskList::~TaskList();
//You are missing these, this is your problem:
TaskList::TaskList(TaskList const &o); //Copy constructor
TaskList &TaskList::operator=(TaskList const &o); //Copy assignment
TaskList::TaskList(TaskList &&o); //Move constructor
TaskList &TaskList::operator=(TaskList &&o); //Move assignment
If you do not explicitly supply these functions, the compiler may automatically generate them, and the compiler-generated versions will be incorrect (for the situation where you are manually managing resources within TaskList), as they will do member-wise moves or copies, rather than copying or moving the underlying resources. When you then use these incorrect compiler-generated versions, your code will have strange behaviour.
For Task, you shouldn't be managing multiple resources at once. Use std::string, or otherwise write your own string class, and then use it to manage the string members of Task. If you do not, your code is almost guaranteed to be incorrect (due to a lack of exception safety).

C++ creating an array in a temporary class

Newbie question! I've started a small project that loads integer values from a file into an array. (The array needs to be accessed at random which is why i've chosen an array and not a vector.)
To load the data values from the file I've created a Load/Save class. The load function reads the first line of the file which gives us the total number of entries the array needs to have, then it will fill the array with the rest of the values in that file.
This load object is only created temporarily, I want to give the data to the program and then delete the object.
What is the best way to achieve this? should I create the array in main() and pass the load object a reference, in which case how can I create the array so it can be re-sized for the amount of data that needs loading..?
here is the load/save class:
class FileIOClass {
public:
FileIOClass();
int ReadFile(char*);
private:
};
this is the cpp code for the class:
FileIOClass::FileIOClass() {
}
int FileIOClass::ReadFile(char* file_name) {
string line;
ifstream file;
file.open(file_name, ios::in);
cout << "Loading data...\n";
int num_x, num_y, array_size;
bool machine_header = false;
if (file.is_open()) {
while(getline(file, line)) {
if (line.size() && machine_header == false) {
// Load machine header information
file >> num_x;
file >> num_y;
file >> array_size;
machine_header = true; // machine header has now been read, set this to true.
}
else {
// this is where i want to load the data from the file into an array.
// the size of the array should be equal to the value in array_size.
}
}
cout << "Loading complete!\n";
}
else {cout<<"File did not open!\n";}
file.close();
return 0;
}
and here is the main.cpp so far:
int main(int argc, char** argv)
{
FileIOClass data_in;
data_in.ReadFile(argv[1]);
return 0;
}
there will be several other classes that will process the data thats contained in the array.
I bet there are a load of odd newbie mistakes in this code - please feel free to point them out, better to learn these things now.
Thanks all!
Ian.
Somthing like this might be good:
vector<int> myVector(array_size);
for(int i=0; file && i<array_size; i++) {
file >> myVector[i];
}
As long as you've already decided on using a class to read the file, storing the data within the class seems reasonable. add a member to this class to store the data:
class FileIOClass {
public:
FileIOClass();
int ReadFile(char*);
unsigned int operator [](int i) const {return m_data[i];}
int size(void) { return m_data.size(); }
private:
std::vector<int> m_data;
};
and insert data into this member in your ReadFile method:
while(getline(file, line)) {
int pos = 0;
if (line.size() && machine_header == false) {
// Load machine header information
file >> num_x;
file >> num_y;
file >> array_size;
m_data.resize(array_size);
machine_header = true; // machine header has now been read, set this to true.
}
else {
file >> m_data[pos++];
// this is where i want to load the data from the file into an array.
// the size of the array should be equal to the value in array_size.
}
}
notice that I overloaded the [] operator, so you can use your class like this:
int main(int argc, char** argv)
{
FileIOClass data_in;
data_in.ReadFile(argv[1]);
if (data_in.size() >= 1)
cout << data_in[0];
return 0;
}
The array needs to be accessed at random which is why i've chosen an array and not a vector.
C++ vectors allow efficient random access (they are arrays under the hood). Use std::vector unless you have profiled your code and found them inefficient for what you are doing.