Block type is valid(pHead->nBlockUse) - zapis listy do pliku

0

Witam
Jestem początkującym programistą dlatego proszę o wyrozumiałość.
Od kilku dni borykam się z problemem zapisania i oczytania listy dwukierunkowej do/z pliku (pisze program na zaliczenie).
Po prostu muszę gdzieś przechować dane gdy zamykam program, jeśli ma ktoś lepszy pomysł to chętnie wysłucham.
Błąd Block type is valid(pHead->nBlockUse) zaznaczyłem w miejscu w którym się pojawia.
Z góry dziękuje za pomoc.
Funkcja odpowiada za zapis listy do pliku:
file.h

 #ifndef file_h
#define file_h
#include<iostream>
#include <fstream>
#include"list.h"

using namespace std;

void save(list<element_cs, customer_data> to_save);
list <element_cs, customer_data> open();


#endif

file.cpp

 #include "file.h"

void save(list<element_cs, customer_data> to_save)
{
	ofstream file_;
	file_.open("data_company.date",  ios::binary | ios::out | ios::trunc);
	if (!file_.good())
	{
		cout << "Nie mozna stworzyc pliku!!!\n";
		getchar();
		
	}
	else
	{
		element_cs *step = to_save.head;
		while (step)
		{
			file_.write(reinterpret_cast <char *>(&step->someone), sizeof(customer_data));
			file_.write(reinterpret_cast <char *>(&step->something), sizeof(article_data));
			file_.write(reinterpret_cast <char *>(&step->i), sizeof(int));
			file_.write(reinterpret_cast <char *>(&step->status), sizeof(int));
			file_.write(reinterpret_cast <char *>(&step->next), sizeof(element_cs));
			step = step->next;

		}
		cout << "Zapisano dane do pliku\n";
	}
	file_.close();
}

list <element_cs, customer_data> open()
{
	list <element_cs, customer_data> bufor;
	ifstream file_;
	file_.open("data_company.date",  ios::binary | ios::in);
	if (!file_.good())
	{
		cout << "Brak pliku!!!\n";
		getchar();
		
	}
	else
	{
		element_cs step;
		while ( step.next != NULL)
		{			
			file_.read(reinterpret_cast <char *>(&step.someone), sizeof(customer_data));
			file_.read(reinterpret_cast <char *>(&step.something), sizeof(article_data));
			file_.read(reinterpret_cast <char *>(&step.i), sizeof(int));
			file_.read(reinterpret_cast <char *>(&step.status), sizeof(int));
			file_.read(reinterpret_cast <char *>(&step.next), sizeof(element_cs));
			bufor.addend(bufor.create_theelement(step));
		}	
	}  //tutaj wywala bład !!!!!!!!!!!!!!!	
	file_.close();	
	return bufor;
}

Błąd powstaje gdzie przy tworzeniu listy wiec dołacze jeszcze kod klasy szablonowej listy dwukierunkowej;

#ifndef list_h
#define list_h

#include<iostream>
#include<string>
#include<vector>
#include "customer_data.h"
#include "company_data.h"
#include "article_data.h"
#include "status_complaint.h"


struct element_cs
{
	element_cs * next, *prev;
	customer_data someone; 
	vector <article_data> something;
	int i=0;//indeks do vectora
	int status = registered;
};
struct element_cm
{
	element_cm * next, *prev;
	company_data someone;
	vector <article_data> something;
	int i = 0;//indeks do vectora
	int status = registered;
};

template< class Typ1, class Typ2 >
class list
{

public:
	Typ1 *head, *tail;
	list();
	~list();
	Typ1* create_element(Typ2  someone_l, article_data something_l);
	Typ1* create_theelement(Typ1 cr);
	void addend(Typ1 *s_element);
	void view_elemnt(Typ1 *s_element);
	
};

template< class Typ1, class Typ2 >
list<Typ1, Typ2>::list()
{
	head = NULL;
	tail = NULL;
}

template< class Typ1, class Typ2 >
list<Typ1, Typ2>::~list()
{
	Typ1 *p;
	while (head)
	{
		p = head->next;
		delete head;
		head = p;
	}
}

template< class Typ1, class Typ2 >
void list<Typ1, Typ2>::addend(Typ1 *s_element)
{
	if ((this->head) == NULL && (this->tail) == NULL)
	{
		this->head = s_element;
		this->tail = s_element;
	}
	else
	{
		this->tail->next = s_element;
		s_element->prev = this->tail;
		s_element->next = NULL;
		this->tail = s_element;
	}

}

template< class Typ1, class Typ2 >
Typ1* list<Typ1, Typ2>::create_element(Typ2 someone_l, article_data something_l)
{
	Typ1 *a = new Typ1;
	a->next = NULL;
	a->prev = NULL;
	a->someone = someone_l;
	a->something=something_l;
	a->i++;
	return a;
}
template< class Typ1, class Typ2 >
Typ1* list<Typ1, Typ2>::create_theelement(Typ1 cr)
{
	Typ1 *a = new Typ1;
	a->next = NULL;
	a->prev = NULL;
	a->someone = cr.someone;
	a->something = cr.something;
	a->i = cr.i;
	a->status = cr.status;
	return a;
}

template< class Typ1, class Typ2 >
void list<Typ1, Typ2>::view_elemnt(Typ1 *s_element)
{
	int j;
	cout << "\nDane reklamacji: \n";
	cout << "Status reklamacji: ";
	view_status(s_element->status);

	s_element->someone.view();

	for (j = 0; j < s_element->i; j++)
	{
		 s_element->something[j].view_art();
	}
}

#endif 
0
struct element_cs
{
	...
	
    vector <article_data> something;
	...
};



element_cs step;
...
	
file_.read(reinterpret_cast <char *>(&step.something), sizeof(article_data)); // (1)

file_.read(reinterpret_cast <char *>(&step.next), sizeof(element_cs)); // (2)
  1. nie możesz zapisywać/odczytywać do/z pliku vectora w ten sposób. Zapewne stąd ten błąd o uszkodzonej stercie.
  2. wskaźniki z pliku czytasz?!
0

1.Usunąłem vector z struktury i zastapiłem go obiektem klasy article_data.
2.Usunąłem zapis wskaźników.
Dalej wyskakuje ten błąd w miejscu w którym zaznaczyłem w pierwszym poście.

0

Więc podaj kod lub zgłoś się na forum wróżbitów.

0

@DN94, vectora usuwać nie musiałeś, wystarczyło zrobić funkcje odpowiedzialne za serializację ów kontenera. Jeśli błąd cały czas występuje, to sprawdź, czy tego typu błędów nie masz z innymi klasami, np. article_data czy company_data.

No i to, co napisał @_13th_Dragon: jak wprowadzasz jakieś zmiany w kodzie, wrzuć je na forum, żeby było wiadomo, w którym miejscu jesteśmy.

0

Wrzucam zmiany wprowadzone w file.cpp i kod klas customer_data oraz article_data :
file.h:

#ifndef file_h
#define file_h
#include<iostream>
#include <fstream>
#include"list.h"

using namespace std;

void save(list<element_cs, customer_data> to_save);
list <element_cs, customer_data> open();


#endif 

file.cpp

 #include "file.h"

void save(list<element_cs, customer_data> to_save)
{
	ofstream file_;
	file_.open("data_company.date",  ios::binary | ios::out | ios::trunc);
	if (!file_.good())
	{
		cout << "Nie mozna stworzyc pliku!!!\n";
		getchar();
		
	}
	else
	{
		element_cs *step = to_save.head;
		while (step)
		{
			file_.write(reinterpret_cast <char *>(&step->someone), sizeof(customer_data));
			file_.write(reinterpret_cast <char *>(&step->something), sizeof(article_data));
			file_.write(reinterpret_cast <char *>(&step->i), sizeof(int));
			file_.write(reinterpret_cast <char *>(&step->status), sizeof(int));
			step = step->next;

		}
		cout << "Zapisano dane do pliku\n";
	}
	file_.close();
}

list <element_cs, customer_data> open()
{
	list <element_cs, customer_data> bufor;
	ifstream file_;
	file_.open("data_company.date", ios::binary  | ios::in);
	if (!file_.good())
	{
		cout << "Brak pliku!!!\n";
		getchar();		
	}
	else
	{
		element_cs step;
		while (!file_.eof())
		{			
			file_.read(reinterpret_cast <char *>(&step.someone), sizeof(customer_data));
			file_.read(reinterpret_cast <char *>(&step.something), sizeof(article_data));
			file_.read(reinterpret_cast <char *>(&step.i), sizeof(int));
			file_.read(reinterpret_cast <char *>(&step.status), sizeof(int));
			bufor.addend(bufor.create_theelement(step));
		}		
	} // tutaj wywala błąd Block type is valid
	file_.close();	
	return bufor;
}

Klasa szablonowa listy
list.h:

#ifndef list_h
#define list_h

#include<iostream>
#include<string>

#include "customer_data.h"
#include "company_data.h"
#include "article_data.h"
#include "status_complaint.h"
#define MAX_TAB  5

struct element_cs
{
	element_cs *next, *prev;
	customer_data someone;
	article_data something;//[MAX_TAB]; // Usunąłem vector z struktury i zastapiłem go obiektem klasy article_data.
	int i=0;//indeks do vectora
	int status = registered;
};
struct element_cm
{
	element_cm * next, *prev;
	company_data someone;
	article_data something;//[MAX_TAB];
	int i = 0;//indeks do vectora
	int status = registered;
};

template< class Typ1, class Typ2 >
class list
{

public:
	Typ1 *head, *tail;
	list();
	~list();
	Typ1* create_element(Typ2  someone_l, article_data something_l);
	Typ1* create_theelement(Typ1 cr);
	void addend(Typ1 *s_element);
	void view_elemnt(Typ1 *s_element);
	Typ1* look_for(Typ2 who);
	
};

template< class Typ1, class Typ2 >
list<Typ1, Typ2>::list()
{
	head = NULL;
	tail = NULL;
}

template< class Typ1, class Typ2 >
list<Typ1, Typ2>::~list()
{
	Typ1 *p;
	while (head)
	{
		p = head->next;
		delete head;
		head = p;
	}
}

template< class Typ1, class Typ2 >
void list<Typ1, Typ2>::addend(Typ1 *s_element)
{
	if ((this->head) == NULL && (this->tail) == NULL)
	{
		this->head = s_element;
		this->tail = s_element;
	}
	else
	{
		this->tail->next = s_element;
		s_element->prev = this->tail;
		s_element->next = NULL;
		this->tail = s_element;
	}

}

template< class Typ1, class Typ2 >
Typ1* list<Typ1, Typ2>::create_element(Typ2 someone_l, article_data something_l)
{
	Typ1 *a = new Typ1;
	a->next = NULL;
	a->prev = NULL;
	a->someone = someone_l;
	a->something=something_l;
	a->i++;
	return a;
}
template< class Typ1, class Typ2 >
Typ1* list<Typ1, Typ2>::create_theelement(Typ1 cr)
{
	Typ1 *a = new Typ1;
	a->next = NULL;
	a->prev = NULL;
	a->someone = cr.someone;
	a->something = cr.something;
	a->i = cr.i;
	a->status = cr.status;
	return a;
}

template< class Typ1, class Typ2 >
void list<Typ1, Typ2>::view_elemnt(Typ1 *s_element)
{
	int j;
	cout << "\nDane reklamacji: \n";
	cout << "Status reklamacji: ";
	view_status(s_element->status);

	s_element->someone.view();

	for (j = 0; j < s_element->i; j++)
	{
		s_element->something.view_art();
	}
}

template< class Typ1, class Typ2 >
Typ1* list<Typ1, Typ2>::look_for(Typ2 who)
{
	Typ1 *f = NULL;
	Typ1 *searcher = this->head;
	bool found = false;
	while ((searcher) != NULL && found == false)
	{
		if (searcher->someone == who)
		{
			found = true;
			f = searcher;
		}
		searcher = searcher->next;
	}
	return f;
}
#endif 

klasa article_data:
article_data.h:

#ifndef article_data_h
#define article_data_h

#include"date.h"
#include<string>
#include<iostream>
using namespace std;


class article_data //klasa reprezentujaca reklamowany artykuł, produkt
{
public:
	article_data();
	article_data(string article_name_c, string serial_number_c, string reciept_number_c, date when_buy_c, string defect_info_c, string service_info_c);
	~article_data();
	void view_art(); 
	bool operator==(const article_data &_article_);

private:
	string article_name; 
	string serial_number; 
	string reciept_number;
	date when_buy; 
	string defect_info; 
	string service_info; 
};


#endif 

article_data.cpp:

#include "article_data.h"


article_data::article_data()
{
}


article_data::~article_data()
{
}

article_data::article_data(string article_name_c, string serial_number_c, string reciept_number_c, date when_buy_c, string defect_info_c, string service_info_c)
{
	article_name = article_name_c;
	serial_number = serial_number_c;
	reciept_number = reciept_number_c;
	when_buy = when_buy_c;
	defect_info = defect_info_c;
	service_info = service_info_c;
	
}
void article_data::view_art()
{
	cout << "Dane sprzetu: \n";
	cout << "Artykul reklamowany: " << this->article_name << endl;
	cout << "Numer seryjny: " << this->serial_number << endl;
	cout << "Numer dokumentu zakupu: " << this->reciept_number << endl;
	cout << "Data zakupu: ";
	this-> when_buy.view_date();
	cout << "Powod reklamacji: " << this->defect_info << endl;
	cout << "Informacja od serwisanta: " << this->service_info << endl;

}
bool  article_data::operator==(const article_data &_article_)
{
	if ((this->article_name == _article_.article_name) && (this->serial_number == _article_.serial_number))
		return true;
	else
		return false;
} 

Klasa customer_data
customer_data.h

#ifndef customer_data_h
#define customer_data_h

#include<iostream>
#include<string>
using namespace std;


class customer_data 
{
public:
	string name; 
	string surname; 
	string address; 
	string e_mail; 
	string phone_nr; 
	customer_data();
	customer_data(string name_c, string surname_c, string address_c, string e_mail_c, string phone_nr_c);
	~customer_data();
	void view();
	bool operator==(const customer_data &_client_);
	
};

#endif 

customer_data.cpp:

#include "customer_data.h"


customer_data::customer_data()
{

}

customer_data::~customer_data()
{
}

customer_data::customer_data(string name_c, string surname_c, string address_c, string e_mail_c, string phone_nr_c)
{
	name = name_c;
	surname = surname_c;
	address = address_c;
	e_mail = e_mail_c;
	phone_nr = phone_nr_c;
}
void customer_data::view()
{
	cout << "Dane klienta: \n";
	cout << "Imie: " << this->name << endl;
	cout << "Nazwisko: " << this->surname << endl;
	cout << "Adres: " << this->address << endl;
	cout << "E-mail: " << this->e_mail << endl;
	cout << "Numer telefonu: " << this->phone_nr << endl;
}
bool  customer_data::operator==(const customer_data &_article_)
{
	if ((this->name == _article_.name) && (this->surname == _article_.surname) && (this->phone_nr == _article_.phone_nr) && (this->e_mail == _article_.e_mail))
		return true;
	else
		return false;
} 
0

Powyżej wrzuciłem zmiany które zrobiłem w kodzie. Jeśli ma ktoś lepszą propozycje jak przechować dane na czas niedziałania programu to chętnie z nich skorzystam.

1

Tak jak myślałem. Klasy customer_data i article_data zawierają std::stringi, dlatego nie mogą być, podobnie jak vector, zapisywane/odczytywane tak, jakby to był zwykły kawałek pamięci.

Tu masz przykład tego, jak to powinno wyglądać poprawnie dla vector<article_data>:

ostream& serialize_string(ostream &os, const std::string &s)
{
	unsigned n = s.size();
	return os.write((char*)&n, sizeof(n)).write(s.c_str(), n);
}

istream& deserialize_string(istream &is, std::string &s)
{
	char b[256];
	unsigned n;
	
	is.read((char*)&n, sizeof(n));

	while(n > 0  && is.read(b, std::min<unsigned>(n, 256))
	{
		s.append(b, is.gcount());
		n -= is.gcount();
	}
	
	return is;
}


class article_data 
{
public:
	...

	ostream& serialize(ostream &os) const
	{
		serialize_string(os, article_name);
		serialize_string(os, serial_number);
		serialize_string(os, reciept_number);
		os.write((char*)&when_buy, sizeof(date)); // zakładam, że 'date' to typ prosty
		serialize_string(os, defect_info);
		serialize_string(os, service_info);
		return os;
	}
	
	istream& deserialize(istream &is)
	{
		deserialize_string(is, article_name);
		deserialize_string(is, serial_number);
		deserialize_string(is, reciept_number);
		is.read((char*)&when_buy, sizeof(date)); // zakładam, że 'date' to typ prosty
		deserialize_string(is, defect_info);
		deserialize_string(is, service_info);
		return is;
	}

	
private:
    string article_name; 
    string serial_number; 
    string reciept_number;
    date when_buy; 
    string defect_info; 
    string service_info; 
};

/*** przykład zapisu vectora z obiektami 'article_data' ***/

vector <article_data> something;
ofstream os(...);

unsigned n = something.size();
os.write((char*)&n, sizeof(n)); // zapisujemy ilość elementów...

for(int i = 0; i < n; ++i)
	something[i].serialize(os); // ... i same elementy

// podumaj nad odczytem :)

p.s. pisane z palucha, nie testowane, więc coś może nie działać.

0

Mam jeszcze prośbę możesz opisać działanie pętli i operacji w niej zawartych.

 while(n > 0  && is.read(b, std::min<unsigned>(n, 256))) 

z deserialize_string
gdyż kompilator nie ma zdefiniowanego

 std::min<unsigned>(n, 256) 
1
#include <algorithm> 

Dokumentacja Twoim przyjacielem :)

Jeśli chodzi o pętle, to czyta ona n znaków ze strumienia. Mógłbym czytać po znaku/bajcie i dodawać do stringa, ale wydaje mi się to mało eleganckie rozwiązanie. Dlatego użyłem bufora, żeby od razu wczytać cały tekst, jeśli jest krótszy niż 256, lub czytać partiami po 256 bajtów/znaków/whatever.

0

Dziękuje za pomoc, zaczynam dopiero programować więc wybacz głupie pytania.

1 użytkowników online, w tym zalogowanych: 0, gości: 1