I have an error here with my code in strcpy.
I declared name , company , type , color and state as string
void SaveList(void)
{
ofstream pFile;
pFile.open("Car.dat",ios::binary);
if(pFile==NULL)
{
cout<<"Cannot Open File \n updated Data not saved into file\n\n";
exit(0);
}
struct Car_F NF; // structure variable to hold data for file
struct Car *CURR;
for (CURR = HEAD ; CURR != HEAD ; CURR = CURR->forw )
{ // copy record from linked list into file record structure
NF.ID=CURR->ID;
strcpy(NF.name,CURR->name);
strcpy(NF.Company_of_car,CURR ->Company_of_car);
strcpy(NF.type_of_car,CURR ->type_of_car);
strcpy(NF.color_of_car,CURR ->color_of_car);
NF.model_of_car = CURR->model_of_car;
NF.price_of_car = CURR->price_of_car;
strcpy(NF.state_of_car,CURR ->state_of_car);
pFile.write((char*) &NF,sizeof(NF)); // write record into file
}
pFile.close();
}
Can somebody help me out please. I will be really happy
The strcpy function is a C function that operates on char* character arrays (which is what C uses as strings). See: http://www.cplusplus.com/reference/cstring/strcpy/
C++ string objects are completely different, and remove the need for calling C string functions. See here for a list of C++ string member functions: http://www.cplusplus.com/reference/string/string/
The operator= string assignment is what you're after. For a first step in fixing this, I would replace the strcpy(NF.name,CURR->name); with NF.name = CURR->name; (and so on). C++ objects make it look a lot more simpler and natural, through the use of the operator function syntax.
Also, why are you copying the record completely before writing it out? Is that necessary? There are a number of other things that are not ideal with the code, such as casting the struct to a char* to write out. I would suggest studying some example code for iostream to see how that is used to serialise (write out and read in) objects.
Related
I have these large pcap files of market tick data. On average they are 20gb each. The files are divided into packets. Packets are divided into a header and messages. Messages are divided into a header and fields. Fields are divided into a field code and field value.
I am reading the file a character at a time. I have a file reader class that reads the characters and passes the characters by const ref to 4 call back functions, on_packet_delimiter, on_header_char, on_message_delimiter, on_message_char. The message object uses a similar function to construct its fields.
Up to here I've noticed little loss of efficiency as compared to just reading the chars and not doing anything with them.
The part of my code, where I'm processing the message header and extracting the instrument symbol of the message, slows down the process considerable.
void message::add_char(const char& c)
{
if (!message_header_complete) {
if (is_first_char) {
is_first_char = false;
if (is_lower_case(c)) {
first_prefix = c;
} else {
symbol_vector.push_back(c);
}
} else if (is_field_delimiter(c)) {
on_message_header_complete();
on_field_delimiter(c);
} else {
symbol_vector.push_back(c);
}
} else {
// header complete, collect field information
if (is_field_delimiter(c)) {
on_field_delimiter(c);
} else {
fp->add_char(c);
}
}
}
...
void message::on_message_header_complete()
{
message_header_complete = true;
symbol.assign(symbol_vector.begin(),symbol_vector.end());
}
...
In on_message_header_complete() I am feeding the chars to symbol_vector. Once header is complete I convert to string using vector iterator. Is this the most efficient way to do this?
In addition to The Quantum Physicist's answer: std::string should behave quite similar as vector does. Even the 'reserve' function is available in the string class, if you intend to use it for efficiency.
Adding the characters is just as easy as it can get:
std::string s;
char c = 's';
s += c;
You could add the characters directly to your member, and you are fine. But if you want to keep your member clean until the whole string is collected, you still should use a std::string object instead of the vector. You then add the characters to the temporary string and upon completion, you can swap the contents then. No copying, just pointer exchange (and some additional data such as capacity and size...).
How about:
std::string myStr(myVec.begin(), myVec.end());
Although this works, I don't understand why you need to use vectors in the first place. Just use std::string from the beginning, and use myStr.append() to add characters or strings.
Here's an example:
std::string myStr = "abcd";
myStr.append(1,'e');
myStr.append(std::string("fghi"));
//now myStr is "abcdefghi"
I dont understand the mistake I am making.
I tryed alot but I am unable to read my FILE.
Basically I write an structure into a file named 0.txt / 1.txt / 2.txt ... based of account amound.
I realy seached hours to fix my problem but I dont understand how I can fix and why I get the ERROR.
Also I have no problem in complining my code (with dev c++) but when I press on Load Accounts Button I get the ERROR "Segmentation Fault" (using windows 7).
I noticed that the problem is at fread() line in function ladeAccounts().
The name of my Structure is "iAccount".
The variable infoma is as iAccount typed and the "number of accounts existing" typed as int anzahl in newAccount() decides the path.
iAccount looks like this:
struct iAccount
{
string ID;
string password;
int level;
};
This is how I write my STRUCT into the FILE:
void Account::newAccount(int anzahl, string username, string pw, int lvl)
{
iAccount neu;
neu.ID = username;
neu.password = pw;
neu.level = lvl;
ss.str("");
ss<<anzahl;
s = ss.str();
s = "Accounts/"+s+".txt";
f1 = fopen(s.c_str(), "w");
fseek(f1, 0, SEEK_SET);
fwrite(&infoma, sizeof(iAccount), 1, f1);
fclose(f1);
}
This is how I read the File (ERROR APPEARS when I call fread()
void Account::ladeAccount(int nummer)
{
stringstream sa;
iAccount account_geladen;
sa.str("");
sa<<nummer;
s = sa.str();
s = "Accounts/"+s+".txt";
f2 = fopen(s.c_str(), "r");
fseek(f2, 0, SEEK_SET);
fread(&infoma, sizeof(infoma), 1, f2);
fclose(f2);
}
Thank you for your help. I have no clue where my problem is and as I said I am searching for hours.
EDIT:
The file gets opened I tryed it (f2 is true!).
EDIT":
ERRNO = 0 !!!
SEE HERE:
ostringstream Str;
Str << errno;
infoma.ID = Str.str();
Just did this to see the result of errno in my wxtextlabel.
Reason
You are most probably calling fread on a NULL file handle. So you have two problems here:
In your code (you don't check if fread succeeds or returns a NULL value)
Your file can't be opened for some reason (this, you should investigate...)
Explication
fopen (see documentation) can return a NULL handle for different reasons. If you don't check the validity of the handle before calling fread you will have a segmentation fault.
Tips
As you can read in the official documentation I linked above, on most library implementations the errno variable can help you giving the system-specific error code on failure. This could help you debugging your error in opening the file.
Side Issues
Once you solve this bug in our code you will have other issues. As people (notably #Christophe) remarked in other answers, there is a structural problem in your code because you try to serialize/deserialize on your file objects non POD (aka your strings). Since string are complex objects you can't serialize them directly.
The approach of using an array of characters will work correctly, as simple types can be handled the way you coded.
For this reason, you can use the std::string c_str() method to obtain a null terminated array of chars from your string and store it in the file.
The opposite operation is even more straightforward, as you can initialize a std::string simply passing the deserialized array of chars:
std::string str(the_array);
You have a problem because you use fread() to load binary data. But this works only with plain old data (POD) objects.
It uses to give desastrous results with less trivial objects especially if the internals of these manage dynamic memory allocaton and/or pointers like it's the case here with strings.
By the way:
If you read/write binary data, you should really use "rb"/"wb" as mode for fopen(). If you don't you would'nt necessary have a seg.fault, but your data might be incorrect on some systems.
Edit:
Sorry, I didn't read well enough: if it happens right at fread() the reason provided by Alex will certainly help. However I leave this answer because as soon as you've solved your fopen() issue, you might get segmentation errors if you try to work with the object that you've read. If you're not conviced, look at sizeof(iAccount) and compare it to the size your string content.
EDIT
if(f2) is true so I am wrong and file got opened successfull right?
I found out that the file is not opened/the fopen can not handle with the path for example 0.txt .
Also I tryed to enter the path directly without building it (without stringstream and so on). Still I have the problem of the segmentation fault. I checked everything the file exists in the folder Accounts. I have an other file called "Accounts.txt" in the same folder and there I have no problem reading the amound of accounts existing (also using a struct). There I dont even check if the fopen had success but it works anyway I will write the code for the file-open-check later.
The code for the reading/writing into Accounts/Accounts.txt is:
struct init{
int anzahl_1;};
init anzahl;
FILE* f;
static string ss = "Accounts/Accounts.txt";
int account_anzahl1()
{
f = fopen(ss.c_str(), "r");
fread(&anzahl, sizeof(init), 1, f);
fseek(f, 0, SEEK_END);
fclose(f);
return anzahl.anzahl_1;
}
void account_anzahl_plus()
{
anzahl.anzahl_1 = anzahl.anzahl_1 +1;
f = fopen(ss.c_str(), "w");
fwrite(&anzahl, sizeof(init), 1, f);
fclose(f);
}
There I have no problem!
I got some problems in creating my program for mobile using QT C++
When i run it i get this: cannot convert 'std::string' to 'std::string*' in initialization
And theres code for that error:
void rozvrh_b17::pars(string par)
{
data = new std::string*(par);
printf(data->data());
}
//data and par are std::string
//without that new std::string*() it does similiar error
And i ask how to convert std::string to std::string* ??
EDIT:
i made this function to transfer data from one form to another and i need to remember that parameter...
I downvoted you because this question shows no research effort.
string * data = ∥
std::string* is a pointer type. You have a std::string, and it's address is the pointer type you want. This is one of the first principles of using pointers.
What do you really try to do?
If you just want to print the string then this should work:
void rozvrh_b17::pars(string par)
{
printf(par.c_str());
}
If you want to create a copy of string on the heap then you need this:
std::string* data = new std::string(par);
but that doesn't make much sense.
You are trying to assign a string from a pointer to string. In this particular case I see several things.
You don't need a copy at all - simply use par right away
You better make par a const ref: void rozvrh_b17::pars(const string& par)
You should use only string whaen calling new otherwise you create a pointer to string. So do: data = new std::string(par);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Reading from text file until EOF repeats last line
I am writting data to a file using the following code
//temp is class object
fstream f;
f.open ("file", ios::in|ios::out|ios::binary);
for(i=0;i<number_of_employees ;++i)
{
temp.getdata();
f.write( (char*)&temp,sizeof(temp));
}
f.close();
temp is the object of following class
class employee
{
char eno[20];
char ename[20];
char desg[20];
int bpay;
int ded;
public:
void getdata();
void displaydata();
}
But when i write data using this code i find that the last object written to file gets written two times.
my function to read from file is
fstream f;
f.open ("file", ios::in|ios::out|ios::binary);
while(f)
{
f.read((char*)&temp, sizeof(temp));
temp.displaydata();
}
f.close();
following shows my file when it is read till eof
Number :1
Name :seb
Designation:ceo
Basic Pay :1000
Deductions :100
Number :2
Name :sanoj
Designation:cto
Basic Pay :2000
Deductions :400
Number :2
Name :sanoj
Designation:cto
Basic Pay :2000
Deductions :400
What is the cause of this and how can i solve it?
If the problem is repeated output, it's very likely caused by the way you are looping. Please post the exact loop code.
If the loop is based on the data you receive from getdata(), you'll need to look closely at exactly what you input as well. You might not be receiving what you expect.
Of course, without real code, these are almost just guesses.
The reason for your problem is simple: you're not checking whether the
read has succeeded before using the results. The last read encounters
end of file, fails without changing the values in your variables, and
then you display the old values. The correct way to do exactly what
you're trying to do would be:
while ( f.read( reinterpret_cast<char*>( &temp ), sizeof( temp ) ) ) {
temp.displaydata();
}
Exactly what you're trying to do, however, is very fragile, and could
easily break with the next release of the compiler. The fact that your
code needs a reinterpret_cast should be a red flag, indicating that
what you're doing is extremely unportable and implementation dependent.
What you need to do is first, define a binary format (or use one that's
already defined, like XDR), then format your data according to it into a
char buffer (I'd use std::vector<char> for this), and finally use
f.write on this buffer. On reading, it's the reverse: you read a
block of char into a buffer, and then extract the data from it.
std::ostream::write and std::istream::read are not for writing and
reading raw data (which makes no sense anyway); if they were, they'd
take void*. They're for writing and reading pre-formatted data.
Writing an object to a file with write((char*)object, sizeof(object)) is looking for trouble!
Rather write a dedicated write function for the class:
class employee {
...
void write(ostream &out) {
out.write(eno, sizeof(eno));
out.write(ename, sizeof(ename));
out.write(desg, sizeof(desg));
out.write((char*)&bpay, sizeof(bpay));
out.write((char*)&ded, sizeof(ded));
}
void read(istream &in) {
in.read(&eno, sizeof(eno));
in.read(&ename, sizeof(ename));
...
in.read((char*)&bpay, sizeof(bpay));
in.read((char*)&ded, sizeof(ded));
}
}
ostream &operator <<(ostream &out, employee &e) {
e.write(out);
return out;
}
istream &operator >>(istream &in, employee &e) {
e.read(in);
return in;
}
Once you've done that, you can use:
f << temp;
to write your employee record to the file.
But note that even this isn't great, because at least as far as the integers are concerned, we're becoming very platform dependent, ito the size of an int, and ito the endianness of the int.
In this function I am trying to write the information from the linked list to a file
class Employer: public People{
void tryWrite(){
ofstream file("Employer.dat",ios::out|ios::app| ios::binary);
if(file.is_open()){
file<<getFirstName()<<" "<<getLastName()<<" " << companyName<<" "<<position<<" "<<getTelHome()<<" "<<getTelMobile()<<" " <<email<<" "<<getAddress()<< endl;
file.close();
}
}
};
#endif
This is the linked list manipulator for the employer class
At this point in the writeFile function I am trying to traverse through the link list and call the tryWrite function in Employer.h to write to the actual data in the link list to file
class EmployerList
{
private:
Employer *head;//employee pointer(head pointer)
public:
void writeFile(){
Employer *temp = head;
while (temp != NULL)
{
temp->tryWrite();//Employee's display method called here
temp = temp->getNext();
}
}
In this read function I would like to read the data in the following order Name: Jane brown Company's name: Lime Position: clerk Address:
New Kingston Home#: 876-466-8778 Mobile #: 543-455-6344 Email: dumb#yahoo.com
But reading directly from the file the data is Jane brown Lime clerk
New Kingston 876-466-8778 543-455-6344 dumb#yahoo.com
when it gets to the address it will display as: Address: New
instead of: Address: New Kingston
The null spaces is creating the issue and i do not know how to get it
to do what i want
void TestRead(){
ifstream tryRead("em.dat", ios::in|ios::binary);
string Email, cName, pos,fName,lName,addr, tHome,tMobile;
while(tryRead>>fName>>lName>>cName>>pos>>addr>>tHome>>tMobile){
cout<<"Name: "<<fName<<lName<<endl;
cout<<"Comapny's Name: "<<cName<<endl;
cout<<"Position: "<<pos<<endl;
cout<<"Address: "<<addr<<endl;
cout<<"Home#: "<<tHome<<endl;
cout<<"Mobile#: "<<tMobile<<endl;
tryRead.close();
}
}
};
#endif
This is main which populate the linked list with data
#include <iostream>
#include <string>
#include "Employer.h"
#include "EmployerList.h"
using namespace std;
void main()
{
EmployerList em;
em.AddNode("nim#yahoo.com", "LIME", "Manager", "Tashauna", "Simon", "New Kingston", "876-985-8337", "876-405-3536");
em.AddNode("ker#gmail.com", "NOKIA", "CEO", "Keric", "McDonald", "Europe", "0411-789-6548", "985-257-1111");
After the linked list is filled with data the write file function in EmployerList.h is called
em.writeFile();
em.TestRead();
system("pause");
}
I didn't read your code, because its irrelevant. The question is in the title, and that's what I'm answering.
Writing a linked list into a file means writing each member of the linked list into a file. Linked list is a chain of objects that point one to the next one, and when you want to dump it into a file - you just dump each of these objects one after another.
When you need to rebuild your linked list - you read each object from the file, and chain it in a new linked list in the same order (if you saved FIFO - make sure to rebuilt the same, not in reverse). Needless to mention, you should not be saving the pointers and reading them from the file back.
If the question is about something in that enormous chunk of code - you'll have to refine the question and minimize the code.
edit
After you kindly mentioned what the real problem is - then in your tryWrite you're opening the same file over and over again, overwriting whatever was there previously. Obviously, it will leave you with the one last object from the list in the end, because all the previous ones would be overwritten.
You should use ios::out | ios::in | ios::ate or ios::out | ios::app, to seek to the end of the existing data and add, instead of just ios::out.
As far as I can tell without transcribing, compiling and running your code, there isn't anything fundamentally wrong with it. I would have extracted the ofstream out of the tryWrite() function, opened it once in writeFile() and pass it in as an argument, rather than opening and closing the file for each node in the linked list.
You MIGHT have some problems reading the linked list back in because you don't seem to do anything to scan for illegal characters in the data. You are using the space character as a delimiter, so you should be careful to make sure that any fields that you save to the file are first escaped (i.e. that you replace any space characters with some kind of escape sequence). Otherwise, when reading things back in, a wayward space could throw things off badly.
For future reference, if you are having problems with your code, rather than just listing all the code and asking what's wrong with it, you should probably try to at least describe what problems you're running into -- what is the output, where in the code do you think you are doing something wrong, etc.