Problem z dwoma obiekatami tej samej klasy...

0

Witam,
Po raz kolejny podczas tworzenia programu napotkałem problem. Tym razem jednak nie udaje mi się znaleźć rozwiązania. Wiem że post jest długi ale postarałem się jak najlepiej przedstawić mój problem. A jest on następujący:
Mam Klasę klient która ma odpowiadać za przechowywanie informacji o aktualnie zalogowanych kontach. Plik nagłówkowy wygląda następująco:

 //---------------------------------------------------------------------------

#ifndef KlientH
#define KlientH
//---------------------------------------------------------------------------
#endif
#include <String.h>

class Klient{
private:

	private:
		char* id;
		char *Imie;
		char *Nazwisko;
		int ilosc_kont;
		char *nr_kont;
		int debet;
		int stan;
		int pin;
		int limit;
		char* konto;
	public:
 //-----------------------------Pobieranie
		Klient();
		Klient(char* konto);
		~Klient();
//Pobieranie
		void pobierzKontaKlienta();
		void pobierzPinKonta(char* nrkonta);
		void pobierzNazwiskoKlienta(char* nrkonta);
		void pobierzImieKlienta(char* nrkonta);
		void pobierzLimitKonta(char* nrkonta);
		void pobierzDebetKonta(char* nrkonta);
		void pobierzStanKonta(char* nrkonta);
//Wyswietlanie
		int wyswietlPinKonta();
		char* wyswietlNazwiskoKlienta();
		char* wyswietlImieKlienta();
		int wyswietlLimitKonta();
		int wyswietlDebetKonta();
		int wyswietlStanKonta();
};

Metody oznaczone komentarzem **Pobieranie **odpowiadają za pobranie informacji z Bazy danych, te oznaczone jako **Wyswietlanie **zwracają wartość poszczególnych pól.

Przykładowy kod metody metody:

void Klient::pobierzImieKlienta(char* nrkonta){
	Baza konto;
	konto.connect();
	char* s="select kl.Imie from klienci kl join konta kn on(kl.id=kn.id_klienta) where numer_konta=";
	strcat(s,nrkonta);
	Imie=konto.Zapytanie(s);
//Powiązana metoda Zapytanie
char * Baza::Zapytanie(char* s)
{
	  if (!mysql_query(conn,s)) {
		myRES = mysql_use_result(conn);
			if (myRES) {
				myFields = mysql_fetch_row(myRES);
				return myFields[0];
			}
		mysql_free_result(myRES);
	  }
}
 

A teraz przejdźmy do konkretu, gdy chcę odwołać się przez obiekt klasy do metod wszystko działa fajnie, ale tylko wtedy jeśli mam tylko jeden obiekt. W chwili dodania drugiego obiektu tej samej klasy niestety ale program wywala błąd.
Kod działający:

void __fastcall TForm3::FormShow(TObject *Sender)
{
	Klient *konto = new Klient(nr_konta);
	konto->pobierzImieKlienta(nr_konta);
}

Kod wywalający błąd:

void __fastcall TForm3::FormShow(TObject *Sender)
{

	nr_konta=Form1->ComboBox1->Items->Strings[Form1->ComboBox1->ItemIndex].c_str();
	Klient konto;
	Klient konto2;
	konto.pobierzImieKlienta(nr_konta);
	konto2.pobierzImieKlienta("658237985");

}

Błąd jaki otrzymuje:
Access violation at address 0040CFD2 in module 'Projectl.exe'. Read of
address 00000000.

0

"Read of address 00000000." <- masz wskaźnik, który jest NULLem (ma wartość 0), czyli nie pokazuje na żaden obiekt, a próbujesz odczytać to na co pokazuje...
Rozwiązanie: użyj IDE w którym istnieje debugger, który pokaże gdzie wystąpił błąd, wtedy program się zastopuje i będziesz widział który to wskaźnik jest NULLem.

0

strcat(s,nrkonta);
s nie ma miejsca na dodatkowy strcat.
ostringstream ss(s);
ss<<nrkonta;
konto.Zapytanie(ss.str().c_str());

char * Baza::Zapytanie(const char *s)
{
if (!mysql_query(conn,s)) {
myRES = mysql_use_result(conn);
if (myRES) {
myFields = mysql_fetch_row(myRES);
return myFields[0]; // naprawdę? A mysql_free_result kto zrobi? A jeżeli zrobisz mysql_free_result to zniknie pamięć przydzielona pod myFields[0]
}
mysql_free_result(myRES);
}
}
do zwracania użyj statycznego bufora lub string'a

0

Przebudowałem metodę zapytanie zgodnie z zaleceniem ma ona teraz formę:

char * Baza::Zapytanie(const char *s)
{
          if (!mysql_query(conn,s)) {
                myRES = mysql_use_result(conn);
if (myRES) {
                                myFields = mysql_fetch_row(myRES);
				String tmp(myFields[0]);
				mysql_free_result(myRES);
                                return tmp.c_str();
                        }
	}
}

Jednak gdy próbuje wywołać metodę klasy Klient przerobioną na bazie ostringstream program się sypie...

void Klient::pobierzImieKlienta(char* nrkonta){
	Baza konto;
	konto.connect();
	char* s="select kl.Imie from klienci kl join konta kn on(kl.id=kn.id_klienta) where numer_konta=";
	ostringstream ss(s);
	ss<<nrkonta;
	Form3->Memo1->Lines->Add((String)ss.str().c_str());
	Imie=konto.Zapytanie(ss.str().c_str());
}

Spróbowałem wyświetlić zawartość zmiennej ss jako wynik otrzymałem:
123456789.Imie from klienci kl join konta kn on(kl.id=kn.id_klienta) where numer_konta=

Przy próbie odczytania nr konta 123456789

Próbowałem także zakombinować bardziej

String s="select kl.Imie from klienci kl join konta kn on(kl.id=kn.id_klienta) where numer_konta=";
s+=(String)nrkonta;
konto.Zapytanie(s.c_str());

Jedak bez rezultatu.

Edit:
Odpowiedź okazała się prostsza niż się spodziewałem... Nawet Za prosta... Może brak temu profesjonalizmu ale działa :)

void Klient::pobierzNazwiskoKlienta(const char* nrkonta){
	Baza konto;
	konto.connect();
	string s="select kl.Nazwisko from klienci kl join konta kn on(kl.id=kn.id_klienta) where numer_konta=";
	s+=nrkonta;
	strcpy(Nazwisko, konto.Zapytanie(s.c_str()));
}

void Klient::pobierzImieKlienta(const char* nrkonta){
	Baza konto;
	konto.connect();
	string s="select kl.Imie from klienci kl join konta kn on(kl.id=kn.id_klienta) where numer_konta=";
	s+=nrkonta;
	strcpy(Imie, konto.Zapytanie(s.c_str()));
1

Może i działa... tyle, że bardziej przez przypadek i bym się z tego wcale nie cieszył.
Sposób zwracania wartości z metody Zapytanie to tragedia. Zwracasz wskaźnik do wewnętrznego bufora string, który po wyjściu z funkcji przestaje istnieć - działa to tylko przez przypadek.
Puszczenie na tym co ta metoda zwróci strcpy to jest koszmar, TAK NIE WOLNO ROBIĆ, wskaźnik Nazwisko pokazuje w nicość, piszesz gdzieś po pamięci i nie masz pojęcia gdzie.

Proponuję poczytać czym jest char*, czym jest c-string i jak tego używać, bo piszesz po nie swojej pamięci, mieszasz w miejscach, w których nie wolno.
Przyda się jeszcze coś o zasięgu zmiennych, czasie ich życia i zwracaniu wartości z funkcji.

Po co mieszasz c-stringi z string i String? Programowanie nie polega na losowym klepaniu w klawiaturę i modlitwie, żeby zadziałało.

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