Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[C] usuwanie elementu oraz zapis i odczyt pliku

masterofcs 21 Oct 2008 22:19 3999 8
  • #1
    masterofcs
    Level 12  
    Mam dwa dość spore problemy, z którymi nie mogę się uporać:
    1. Usunąć dany element tablicy dynamicznej. Oto fragment kodu przedstawiający deklarację struktury oraz moje (prawdopodobnie do niczego się nienadające) wypociny:
    Code:

    struct node{
    struct info *pointer;
    struct node *prev;
    struct node *next;
    };

    struct info{
    char imie[15];
    char nazwisko[20];
    char email[20];
    };

    struct node *first;
    struct node *last;
    struct node *current;
    struct node *current2;



    ............................
    int a, j;
    printf ("podaj numer wiersza:\n");
    scanf("%d", &a);
    current = first; //a=a-1
    for(j=0; j<a; j++) //j=a
    {
    current = current -> next;
    }
    free(current -> pointer);
    for(j=i-a; j=0; j--)
    {
    current = current -> next;
    //??
    }
    free(last);
    last = current;


    2. Muszę odczytać z pliku (oraz zapisać do pliku) dane, które oddzielone są od siebie przecinkami. Wygląda to tak:
    Quote:
    imie1, nazwisko1, email1,
    imie2, nazwisko2, email2,
    imie3, nazwisko3, email3,
    i tak dalej...
    Fragmenty kodu odpowiadające za zapis i odczyt z pliku elementów oddzielonych tylko "spacjami":

    zapis:
    Code:

    char p[20];
    fp = fopen("nazwa.txt", "w");
    current = first;
    while (current != NULL)
    {
    fputs (current -> pointer -> imie, fp);
    fputs (" ", fp);
    fputs (current -> pointer -> nazwisko, fp);
    fputs (" ", fp);
    fputs (current -> pointer -> email, fp);
    fputs (" ", fp);
    fputs ("\n", fp);
    current = current -> next;
    }
    fclose(fp);


    odczyt:
    Code:
     char p[20];
    
    fp = fopen ("nazwa.txt", "r");
    current = (struct node*)malloc(sizeof(struct node));
    current -> prev = NULL;
    current -> next = NULL;
    first = current;                                                   
    last = current;
    current -> pointer = (struct info*)malloc(sizeof(struct info));
    strcpy (current -> pointer -> imie, p);
    fscanf(fp, "%s", current -> pointer -> nazwisko);
    fscanf(fp, "%s", current -> pointer -> email);
    while (fscanf(fp, "%s", p) != EOF)
    {
    current = (struct node*)malloc(sizeof(struct node));
    current -> next = NULL;
    current -> prev = last;
    last -> next = current;
    last = current;                                                 
    current -> pointer = (struct info*)malloc(sizeof(struct info));
    strcpy (current -> pointer -> imie, p);
    fscanf(fp, "%s", current -> pointer -> nazwisko);
    fscanf(fp, "%s", current -> pointer -> email);
    }
  • #2
    wiesniak
    Level 31  
    1. Pamiętaj, że jak usuwasz element ze środka listy, to musisz złączyć "rozerwane" części.
    Czyli jak już sobie dojdziesz do elementu, który chcesz usunąć, to zrób coś takiego:
    current->prev->next = current->next; // czyli wskaźnik na następny element w poprzedniku ustawiasz na następny element za tym kasowanym
    current->next->prev = current->prev; // teraz w drugą stronę - wskaźnik na element poprzedni w następniku wskazuje na poprzednika usuwanego
    W ten sposób "wyczepisz" z listy element do skasowania i pozostanie Ci tylko jego usunięcie.

    2. Skąd bierzesz "p" przy tworzeniu pierwszego elementu? Czy czasem nie powinieneś go rówież czytać z pliku zamiast robić strcpy()?

    A nawiasem mówiąc, próbowałeś w środowisku debugować i obserwować, co się dzieje? Szczególnie przy operacjach na pliku.
  • #3
    masterofcs
    Level 12  
    Ad.1. A to, co mam napisane powyżej jest wszystko dobrze? Bo wydaje mi się, że to nie jest poprawnie... :)
    gdzie mam wkleić to, co mi napisałeś? Mógłbyś mi to wkleić do mojego kodu i napisać całość jak ma być? :)
    Ad.2. Z parametrem p jest wszystko ok. Potrzebuję tylko jakiś kod na te "przecinki"... :|
  • #4
    wiesniak
    Level 31  
    1. Gdyby było dobrze, to bym nie pisał :-)
    Pomyśl, to Twój program. Weź kartkę i narysuj sobie tą listę, najlepiej z 5 elementów. Później zaznacz sobie środkowy do usunięcia i zobacz, co musisz zrobić.
    Musisz zmienić wskaźniki poprzednika i następnika tak, by zamiast wskazywać na usuwany element, wskazywały na siebie - dokładnie to robi mój kawałek kodu.
    Pierwsza pętla for przechodzi przez listę do elementu, który chcesz usunąć - ok. Następnie zwalniasz strukturę z danymi - ok, choć IMO lepiej to zrobić później, jak już załatwisz wskaźniki i zostanie czyszczenie. Następnie masz kolejnego fora, który robi coś dziwnego (co to jest w ogóle "i"?).
    Wywal tą pętlę, tam załatw te wskaźniki poprzednika i następnika (nie zmieniając current). Teraz będziesz miał element do usunięcia wskazywany przez current, a w liście nie będzie już do niego odwołań, więc będziesz mógł go usunąć.

    2. Na pewno wszystko jest ok? Z tego kodu, który pokazałeś wynika, że przy pierwszym elemencie p jest puste - pomiędzy fopen() a strcpy() nie widzę żadnego odczytu imienia z pliku do tablicy p.
    Co do przecinków, to skoro imię, nazwisko i mail, to sumarycznie góra 55 znaków, to zrób bufor na 60 znaków, czytaj linię z przecinkami, a później wyodrębniaj poszczególne dane czytając po znaku i testując na obecność przecinka.

    Przy okazji: na Twoim miejscu opakowałbym operacje na liście w jakieś wygodne funkcje - dodajNaPoczatekListy(), dodajNaKoniecListy(), dodajWOkresloneMiejsceListy() itd, podobnie z usuwaniem.
  • #5
    masterofcs
    Level 12  
    1. Druga pętla wynika z tego że, nie wiedziałem iż można "skleić" ze sobą elememty. Po usunięciu chciałem przesuwać dalsze elementy, aby "zapełnić luke". Potem miałem na myśli wyNULLować ostatni element tablicy. "i" to liczba elementów tablicy.

    2. Nie wiem co z tym "p". wszystko działa jak należy. Mógłbyś mi powiedzieć jak zrobić taki bufor i test na obecność przecinka w odczycie i zapisie? :idea:
  • #6
    wiesniak
    Level 31  
    1. Poszukaj sobie informacji o listach dwukierunkowych - to Ci ułatwi sprawę. Aha - Ty nie pracujesz na tablicy - struktura, którą utworzyłeś, to jest lista dwukierunkowa.

    2. Bufor, czyli tablicę - to wiesz jak zrobić. Przy zapisie nie musisz testować przecinka - po prostu go wstawiasz tam, gdzie potrzebujesz.
    Obecnie czytasz wartości wprost do tablic w elementach listy. Zamiast tego robisz jeden odczyt do tablicy pomocniczej (czyli tego bufora), a następnie robisz 3 pętle while kopiujące kolejno imię, nazwisko i mail. Coś w tym stylu:
    Code:
    int i = 0;
    
    while(buf[i]!=',' && buf[i]!='\0')
    {
       current->pointer->imie[i]=buf[i];
       i++;
    }
    i++;   // przechodzimy do elementu za przecinkiem
    while(buf[i]!=',' && buf[i]!='\0')
    {
       current->pointer->nazwisko[i]=buf[i];
       i++;
    }
    i++;
    while(buf[i]!=',' && buf[i]!='\0')
    {
       current->pointer->email[i]=buf[i];
       i++;
    }

    Nie testowałem kodu, ale może zadziała :D Liczy się idea.
  • #7
    masterofcs
    Level 12  
    1. już działa - wielkie dzięki :)
    2. zapis zrobiony :)
    gdzie/zamiast czego mam to wkleić? :D
  • Helpful post
    #8
    wiesniak
    Level 31  
    Pomyśl gdzie :)
    Program działać ma tak, że najpierw czyta calą linię (jeden odczyt, a nie 3 jak w Twoim kodzie), a później ją parsuje (mój przykład) i tak w kółko, aż do końca pliku.

    Przy okazji pytanie: czy koniecznie musisz przecinkami rozdzielać wpisy? Bo jeśli nie, to zostaw spacje, albo zamiast nich wstaw tabulatory - wtedy będziesz mógł normalnie czytać po jednym elemencie, a nie po trzy. Ułatwisz sobie życie i zmniejszysz złożoność obliczeniową tego kawałka kodu (ze spacjami masz wkile() {instrukcje}, a z przecinkami while() {while() {instrukcje}}, czyli z algorytmu o złożoności liniowej masz złożoność kwadratową).
  • #9
    masterofcs
    Level 12  
    program na laborki -> przecinki muszą być :D