L.jednokierunowa. Usuwanie pierwszego i zarazem ostatniego elementu.

0

Witam, mam problem z usunięciem jedynego elementu w liście. W funkcji usuwającej mam taki warunek usuwania, gdy pierwszy jest zarazem ostanim elementem, ale nie działa - gdy odpalam program uruchamia się petla nieskończona:

 if(head->next == NULL){
                    free(head);
                    return NULL;
 }
0

a jesteś pewny, że head->next ustawiłeś na nulla?

0

To jest moja funkcja usuwająca. Mój program działa na zasadzie, że musze usuwać n elementów z końca listy. Więc jak usune wszystkie elementy z końca i zostanie tylko jeden element to head->next==NULL jest już chyab ustawione

struct lista* usun(struct lista* head){
       struct lista* tmp=NULL;
       struct lista* tmp1=NULL;
       
       if(head==NULL){
                      printf("Lista juz jest pusta");
                      return NULL;
       }
       
       if(head->next == NULL){
                    free(head);
                    return NULL;
       } else {
              tmp=head;
              tmp1=head;
              tmp=tmp->next;

              while(tmp->next!=NULL){
                     
                    tmp=tmp->next;
                    tmp1=tmp1->next;
              }              
              
              tmp1->next=NULL;
              free(tmp);
              
              return head;
         }
         
}
0
if(head->next == NULL){
                    free(head);
                    return NULL;

Tutaj powinieneś jeszcze head ustawić na NULL.

Reszta wygląda w porządku, a pokaż jeszcze kod gdzie inicjalizujesz listę.

0

Jak wstawiam head=NULL przez free(head) to już nie ma tej nieskończonej pętli, ale nie usuwa tego elementu, a jak wwalam za free(head) to na free(head) robi się znów pętla nieskończona.
Liste tworzę wczytując ją z pliku binarnego. To jest funkcja za to odpowiedzialna:

struct lista* wczytaj_baze(int n)
{   
    
    int i=0;
    struct ksiazka ks;
    FILE *plik;
    struct lista* nowy=NULL;
    struct lista* head=NULL;
    struct lista* ogon=NULL;
     
    if ((plik = fopen("dane.bin", "rb")) == NULL)
    {
        
        printf("Blad otwarcia pliku");
        return NULL;
        
    }       
            
            
            
            fread(&ks, sizeof(ks), 1, plik);
            nowy=(struct lista*)malloc(sizeof(struct lista));
            nowy->next = NULL;
            nowy->ks=ks;
            head=nowy;
            ogon=nowy;
            i++;
            
            
            
            while (fread(&ks, sizeof(ks), 1, plik)==1 && i<n) {
                    nowy=(struct lista*)malloc(sizeof(struct lista));
                    nowy->next = NULL;
                    nowy->ks=ks;
                    ogon->next=nowy;
                    ogon=nowy;
                    i++;
            }
       
      
    
    fclose(plik);
    return head;
    
}
0

Jak wstawiam head=NULL przez free(head) to już nie ma tej nieskończonej pętli, ale nie usuwa tego elementu, a jak wwalam za free(head) to na free(head) robi się znów pętla nieskończona.

Hmm .. po 1 co rozumiesz przez usunięcie elementu?

a po 2 - na funkcji free nie możesz mieć 'pętli nieskończonej' ponieważ to jest tylko jedna funkcja, która sama z siebie nie ma prawa się zapętlić, co najwyżej może wyrzucić jakiś błąd.

0

Przez usunięcie elementu rozumiem zwolnienie zaalokowanej wcześniej dla niego pamięci. Nie wiem jak to możliwe, ale free(head) robi nieskończoną pętle, tzn działanie programu nigdy się nie kończy i jakieś krzaczki ciągle wyskakują. Jak wywalam tą linijke free(head) z kodu to tej pętli nie ma. Ostatniego elementu mi dobrze nie usuwa, bo funkcja wyświetlająca zawartosc listy pokazuje, że ostatni element;/ Tu jest mój cały kod programu:

#include <stdio.h>
#include <stdlib.h>

/* Struktury */

struct ksiazka{
         char tytul[256];
};

struct lista{
        struct lista *next;
        struct ksiazka ks;
};

/* Funcje użyte w programie */
void zapisz(int n);
struct lista* wczytaj_baze(int n);
void wyswietl(struct lista* head);
struct lista* dodaj(struct lista* head);
struct lista* usun(struct lista* head);


int main(int argc, char *argv[])
{
    int n, liczba_ksiazek_do_usuniecia, i=0, liczba_ksiazek_do_dodania;
    struct lista* head=NULL;
   
    printf("Ile ksiazek chcesz pobrac z pliku??\n");
    scanf("%d", &n);
   // zapisz(n);
    if(n<=0){
            head=NULL;
    } else{
           head=wczytaj_baze(n);
      }
    printf("Stan listy po wczytaniu %d ksiazek z pliku: \n", n);
    wyswietl(head);
    
    printf("Ile ksiazek chcesz dolozyc??\n");
    scanf("%d", &liczba_ksiazek_do_dodania);
    while(i<liczba_ksiazek_do_dodania && liczba_ksiazek_do_dodania>0){
    dodaj(head);
    i++;
    }
    i=0;
    printf("Stan listy po dodaniu %d ksiazek: \n", liczba_ksiazek_do_dodania);
    wyswietl(head);
    
    printf("Ile ksiazek chcesz usunac??\n");
    scanf("%d", &liczba_ksiazek_do_usuniecia);
    
    while(i<liczba_ksiazek_do_usuniecia && liczba_ksiazek_do_usuniecia>0){
    usun(head);
    i++;
    }
    i=0;
    printf("Stan listy po usunieciu %d ksiazek: \n", liczba_ksiazek_do_usuniecia);
    wyswietl(head);
    
  
  system("PAUSE");	
  return 0;
}


void zapisz(int n){
      FILE *plik;
      struct ksiazka ks; 
      int i=0;
      plik = fopen("dane.bin","wb");
        system("CLS");
      
      while(i<n){
      printf("\nTytul ksiazki : ");
      scanf("%s",&ks.tytul);
      fwrite(&ks,sizeof(ks),1,plik);
      
      i++;
      }
      fclose(plik);
      printf("\n Zapisano do pliku... \n");
      getch();

      
}


struct lista* wczytaj_baze(int n)
{   
    
    int i=0;
    struct ksiazka ks;
    FILE *plik;
    struct lista* nowy=NULL;
    struct lista* head=NULL;
    struct lista* ogon=NULL;
    
    if(n<=0){
             return NULL;
    }
     
    if ((plik = fopen("dane.bin", "rb")) == NULL)
    {
        
        printf("Blad otwarcia pliku \n");
        return NULL;
        
    }       
            
            
            fread(&ks, sizeof(ks), 1, plik);
            nowy=(struct lista*)malloc(sizeof(struct lista));
            nowy->next = NULL;
            nowy->ks=ks;
            head=nowy;
            ogon=nowy;
            i++;
            
            
            
            while (fread(&ks, sizeof(ks), 1, plik)==1 && i<n) {
                    nowy=(struct lista*)malloc(sizeof(struct lista));
                    nowy->next = NULL;
                    nowy->ks=ks;
                    ogon->next=nowy;
                    ogon=nowy;
                    i++;
            }
       
      
    
    fclose(plik);
    return head;
    
}
void wyswietl(struct lista* head){
    if(head==NULL){
                   printf("Lista jest pusta!! \n");
    } else{
           
           do{
                   printf("%s\n",head->ks.tytul);
                   head=head->next;
           }while(head);

      }
}

struct lista* dodaj(struct lista* head){
       
       char tytul[40];
       struct lista *ogon=head;
       struct lista* nowy=NULL;
       
       //ustawienie ogona na koniec listy
       if(ogon->next != NULL){
                     do{
                              ogon=ogon->next;
                     }while(ogon->next!=NULL);
                     
       }
       printf("Podaj tytul ksiazki: ");
       scanf("%s", tytul);
       
       nowy=(struct lista*)malloc(sizeof(struct lista));
       strcpy(nowy->ks.tytul,tytul);
       nowy->next=NULL;
       ogon->next=nowy;
       ogon=nowy;
       
       return head;
       
}

struct lista* usun(struct lista* head){
       struct lista* tmp=NULL;
       struct lista* tmp1=NULL;
       
       if(head==NULL){
                      printf("Lista juz jest pusta");
                      return NULL;
       }
       
       if(head->next == NULL){
                    head=NULL;
                    free(head); //<--------------------------------------------------to coś powoduje pętle, gdy nie ma head=NULL przed. A head=NULL nie usuwa elementu
                    return head;
       } else {
              tmp=head;
              tmp1=head;
              tmp=tmp->next;

              while(tmp->next!=NULL){
                     
                    tmp=tmp->next;
                    tmp1=tmp1->next;
              }              
              
              tmp1->next=NULL;
              free(tmp);
              
              return head;
         }
         
}
              
              
        
1

Tyle gmatwaniny kiedy wystarczy:

struct lista* usun(struct lista* head)
  {
   struct lista *tmp;
   if(head)
      {
       tmp=head;
       head=tmp->next;
       free(tmp);
      }
   else printf("Lista juz jest pusta");
   return head;
  }
0

Już wiem co źle robiłem. Nie zaaktualniałem stanu wskaźnika na liste w mainie. Tzn. Nie przypisywałem w mainie do head=usun(head) lub head=dodaj(head). Teraz już ładnie śmiga.

Mam jeszcze jedno pytanie, jak zrobić, żeby można było zapisywać tytuły książek dłuższe niż jeden wyraz?? Tzn. Jak chce dodać np tytuł: Harry Potter to dodaje to do listy jako dwa elementy: 1szy: Harry 2gi: POtter.

1

wczytywać fgets-em a nie scanf-em

0

Ale mi chodzi o dodawanie tytułu już po wczytaniu tytułów z plikuu. Fgets jest do odczytywania z pliku, chyba, że coś mi się pokręciło :)
@Edit
Dobra pokręciło mi się, można to robić, ale nie wiem dokładnie jak.
Jak robie coś takiego w funkcji dodającej do listy:

fgets(tytul, 40, stdin);

to dodaje mi pusty element. Z kolei jak coś takiego: fgets(ks.tytul, sizeof(ks), stdin);

 to dodaje mi uśmiechnięta buźke do listy. Jak poprawnie mam użyć fgets'a?

@edit1

Rozwiązałem ten problem pisząc pod sobą dwie instrukcje fgets:
```c
fgets(tytul, 40, stdin);
fgets(tytul, 40, stdin);

Po tym zabiegu dobrze dodaje jeden element. Jak miałem jednego fgets'a to program automatycznie dodawał element do listy - nie dając mi nawet wpisać tytułu, a jak są dwa to mogę wpisać tytuł. Można było jakoś inaczej rozwiązać ten problem??

0

@Edit

Tak teraz wygląda moja funkcja dodająca:

struct lista* dodaj(struct lista* head){
       
       char tytul[40];
       struct ksiazka ks;
       struct lista *ogon=NULL;
       struct lista* nowy=NULL;
       
       
       if(head){
                ogon=head;
                 //ustawienie ogona na koniec listy
                     if(ogon->next != NULL){
                                   do{
                                   ogon=ogon->next;
                                   }while(ogon->next!=NULL);
                     
                      }
       }
       
       
       if(head==NULL){
        printf("\nPodaj tytul ksiazki: "); 
        fgets(tytul, 40, stdin);
        fgets(tytul, 40, stdin);
        nowy=(struct lista*)malloc(sizeof(struct lista));
        strcpy(nowy->ks.tytul,tytul);
        nowy->next=NULL;
        head=nowy;
        ogon=nowy;
       } else {
               printf("\nPodaj tytul ksiazki: ");
               fgets(tytul, 40, stdin);
               fgets(tytul, 40, stdin);
               nowy=(struct lista*)malloc(sizeof(struct lista));
               strcpy(nowy->ks.tytul,tytul);
               nowy->next=NULL;
               ogon->next=nowy;
               ogon=nowy;
         }
       
       return head;
       
}

Podbijam temat, bo nie za bardzo rozumiem dlaczego trzeba było dać pod sobą dwa fgetsy, żeby poprawnie dodać jeden element- ten problem rozwiązałem metodą prób i błędów.

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