Writing to a file from multiple functions and replacing the values C++ - c++

I have a file example.txt which will be updated with values by different functions at seperate lines. And the mentioned three functions will be in a timer loop so it will continuously calling the three functions again and again so the three functions will need to write the file with their updated values calculated in it.
For better understanding please see the example scenario,
First time when the functions called,
*Function1 is writing value of 1 at first line of the file.
*Function2 is writing value of 5 at second line of the file.
*Function3 is writing value of 7 at third line of the file.
Now again timer function calling the above three functions again and i am expecting the below output in the file to be written.
*Function1 should write value of 8 at first line of the file.
*Function2 should write value of 9 at second line of the file.
*Function3 should write value of 10 at third line of the file.
Sample program :
#include <iostream>
#include <fstream>
using namespace std;
void writeToFile(int seq)
{
fstream myfile;
myfile.open("example.txt",fstream::in | fstream::out | fstream::app );
myfile << seq <<endl;
myfile.close();
}
void A()
{
writeToFile(5);
}
void B()
{
writeToFile(2);
}
void C()
{
writeToFile(4);
}
//assume timer function called for every 20secs;
void timer_func()
{
A();
B();
C();
}
int main()
{
timer_func();
return 0;
}
Please suggest me some possible ways to attain it.

Consider keeping the file in memory in a class and writing it as soon as something changes. And remember thread safety, if applicable.

It is bad idea to do things in that way, but if you want so...
#include <string> // string
#include <fstream> // fstream
#include <cstdio> // snprintf
#include <cassert> // assert
#include <cstring> // memset
#define INITIAL_LINE_COUNT 3
#define INITIAL_FILE_NAME "example.txt"
// singleton class that provides writing to the file
class LineWriter
{
private:
std::fstream m_file;
int m_line_count;
// common singleton implementation
LineWriter() = delete;
~LineWriter() = default;
LineWriter(const LineWriter&) = delete;
LineWriter& operator = (const LineWriter&) = delete;
LineWriter(LineWriter&&) = delete;
LineWriter& operator = (LineWriter&&) = delete;
LineWriter(const std::string& filename, int line_count)
{
m_file.exceptions(std::fstream::badbit);
m_file.open(
filename,
std::fstream::out | std::fstream::binary
);
// fill the file with empty 16-byte length strings ended by CRLN
{
for (int i = 0; i < line_count; ++i)
{
m_file.write(" \r\n", 16);
}
}
m_line_count = line_count;
}
public:
void write(int line, int value)
{
// just to check that everything is ok
assert(m_file.is_open());
assert(line <= m_line_count && line > 0);
char buffer[14];
int size = std::snprintf(buffer, 14, "%d", value);
// calculate position of line
// just simple (line - 1) * 16
int pos = (line - 1) << 4;
// clear previous value
m_file.seekp(pos);
m_file.write(" ", 14);
// write new one
m_file.seekp(pos);
m_file.write(buffer, size);
}
static LineWriter& get_instance()
{
static LineWriter instance(INITIAL_FILE_NAME, INITIAL_LINE_COUNT);
return instance;
}
};
void write_to_file(int line, int value)
{
LineWriter::get_instance().write(line, value);
}
void call_a() { write_to_file(1, 5); }
void call_b() { write_to_file(2, 13); }
void call_c() { write_to_file(3, 2); }
void timer_func()
{
call_a();
call_b();
call_c();
}
int main()
{
while (true)
{
timer_func();
}
}
As mentioned #n.m. it is much better to just cache result of all functions and write them single time (if there are not so many lines).
If there are a lot of values and strings, so it is better to use database engines like sqlite as mentioned #JesperJuhl in coments.
Also this example is not thread safe, if you need call this writer from multiple threads just add member mutex lock at the top of LineWriter::write method:

Related

C++ Declaring arrays in class and declaring 2d arrays in class

I'm new with using classes and I encountered a problem while delcaring an array into a class. I want to initialize a char array for text limited to 50 characters and then replace the text with a function.
#ifndef MAP_H
#define MAP_H
#include "Sprite.h"
#include <SFML/Graphics.hpp>
#include <iostream>
class Map : public sprite
{
private:
char mapname[50];
int columnnumber;
int linenumber;
char casestatematricia[];
public:
void setmapname(char newmapname[50]);
void battlespace(int column, int line);
void setcasevalue(int col, int line, char value);
void printcasematricia();
};
#endif
By the way I could initialize my 2d array like that
char casestatematricia[][];
I want later to make this 2d array dynamic where I enter a column number and a line number like that
casestatematricia[linenumber][columnnumber]
to create a battlefield.
this is the cpp code so that you have an idea of what I want to do.
#include "Map.h"
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace sf;
void Map::setmapname(char newmapname[50])
{
this->mapname = newmapname;
}
void Map::battlespace(int column, int line)
{
}
void Map::setcasevalue(int col, int line, char value)
{
}
void Map::printcasematricia()
{
}
thank you in advance.
Consider following common practice on this one.
Most (e.g. numerical) libraries don't use 2D arrays inside classes.
They use dynamically allocated 1D arrays and overload the () or [] operator to access the right elements in a 2D-like fashion.
So on the outside you never can tell that you're actually dealing with consecutive storage, it looks like a 2D array.
In this way arrays are easier to resize, more efficient to store, transpose and reshape.
Just a proposition for your problem:
class Map : public sprite
{
private:
std::string mapname;
int columnnumber;
int linenumber;
std::vector<char> casestatematricia;
static constexpr std::size_t maxRow = 50;
static constexpr std::size_t maxCol = 50;
public:
Map():
casestatematricia(maxRow * maxCol, 0)
{}
void setmapname(std::string newmapname)
{
if (newmapname.size() > 50)
{
// Manage error if you really need no more 50 characters..
// Or just troncate when you serialize!
}
mapname = newmapname;
}
void battlespace(int col, int row);
void setcasevalue(int col, int row, char value)
{
// check that col and line are between 0 and max{Row|Column} - 1
casestatematricia[row * maxRow + col] = value;
}
void printcasematricia()
{
for (std::size_t row = 0; row < maxRow; ++row)
{
for (std::size_t col = 0; col < maxCol; ++col)
{
char currentCell = casestatematricia[row * maxRow + col];
}
}
}
};
For access to 1D array like a 2D array, take a look at Access a 1D array as a 2D array in C++.
When you think about serialization, I guess you want to save it to a file. Just a advice: don't store raw memory to a file just to "save" time when your relaunch your soft. You just have a non portable solution! And seriously, with power of your computer, you don't have to be worry about time to load from file!
I propose you to add 2 methods in your class to save Map into file
void dump(std::ostream &os)
{
os << mapname << "\n";
std::size_t currentRow = 0;
for(auto c: casestatematricia)
{
os << static_cast<int>(c) << " ";
++currentRow;
if (currentRow >= maxRow)
{
currentRow = 0;
os << "\n";
}
}
}
void load(std::istream &is)
{
std::string line;
std::getline(is, line);
mapname = line;
std::size_t current_cell = 0;
while(std::getline(is, line))
{
std::istringstream is(line);
while(!is.eof())
{
char c;
is >> c;
casestatematricia[current_cell] = c;
++current_cell;
}
}
}
This solution is only given for example. They doesn't manage error and I have choose to store it in ASCII in file. You can change to store in binary, but, don't use direct write of raw memory. You can take a look at C - serialization techniques (just have to translate to C++). But please, don't use memcpy or similar technique to serialize
I hope I get this right. You have two questions. You want know how to assign the value of char mapname[50]; via void setmapname(char newmapname[50]);. And you want to know how to create a dynamic size 2D array.
I hope you are comfortable with pointers because in both cases, you need it.
For the first question, I would like to first correct your understanding of void setmapname(char newmapname[50]);. C++ functions do not take in array. It take in the pointer to the array. So it is as good as writing void setmapname(char *newmapname);. For better understanding, go to Passing Arrays to Function in C++
With that, I am going to change the function to read in the length of the new map name. And to assign mapname, just use a loop to copy each of the char.
void setmapname(char *newmapname, int length) {
// ensure that the string passing in is not
// more that what mapname can hold.
length = length < 50 ? length : 50;
// loop each value and assign one by one.
for(int i = 0; i < length; ++i) {
mapname[i] = newmapname[i];
}
}
For the second question, you can use vector like what was proposed by Garf365 need to use but I prefer to just use pointer and I will use 1D array to represent 2d battlefield. (You can read the link Garf365 provide).
// Declare like this
char *casestatematricia; // remember to initialize this to 0.
// Create the battlefield
void Map::battlespace(int column, int line) {
columnnumber = column;
linenumber = line;
// Clear the previous battlefield.
clearspace();
// Creating the battlefield
casestatematricia = new char[column * line];
// initialise casestatematricia...
}
// Call this after you done using the battlefield
void Map::clearspace() {
if (!casestatematricia) return;
delete [] casestatematricia;
casestatematricia = 0;
}
Just remember to call clearspace() when you are no longer using it.
Just for your benefit, this is how you create a dynamic size 2D array
// Declare like this
char **casestatematricia; // remember to initialize this to 0.
// Create the battlefield
void Map::battlespace(int column, int line) {
columnnumber = column;
linenumber = line;
// Clear the previous battlefield.
clearspace();
// Creating the battlefield
casestatematricia = new char*[column];
for (int i = 0; i < column; ++i) {
casestatematricia[i] = new char[line];
}
// initialise casestatematricia...
}
// Call this after you done using the battlefield
void Map::clearspace() {
if (!casestatematricia) return;
for(int i = 0; i < columnnumber; ++i) {
delete [] casestatematricia[i];
}
delete [][] casestatematricia;
casestatematricia = 0;
}
Hope this help.
PS: If you need to serialize the string, you can to use pascal string format so that you can support string with variable length. e.g. "11hello world", or "3foo".

C++ - one function makes others malfunction

Here is my task:
Write class Word which has:
pointer on array of characters
constructors and destructors
function to read word
function to check if character which is passed to it as argument occurs in word and return position of occurance
function to check which of two words has more occurances of number 10 and to return that number of occurances
Here is my solution. I compiled it without errors but it doesn't work as it shoud.
#include <iostream>
#include <string.h>
using namespace std;
class Word
{
private:
char *content;
int length;
public:
Word();
Word(char *);
~Word();
void print_content(void);
int check_character(char);
friend int check_number(Word,Word);
};
Word::Word()
{
}
Word::Word(char *n)
{
length=strlen(n);
content=new char [length];
for(int i=0;i<length;i++)
{
content[i]=n[i];
}
}
Word::~Word()
{
delete content;
}
void Word::print_content(void)
{
for(int i=0;i<length;i++)
{
cout<<""<<content[i];
}
}
int Word::check_character(char a)
{
int position=0;
for(int i=0;i<length;i++)
{
if(content[i]==a)
{
position=i+1;
}
}
if(position>0)
{
return position;
}
else return 0;
}
int check_number(Word n,Word m)
{
int counter_n=0;
int counter_m=0;
for(int i=1;i<n.length;i++)
{
if((n.content[i-1]=='1')&&(n.content[i]=='0'))
{
counter_n=counter_n+1;
}
}
for(int i=1;i<m.length;i++)
{
if((m.content[i-1]=='1')&&(m.content[i]=='0'))
{
counter_m=counter_m+1;
}
}
if(counter_n>counter_m)
{
return counter_n;
}
else if(counter_n<counter_m)
{
return counter_m;
}
else return 0;
}
int main()
{
char characters1[]="qwerty10",*p1,*p2;
char characters2[]="stackoverflow101010";
p1=characters1;
p2=characters2;
Word first(p1);
Word second(p2);
cout<<""<<first.check_character('q')<<endl;
cout<<""<<second.check_character('f')<<endl;
//cout<<""<<check_number(first,second)<<endl;
first.print_content();
second.print_content();
}
Function check_number(first,second) for some reason makes other functions to work incorrectly, if you call it by removing "//" you will see that first.print_content() and second.print_content() don't give us correct result. Or if function first.check_character('r') is first called, second.check_character('j') second called and then check_number(first,second), then two firsly called functions don't work.
What's reason for this strange behaviour?
Word objects are passed by copy to check_number, but you did not define the copy constructor. So default one is used by the compiler and this one copies pointer (char* content). Temporary objects passed to the function are pointing to data created first and second in the main function...upon deletion (temprary objects are deleted after the function is called), they delete the pointers, so first and second objects are pointing to deleted memory. You have undetermined behaviour here, this explains side effects you experienced.
Passing objects by reference to check_number is an easy way to fix your problem. Here is a working code (including many fixes because you did not access arrays correctly):
#include <iostream>
using namespace std;
#include <iostream>
#include <string.h>
using namespace std;
class Word
{
private:
char *content;
int length;
public:
Word();
Word(char *);
~Word();
void print_content(void);
int check_character(char);
friend int check_number(const Word&,const Word&); // changed here
};
Word::Word()
{
}
Word::Word(char *n)
{
length=strlen(n);
content=new char [length];
for(int i=0;i<length;i++)
{
content[i]=n[i]; // changed here
}
}
Word::~Word()
{
delete [] content; // changed here
}
void Word::print_content(void)
{
for(int i=0;i<length;i++)
{
cout<<""<<content[i]; // changed here
}
}
int Word::check_character(char a)
{
int position=0;
for(int i=0;i<length;i++)
{
if(content[i]==a) // changed here
{
position=i+1;
}
}
if(position>0)
{
return position;
}
else return 0;
}
int check_number( const Word& n, const Word& m)// changed here
{
int counter_n=0;
int counter_m=0;
for(int i=1;i<n.length;i++)
{
if((n.content[i-1]=='1')&&(n.content[i]=='0')) // changed here
{
counter_n=counter_n+1;
}
}
for(int i=1;i<m.length;i++)
{
if((m.content[i-1]=='1')&&(m.content[i]=='0')) // changed here
{
counter_m=counter_m+1;
}
}
if(counter_n>counter_m)
{
return counter_n;
}
else if(counter_n<counter_m)
{
return counter_m;
}
else return 0;
}
int main()
{
char characters1[]="qwerty10",*p1,*p2;
char characters2[]="stackoverflow101010";
p1=characters1;
p2=characters2;
Word first(p1);
Word second(p2);
cout<<""<<first.check_character('q')<<endl;
cout<<""<<second.check_character('f')<<endl;
cout<<""<<check_number(first,second)<<endl;
first.print_content();
second.print_content();
}
This outputs:
1
10
3
qwerty10stackoverflow101010
Declaring a copy constructor is another way to fix the problem:
Word( const Wodr& word ) :
length( word.length ),
content( new char[word.length] )
{
memcpy( content, word.content, word.length );
}
That would be less efficient than passing objects by const reference, but would make your code safer (it's good to always declare copy constructor to prevent bug you experienced here).
Finally, if you are lazy, you can also declare the copy constructor as private, to prevent compiler to copy objects, just declare it, don't impelment it:
class Word
{
....
private:
Word( const Word& word ); // this makes argument passed by copy impossible.
};
Then, compiler will not let you call check_number.

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++ Struct defined data passing. Simple answer im sure

I am sure this is a very simple fix and I feel dumb asking it but here it goes.
I need help with a struct and passing info from a gather function to a save or set function, and then passing it again to another function for further use.
Basically, it looks like this to start. I'll just add short snips of the code. All can be provided if you would like to see it.
I right now am just looking for the proper way to pass struct defined data from get.... to set.... functions.
struct printype
{
char dots[8][15];
int unknown15; // can have values of 0..127
string serial11_14; // 8 characters 00000000...99999999
int year8; // without century, 0..99
int month7; // 1..12
int day6; // 1..31
int hour5; // 0..23
int minute2; // 0..59
};
int getunknown15(); // prototypes
int setunknown15(int);
then we have a simple main.
int main()
{
printype pt;
pt.unknown15=getunknown15();
pt.unknown15=setunknown15(12);
pt.serial11_14=getserial11_14();
pt.serial11_14=setserial11_14("12345678");
pt.year8=getyear8();
pt.year8=setyear8(44);
pt.month7=getmonth7();
pt.month7=setmonth7(11);
pt.day6=getday6();
pt.day6=setday6(12);
pt.hour5=gethour5();
pt.hour5=sethour5(12);
pt.minute2=getminute2();
pt.minute2=setminute2(23);
cout <<"-----------------------------------------------------"<<endl;
cout <<" Let's Get Started"<<endl;
cout <<"-----------------------------------------------------"<<endl;
setup(pt.dots); // sets up the array
dpinfo(pt); // prints out the final array
ftarray(pt);
spar(pt.dots);
darray(pt.dots);
}
and finally the get and set array functions.
int getunknown15()
{
printype tem;
cout <<"-----------------------------------------------------"<<endl;
cout <<" Enter the Unkown Variable (0-127): ";
cin >>tem.unknown15;
cout <<"-----------------------------------------------------"<<endl;
return tem.unknown15;
}
next is
int setunknown15(int tem)
{
printype pp;
if (tem>127||tem<0)
{
cout << "Error" << endl;
return 0;
}
else
{
pp.unknown15 = tem;
return pp.unknown15;
}
}
I hope this isn't too much to read and understand
Anyway, I know this has a really simple answer but my brain just isn't working right now.
Edit: As StilesCrisis stated, Send struct as parameter is quiet stupid in this case. better use a const reference.
Well, I am not sure if I understand your question correctly. You can simply send struct to another function as parameter, or as a pointer.
like:
void SetStruct(const printype& var);
printype GetStruct();
Is it what you are looking for?
Please use the following access to the your fields, (by reference):
struct printype *myPtr = new printype;
myPtr->day6 = 43;
When use pointer instead of a normal variable, you should use -> instead . to access your fields.
I know this is kind of old but I thought I should give it a shot, since you are using C++ and it looks like you are trying to use some OO practices (I think), you don't need to start with a struct, even though OO principles can be applied using them as well though not as elegantly.
you can define your class header file as such.
#ifndef PRINTYPE_H
#define PRINTYPE_H
#include <string>
using namespace std;
class printype
{
private: // we always want to declare our member fields private for safety/managements reasons, no one will be able to access them outside.
char dots[8][15];
int unknown15; // can have values of 0..127
string serial11_14; // 8 characters 00000000...99999999
int year8; // without century, 0..99
int month7; // 1..12
int day6; // 1..31
int hour5; // 0..23
int minute2; // 0..59
void init(); // This is the method we use to initialize our starting state.
public: // This is our public methods, how people deal with/get/set our state.
printype(); // This is our default constructor
printype(const printype& print_type); // This our copy constructor
virtual ~printype(); // This is our destructor, its virtual, making safer for inheritance.
// This is our setters/getters
void setUnknown(int unknown);
int getUnknown();
void setYear(int year);
int getYear();
void setMonth(int mont);
int getMonth();
// and well you get the idea, you can add more methods.
};
#endif
and the accompanying class source file with your functions implementation
printype::printype()
{
this->init(); // Initialize all your vatiables, safer to just define a function to this.
}
printype::printype(const printype& orig) // copy constructor
{
this->setUknown(orig.getUnknown());
this->setDay(orig.getDay());
this->setDots(orig.getDots());
// you get the idea ...
}
printype::~printype()
{
// Have anything you need to do before destroying the object.
}
void printype::init()
{
this->setUnknwon(0);
this->setyear(0);
this->setMonth(1);
char dots[8][15] = {'\0'};
this->setDots(dots);
// you get the idea, you want to initialize all your variables since, for the most part they initially hold garbage.
}
void printype::setUnknown(int unknown)
{
if (unknown >= 0 && unknown < 127)
this->unknown15 = unknown;
else
error("Expecting unknown to be between 0 and 127"); // error should probably print the error and/or exit(-1) up to u
}
int printype::setYear(int year)
{
if (year >= 1 && year <= 99)
this->year8 = year;
else
error("Expecting year between 0 and 99"); // you may want to implement an error function!
}
int printype::getYear()
{
return this->year8;
}
void printype::setDots(char dots[8][15])
{
// you may want to do some verifications
memcpy(this->dots, dots, sizeof(dots));
}
void printype::setDots(char **dots) // this is a bit unsafe, use at your own risk.
{
if (dots)
{
unsigned int index = 0;
for (index = 0; index < 8; index++)
if (dots[index])
memcpy(this->dots[index], dots[index], 15);
else
error("dots required pointer ...");
}
else
error("dots required pointer ...");
}
char **getDots() // We will be returning a copy, we don't want the internal state to be affected, from outside, by using reference or pointers.
{
char **dots = new char*[8];
unsigned int index = 0;
for (index = 0; index < 8; index++)
{
dots[index] = new char[15];
memcpy(dots[index], this->dots[index], 15);
}
return dots;
}
// and well you get the idea ...
to use your class
printype *print_type_p = new print_type();
// or
printype pront_type_p();
// use the different public method to update the internal state.
print_type_p->setYear(3);
// or
print_type.setYear(3);
print_type_p->getYear();
// and so on.

C++ Reading Objects from File Error

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 !