Problem z dwoma obiekatami tej samej klasy...

Odpowiedz Nowy wątek
2013-01-14 21:30
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.

Pozostało 580 znaków

2013-01-14 21:50
nobody__
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.

Pozostało 580 znaków

2013-01-14 21:52
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


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.

Pozostało 580 znaków

2013-01-15 00:04
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()));
edytowany 1x, ostatnio: Mexis, 2013-01-15 03:14

Pozostało 580 znaków

2013-01-15 09:07
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.


edytowany 1x, ostatnio: byku_guzio, 2013-01-15 09:09

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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