Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Przesuwanie wskaźnika roboczego w liście dwukierunkowej [ANSI C]

Kieleczek 03 Kwi 2011 14:19 1487 6
  • #1 03 Kwi 2011 14:19
    Kieleczek
    Poziom 14  

    Witam, mam za zadanie napisać jak w temacie funkcje wykonujące kolejno następujące czynności w liście DWUKIERUNKOWEJ:
    - wyświetlenie aktualnej wartości wskaźnika roboczego
    - przesunięcie wsk. roboczego w przód
    - przesunięcie wsk. roboczego w tył

    Problemem jest to że nie wiem jak ma być zapamiętywana aktualna pozycja aby możliwe było przesuwanie tego wskaźnika :/

    Mam poza tym w programie funkcje dodawania elementu do listy, usuwania elementu o danej wartości, kasowania listy. Czy do każdej z tej funkcji muszę osobno "dopasowywać" ten wskaźnik roboczy?

    Poniżej podaje funkcje na dodawanie elementu do listy i moją próbę napisania funkcji na przesuwanie/wyświetlanie wskaźnika:

    Ciało głowne programu zawiera także:

    Code:
    typedef struct element {
    
      struct element *next, *prev;
      float val;
    } el_listy;

    el_listy *head=NULL, *tail=NULL, *temp;
    head->next = NULL;
    temp = head;


    Funkcja dodawania elementu na koniec listy:
    Code:
    void dodaj_do_listy (el_listy *glowa, el_listy *ogon, el_listy *roboczy, float liczba)
    
    {
      el_listy *wsk=glowa, *wsk2=ogon, *wsk3=roboczy, *nowy;
      wsk3=wsk;
      while (wsk->next != NULL)
        {
        wsk = wsk->next;
        }
      nowy = (el_listy *) malloc (sizeof(el_listy));
      nowy->val = liczba;
      nowy->prev = wsk;
      nowy->next = wsk2;
      wsk->next = nowy;
    }


    Code:
    Funkcje kolejno na wyświetlanie aktualnej pozycji wsk. roboczego/przesuwanie go w przód:
    
    void pozycja_wskaznika(el_listy *roboczy)
    {
    el_listy *wsk3=roboczy;     
    printf("Aktualna pozycja wskaznika roboczego: %0.2f",wsk3->val);     
    }


    Code:
    void do_przodu(el_listy *glowa, el_listy *roboczy)
    
    {
    el_listy *wsk=glowa, *wsk3=roboczy;
    wsk3=wsk3->next;
    printf("Aktualna pozycja wskaznika roboczego: %0.2f",wsk3->val);     
    }


    Oczywiście funkcja na przesuwanie wskaźnika nie działa tak jak trzeba bo wyświetla ona tylko pojedyncze przesunięcie z "głowy" na następny element ale w tym momencie zawsze wykonuje to samo tzn. nie przesuwa dalej.

    Nie bardzo też rozumiem ideę "ogona" listy - o ile głowa był to fikcyjny element pomagający w poruszaniu się po liście to ogon też ma być taki? Ma być to następny (może pusty) element po ostatnim elemencie listy? W jaki sposób służy on w poruszaniu się w tył?
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0 6
  • #2 03 Kwi 2011 21:58
    redie
    Poziom 15  

    Zarówno "głowa" jak i "ogon" nie są fikcyjnymi elementami - są to wskaźniki na listę a ich funkcją jest wskazywanie odpowiednio początku listy i końca listy. Do poruszania się po liście wykorzystuje się wskaźniki "robocze" (tymczasowe).

    Załóżmy, że mój tymczasowy wskaźnik to tmp - oto jak się nim poruszać po liście:

    Code:
    // do przodu
    
    tmp = tmp->next;

    // do tyłu
    tmp = tmp->prev;


    Widzę, że w Twoich funkcjach tworzysz sobie lokalne zmienne, którym przypisujesz wartości argumentów. Wezmę pod uwagę tę ostatnią funkcję czyli do_przodu.
    Stworzyłeś tam zmienną wsk3 i przypisałeś jej wartość zmiennej roboczy - w jakim celu? Skoro zmienna roboczy jest lokalna i nawet po przypisaniu jej innej wartości nie wpłynie ona na nic.
    Jeśli chcesz wykonać poprawny ruch do przodu to powinieneś móc zmieniać wartość wskaźnika roboczy w tej funkcji. A aby to zrobić musisz wysłać do funkcji wskaźnik na wskaźnik (bo w ANSI C nie ma chyba referencji).
    Wtedy taka funkcja będzie wyglądała jakoś tak:
    Code:
    void do_przodu( el_listy **roboczy )
    
    {
      *roboczy = (*roboczy)->next;
      printf("Aktualna pozycja wskaznika roboczego: %0.2f",(*roboczy)->val);     
    }

    0
  • #3 04 Kwi 2011 18:57
    Kieleczek
    Poziom 14  

    Ok, tylko że jak próbuję dać w tej funkcji wskaźnik na wskaźnik jak podałeś to otrzymuje błąd

    Code:
    cannot convert `el_listy*' to `el_listy**' for argument `1' to `void do_przodu(el_listy**)'


    i nie chce się skompilować :/

    Jeszcze pytanie co do ogona- ma on wskazywać na następny (pusty) element listy o wartości NULL a sam być ostatnim elementem listy (zawierającym jakąś wartość)??

    0
  • #4 04 Kwi 2011 19:13
    redie
    Poziom 15  

    Trzeba podać wskaźnik na twój wskaźnik, czyli

    Code:
    &el_listy


    Ogon ma wskazywać zawsze ostatni element listy. Bez względu na to ile jest elementów on zawsze pokazuje ten ostatni - czyli ten w którym pole next jest równe NULL.

    Ogon może mieć wartość NULL tylko i wyłącznie wtedy gdy lista jest pusta.
    Wyobraź sobie że przed Tobą stoi skład 5 wagonów połączonych ze sobą, twoja prawa ręka to "głowa" kolejki, a lewa ręka to "ogon" kolejki. Mają one za zadanie wskazywać początek i koniec kolejki, więc wystarczy że wskażesz palcem pprawej ręki na pierwszy wagon, a palcem lewej ręki na ostatni wagon.
    Podczas pisania obsługi kolejek warto użyć kartki i długopisu - o wiele łatwiej jest to zwizualizować.

    0
  • #5 04 Kwi 2011 20:13
    Kieleczek
    Poziom 14  

    Ok rozumiem już ideę ogona. Mam jeszcze jedno pytanko: ostatnią funkcją którą mam napisać jest dodawanie elementu za wskaźnikiem roboczym. Napisałem taką funkcję:

    Code:
    void dodaj_za_wskaznikiem(el_listy **roboczy, float liczba)
    
    {
      el_listy *nowy;
      nowy = (el_listy *) malloc (sizeof(el_listy));
      nowy->val = liczba;
      nowy->prev = *roboczy;
      nowy->next = (*roboczy)->next;
      (*roboczy)->next = nowy;
    }


    Jednak np. przy próbie usunięcia dodanego za tym wskaźnikiem elemntu program go nie widzi. Jak dodać go aby rzeczywiście znalazł się w liście?

    0
  • Pomocny post
    #6 04 Kwi 2011 20:29
    redie
    Poziom 15  

    W tej funkcji akurat lepiej nie używać wskaźnika na wskaźnik roboczy :)
    ale widzę że coraz lepiej Ci idzie. Pozwolę sobie poprawić tę funkcję dodając linijkę którą zgubiłeś przy wzajemnym wskazywaniu elementów oraz warunki zabezpieczające.

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #7 04 Kwi 2011 21:50
    Kieleczek
    Poziom 14  

    Ok przerobiłem tą funkcję tylko że moje pozostałe funkcje (wypisywanie do pliku, usuwanie elementów listy, kasowanie listy itd.) nadal nie widzą tego elementu dodanego za roboczym, więc jeśli dobrze rozumiem to każdą z nich muszę osobno dostosunkować do nowego elementu? Bo element dodany za roboczym zachowuje się trochę u mnie jak widmo o_O

    EDIT: ok już sobie poradziłem, po prostu musiałem lekko zmodyfikować funkcje usuwające ;) nie działa jeszcze zbyt dobrze po skasowaniu listy (trochę dziwne rzeczy wskazuje wskaźnik) ale myśle że na razie ujdzie ;)

    Dzięki za pomoc, przetestuje program i w razie czego jeszcze napiszę :)
    Pozdrawiam

    0