Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailem C++ - Spojový seznam - nefunkční Find() a problém s výjimkami

Tak, po frontě jsem tu zas, a se seznamem :D Věc se má tak, že mi z nějakého důvodu nefunguje fce Find, problém dělá přiřazení node=node->next, kde se do node přiřadí 0, ale netuším proč - předpokládal jsem, že když na začátku fce do node přiřadím first, budu moct manipulovat přes node i s nexty...

Tady je kód: mafpzl35-18993

A ohledně výjimek... Pokud mám třeba fci First, která vrací data z hlavy, tak musím ošetřit situaci, kdy je hlava NULL. Normálně jsem to řešil vracením "nepravděpodobné hodnoty", třeba -1, ale to není ok, protože pokud by v hlavě bylo uložené totéž číslo, je s tím problém... Proto jsem chtěl použít nějakou výjimku, která by mi umožnila nevracet nic a vypsat na obrazovku krátkou hlášku o chybě. Bohužel, fprintf(stderr, error) vypíše hlášku, ale za ni ještě počet vytištěných znaků, což mi ve výpisu vadí. Zkusil jsem tedy try-catch, ale tam zase dochází k okamžitému ukončení programu po vytištěné hlášce, popř. to vrací 0 - co s tím? Kód Firstu s výjimkou je zde:

int List::First(){
    try{
        if(!first){
            throw new ListEmptyError();
        }else{
            return first->data;
        }

    }catch(...){
        cout <<  endl;
    }
}

Opět moc díky za rady, snad už mých dotazů bude postupně ubývat :D

Předmět Autor Datum
V tom find ziaden problem neni, ked ti to tam priradi NULL tak si si to blbo naspojkoval pri vytvara…
MM.. 04.06.2013 14:25
MM..
T.j. inymi slovami napisane - ak vynimku generujes vo funkcii Neco(), tak try-catch ma byt tam kde s…
MM.. 04.06.2013 14:35
MM..
Ale kukam ze ty to try - catch mas dobre (vyvolanie exception je medzi try a catch, nemusi to byt nu…
MM.. 04.06.2013 14:52
MM..
Co sa tyka toho spojkovania (Add_on_First) tam vidim zatial problem v tomto if(last == NULL){ last =…
MM.. 04.06.2013 15:38
MM..
A v tom else je blbo: first->prev = first; ma byt first->prev = node; ale to by tiez nemalo robit pr…
MM.. 04.06.2013 15:48
MM..
Ok, Add_First jsem přepsal takhle: void List::Add_on_first(int data){ item *node = new item; //vytv…
Katsushiro 04.06.2013 15:52
Katsushiro
Este tam vidim jeden potencialny problem a to ze ak pri mazani prvku vymazes posledny prvok tak nena…
MM.. 04.06.2013 15:54
MM..
Tak, last jsem ošetřil, teď koukám na ten try-catch. Povedlo se mi to vyřešit takto: Definice fce:…
Katsushiro 04.06.2013 18:52
Katsushiro
A co ma ta funkce "elegantene" urobit ked je list prazdny? Ma ti zatelefonovat ze kam ma skocit? Tym…
MM.. 05.06.2013 11:10
MM..
Ked ma fcia vracat hodnotu tak musi vratit hodnotu, ked ziadnu nema tak musi skocit mimo funkci. Ina… poslední
MM.. 05.06.2013 11:37
MM..
No, objevil se další problém, který jsem nečekal ani já :D Vytvořil jsem funkci Del_last, která by m…
Katsushiro 05.06.2013 11:05
Katsushiro
necital som cely program ale ked urobis last = last->prev; tak nemozes vediet ze ci ten last teraz n…
MM.. 05.06.2013 11:19
MM..

V tom find ziaden problem neni, ked ti to tam priradi NULL tak si si to blbo naspojkoval pri vytvarani. Pouzi debugger daj si tam breakpoint a pozri si tie datove struktury ze co v nich je.

fprintf(stderr, error) vypíše hlášku, ale za ni ještě počet vytištěných znaků

coze? Mozes sem dat nejaky konkretny priklad kodu?

Co sa tyka vynimiek tak to musis najprv trochu pochopit ze co to je a preco to vobec existuje.
Priklad: mam program
UholVystrelu = NajdiPaducha();
Strielaj(UholVystrelu);

V takom programe ak napr. fcia NajdiPaducha() nenajdi nikoho tak sa proste nesmie vratit inac by program strielal nieklam doprdele kde vobec strielat nema. T.j. program NEMOZE pokracovat. Samozrejme si si mohol tam dat navratovu hodnotu a testovat ju, ale to je nepohodlne ak je vela volani ktore mozu vyvolat stejnu vynimku, napr. pri diskovych operaciach apod. nebudem predsa za kazdou operaciou testovat nejake hodnoty. Takze si to try-catch urobim tam kde volam tych vela funkcii a akonahle nastane vynimka tak sa to NEvrati z funkcie ale skace rovno na catch. Ak neexistuje catch pred volanim fcie tak to ukonci program (nemozes predsa strielat a volanie funkcie NajdiPaducha() neni uzavrete v try-catch takze nema kam inam skocit, len ukoncit program.
//edit: deletol som zbytocny prikald

Ale kukam ze ty to try - catch mas dobre (vyvolanie exception je medzi try a catch, nemusi to byt nutne vo funkcii takze to mas OK) takze mas najskor blbo to catch nadefinovane (nechyta to tu konkretnu exception - to sa da selektovat ze co ma catch chytat a co ne.)

P.S. aha uz to vidim. Skoci to to do catch a potom to pokracuje dalej - a jaku hodnotu potom vratis? Nejake null alebo nahodne a potom jasne ze program ma problem. Normalne sa to robi tak jak som pisal v prvom prispevku, try-catch sa robi u volania funkcie, aby si po vyvolani vynimky nemusel vracat ziadnu hodnotu a aby to skocilo tam na catch. ked to urobis len vo fcii tak si chytil vynimku uz vo fcii (skocilo ti to na catch) ale potom to normalne pokracuje (vynimku si osetril v catch) takze stale musis vratit nejaku hodnotu z tej funkcie.

Co sa tyka toho spojkovania (Add_on_First) tam vidim zatial problem v tomto
if(last == NULL){
last = first;
last->next = first->next;
last->prev = first->prev;
}
konkretne to
last->next = first->next;
last->prev = first->prev;
je nezmysel pretoze last a first ukazuje na stejnu adresu takze robis vlastne neco ako X=X a Y=Y. Ale neni to chyba, len zbytocnost.

Ok, Add_First jsem přepsal takhle:

void List::Add_on_first(int data){
    item *node = new item; //vytvorim objekt

    //inicializuji objekt
    node->data = data;
    node->next = NULL;
    node->prev = NULL;

    if(first == NULL){
        first = node;
        first->next = NULL;
        first->prev = NULL;

        if(last == NULL){
            last = first;
        }

    }else{
        item *temp; //pro provazani noveho a byvaleho "first"
        temp = first;

        first->prev = node;

        first = first->prev;
        first->next = temp;
        first->prev = NULL;

    }
}

Vypadá to, že Find už funguje - jdu mrknout na try-catch :D

Edit: Kontroluješ rychleji, než já stíhám přemýšlet :D

Tak, last jsem ošetřil, teď koukám na ten try-catch. Povedlo se mi to vyřešit takto:

Definice fce:

class ListEmptyError{
public:
    ListEmptyError(){
        cout << "LEE!";
    }
};

int List::First(){
    if(first){
        return first->data;
    }

    throw ListEmptyError();
};

Volání fce v mainu:

    try{
        cout << a.First() << endl; //LEE
    }catch(...){
        cout << endl;
    }

Takhle to funguje, jak bych chtěl, ale napadá mě, jestli by to nešlo řešit nějak elegantněji, ideálně už v rámci funkce?

Ked ma fcia vracat hodnotu tak musi vratit hodnotu, ked ziadnu nema tak musi skocit mimo funkci.
Inac sa to da len tak ze si zadefinujes funkci tak ze nevraca hodotu ale nejaky status a hodotu bude plnit do nejakej adresy, napr.

BOOL DajData(int* pInt)
{
 if(mam_data)
 {
  *pInt=data;
  return TRUE
 }
 else
  return FALSE;
}

main()
{
 int i;
 if(DajData(&i))
   cout << i;
 else
   cout << "nemam data"
}

k tomu ale potom nepotrebujes ziadne exceptions, a je to komplikovane testovat to furt po kazdom volani fcie, viz moja uplne prva odpoved. Do try-catch bloku mozes uzavret aj 10volani fcie a nasledne urobit osetrenie chyby len na jednom mieste, tym padom zdrojak neni preplneny ifmi a program je prehladnejsi.
P.S> nemaju vas to nahodou ucit v skole? :D Zdravim neschopnych pedagogov :)

No, objevil se další problém, který jsem nečekal ani já :D Vytvořil jsem funkci Del_last, která by měla mazat poslední prvek seznamu, a tedy i fungovat hodně podobně jako Del_first... Problém je, že pokud ji zavolám, a seznam je pak prázdný, následující find při "throw" nahlásí Segmentation fault. Fakt už nevím proč, kód Del_last vypadá takto:

void List::Del_last(){
    if(last == NULL){
        cout << "Seznam je prazdny!" << endl;
    }else{
        item *del;

        del = last;

        last = last->prev;
        last->next = NULL;

        delete del;

        if(last == NULL){
            first = NULL;
        }
    }
}

Celý kód pak vypadá takhle: ktblte55-19005

Opět moc díky za rady, je to nějak náročné :D

necital som cely program ale ked urobis
last = last->prev;
tak nemozes vediet ze ci ten last teraz neni NULL takze nemozes na tu adresu na ktoru ukazuje last pristupovat len tak
last->next = NULL;
ale musis najprv otestovat ci last neni null a pristupovat na tu adresu mozes len ak last neni NULL. Ak je null a chces na tu adresu cosi zapisovat tak "program proved neplatnou operaci". T.j. nemozes menit next u neexistujuceho prvku.
A neni to narocne :)

Zpět do poradny Odpovědět na původní otázku Nahoru