Nie jesteś zalogowany.
Jeśli nie posiadasz konta, zarejestruj je już teraz! Pozwoli Ci ono w pełni korzystać z naszego serwisu. Spamerom dziękujemy!
Prosimy o pomoc dla małej Julki — przekaż 1% podatku na Fundacji Dzieciom zdazyć z Pomocą.
Więcej informacji na dug.net.pl/pomagamy/.
Strony: 1
Witam.
Mam problem z rozwiązaniem zadania 7 z rozdziału 14.
Zmodyfikuj listing 14.14 tak, aby w miarę odczytywania kolejnych rekordów i wyświetlania ich na ekranie możliwe było usunięcie lub zmiana zawartości każdego rekordu. W przypadku usunięcia rekordu w zwolnionym miejscu tablicy powinien zostać umieszczony następny odczytany rekord. Aby umożliwić zmianę zawartości pliku, będziesz musiał użyć trybu "r+b" zamiast "a+b". Będziesz również musiał poświęcić więcej uwagi wskaźnikowi położenia, tak aby dodawane rekordy nie zamazywały rekordów istniejących. Najprostrszym wyjściem jest przygotowanie całości danych w pamięci komputera, a następnie zapisanie ich w ostatecznej wersji w pliku. Usuwanie można by obsłużyć poprzez uzupełnienie struktury o specjalny znacznik, sygnalizujący, że struktura została usunięta (i nie ma być zapisana do pliku).
Mój kod:
#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXTYT 40 #define MAXAUT 40 #define MAXKS 10 char * wczytaj(char * z, int ile); struct ksiazka { char tytul[MAXTYT]; char autor[MAXAUT]; float wartosc; bool usunieta; }; int main(void) { struct ksiazka bibl[MAXKS]; int licznik = 0; int index, licznikp; FILE * pksiazki; int rozmiar = sizeof(struct ksiazka); if ((pksiazki = fopen("ksiazki.dat", "a+b")) == NULL) { fputs("Nie moge otworzyc pliku ksiazki.dat\n", stderr); exit(1); } rewind(pksiazki); while (licznik < MAXKS && fread(&bibl[licznik], rozmiar, 1, pksiazki) == 1) { if (licznik == 0) puts("Biezaca zawartosc pliku ksiazki.dat:"); printf("%s by %s: %.2f zl\n", bibl[licznik].tytul, bibl[licznik].autor, bibl[licznik].wartosc); licznik++; } licznikp = licznik; if (licznik == MAXKS) { fputs("Plik ksiazki.dat jest pelny.", stderr); exit(2); } struct ksiazka ksiazka; int wybor; puts("Co chcesz zrobic (1 - dodac, 2 - usunac, 3 - zmodyfikowac, 4 - zostawic bez zmian)?"); scanf("%d", &wybor); switch (wybor) { case 1: puts("Podaj nowe tytuly ksiazek."); puts("Aby zakonczyc, nacisnij [enter] na poczatku wiersza."); while (licznik < MAXKS && wczytaj(bibl[licznik].tytul, MAXTYT) != NULL && bibl[licznik].tytul[0] != '\0') { puts("Teraz podaj autora."); wczytaj(bibl[licznik].autor, MAXAUT); puts("Teraz podaj wartosc."); scanf("%f", &bibl[licznik++].wartosc); while (getchar() != '\n') continue; bibl[licznik].usunieta = false; if (licznik < MAXKS) puts("Podaj nastepny tytul."); } break; case 2: puts("Podaj tytul ksiazki do usuniecia."); wczytaj(ksiazka.tytul, MAXTYT); puts("Teraz podaj autora."); wczytaj(ksiazka.autor, MAXAUT); puts("Teraz podaj wartosc."); scanf("%f", &ksiazka.wartosc); int i = 0; while (i < MAXKS && strcmp(bibl[i].tytul, ksiazka.tytul) != 0 && strcmp(bibl[i].autor, ksiazka.autor) != 0 && bibl[i].wartosc != ksiazka.wartosc) i++; if (i != MAXKS) bibl[i].usunieta = true; break; default: puts("Nieprawidlowy wybor."); break; } if (licznik > 0) { puts("Oto lista Twoich ksiazek:\n"); for (index = 0; index < licznik; index++) if (!bibl[index].usunieta) { printf("%s, autor: %s, cena: %.2f zl\n", bibl[index].tytul, bibl[index].autor, bibl[index].wartosc); fwrite(&bibl[licznikp], rozmiar, licznik - licznikp, pksiazki); } } else puts("Zadnych ksiazek? Szkoda\n"); puts("Koniec.\n"); return 0; } char * wczytaj(char * z, int ile) { char * wynik; char * tutaj; wynik = fgets(z, ile, stdin); if (wynik) { tutaj = strchr(z, '\n'); if (tutaj) *tutaj = '\0'; else while (getchar() != '\n') continue; } return wynik; }
Wychodzą mi dziwne wyniki po uruchomieniu programu:
Biezaca zawartosc pliku ksiazki.dat:
Metryczna mlodosc by POlly Poetica: 75.99 zl
Co chcesz zrobic (1 - dodac, 2 - usunac, 3 - zmodyfikowac, 4 - zostawic bez zmian)?
1
Podaj nowe tytuly ksiazek.
Aby zakonczyc, nacisnij [enter] na poczatku wiersza.
Oto lista Twoich ksiazek:
Metryczna mlodosc, autor: POlly Poetica, cena: 75.99 zl
Koniec.
Czemu zczytanie jedynki powoduje, że nie chce się wczytać tytuł?
Offline
hubot napisał(-a):
Czemu zczytanie jedynki powoduje, że nie chce się wczytać tytuł?
Ponieważ funckja wczytaj zwraca za pierwszym razem pustego stringa (o długości 0) i dlatego ta pętla:
while (licznik < MAXKS && wczytaj(bibl[licznik].tytul, MAXTYT) != NULL && bibl[licznik].tytul[0] != '\0') { (...)
nigdy się nie wykona
można po prostu przed rozpoczęciem pętli raz wywołać:
wczytaj(bibl[licznik].tytul, MAXTYT)
i będzie działać tak jak chciał autor
Offline
Tak się dzieje ponieważ scanf nie wczytuje newline i jest on zbierany przez pierwsze wywołanie fgets w funkcji wczytaj
Ostatnio edytowany przez Elizabeth (2018-03-04 18:30:52)
Offline
Mam problem z usuwaniem rekordów z pliku.
Na początku otrzymuję wynik porządany:
Biezaca zawartosc pliku ksiazki.dat:
abc by def: 123.00 zl
abg by deh: 234.00 zl
Co chcesz zrobic (1 - dodac, 2 - usunac, 3 - zmodyfikowac, 4 - zostawic bez zmian)?
2
Podaj tytul ksiazki do usuniecia.
abg
Teraz podaj autora.
deh
Teraz podaj wartosc.
234.00
Oto lista Twoich ksiazek:
abc, autor: def, cena: 123.00 zl
Koniec.
Natomiast po ponownym uruchomieniu programu okazuje się, że rekord nie został usunięty:
Biezaca zawartosc pliku ksiazki.dat:
abc by def: 123.00 zl
abg by deh: 234.00 zl
Co chcesz zrobic (1 - dodac, 2 - usunac, 3 - zmodyfikowac, 4 - zostawic bez zmian)?
Mój kod:
#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXTYT 40 #define MAXAUT 40 #define MAXKS 10 char * wczytaj(char * z, int ile); struct ksiazka { char tytul[MAXTYT]; char autor[MAXAUT]; float wartosc; bool usunieta; }; int main(void) { struct ksiazka bibl[MAXKS]; int licznik = 0; int index, licznikp; FILE * pksiazki; int rozmiar = sizeof(struct ksiazka); if ((pksiazki = fopen("ksiazki.dat", "r+b")) == NULL) { fputs("Nie moge otworzyc pliku ksiazki.dat\n", stderr); exit(1); } rewind(pksiazki); while (licznik < MAXKS && fread(&bibl[licznik], rozmiar, 1, pksiazki) == 1) { if (licznik == 0) puts("Biezaca zawartosc pliku ksiazki.dat:"); if (!bibl[licznik].usunieta) printf("%s by %s: %.2f zl\n", bibl[licznik].tytul, bibl[licznik].autor, bibl[licznik].wartosc); licznik++; } licznikp = licznik; if (licznik == MAXKS) { fputs("Plik ksiazki.dat jest pelny.", stderr); exit(2); } struct ksiazka ksiazka; int wybor; puts("Co chcesz zrobic (1 - dodac, 2 - usunac, 3 - zmodyfikowac, 4 - zostawic bez zmian)?"); scanf("%d", &wybor); while (getchar() != '\n') continue; switch (wybor) { case 1: puts("Podaj nowe tytuly ksiazek."); puts("Aby zakonczyc, nacisnij [enter] na poczatku wiersza."); while (licznik < MAXKS && wczytaj(bibl[licznik].tytul, MAXTYT) != NULL && bibl[licznik].tytul[0] != '\0') { puts("Teraz podaj autora."); wczytaj(bibl[licznik].autor, MAXAUT); puts("Teraz podaj wartosc."); scanf("%f", &bibl[licznik++].wartosc); while (getchar() != '\n') continue; bibl[licznik].usunieta = false; if (licznik < MAXKS) puts("Podaj nastepny tytul."); } break; case 2: puts("Podaj tytul ksiazki do usuniecia."); wczytaj(ksiazka.tytul, MAXTYT); puts("Teraz podaj autora."); wczytaj(ksiazka.autor, MAXAUT); puts("Teraz podaj wartosc."); scanf("%f", &ksiazka.wartosc); int i = 0; while (i < MAXKS && strcmp(bibl[i].tytul, ksiazka.tytul) != 0 && strcmp(bibl[i].autor, ksiazka.autor) != 0 && bibl[i].wartosc != ksiazka.wartosc) i++; if (i != MAXKS) bibl[i].usunieta = true; break; default: puts("Nieprawidlowy wybor."); break; } if (licznik > 0) { puts("Oto lista Twoich ksiazek:\n"); for (index = 0; index < licznik; index++) if (!bibl[index].usunieta) { printf("%s, autor: %s, cena: %.2f zl\n", bibl[index].tytul, bibl[index].autor, bibl[index].wartosc); } fwrite(&bibl[licznikp], rozmiar, licznik - licznikp, pksiazki); } else puts("Zadnych ksiazek? Szkoda\n"); puts("Koniec.\n"); return 0; } char * wczytaj(char * z, int ile) { char * wynik; char * tutaj; wynik = fgets(z, ile, stdin); if (wynik) { tutaj = strchr(z, '\n'); if (tutaj) *tutaj = '\0'; else while (getchar() != '\n') continue; } return wynik; }
Offline
O matko, jak można tak "usuwać" dane z tablicy poprzez zaznaczanie flagi ??? Powinieneś po prostu przepisywać dane do nowej tablicy pomijając elemnety spełniające warunek usunięcia, potem zwolnić dane oryginalne, a nowe dane podpiąć pod stary wskaźnik
Taka konstrukcja:
fwrite(&bibl[licznikp], rozmiar, licznik - licznikp, pksiazki);
akurat działa przy dodawaniau, ponieważ przy dodawaniu licznik się zwiększa a licznikp zachowuje oryginalną
wartość,
to nie może działać przy usuwaniu z wielu powodów, np. dlatego, że nigdzie w prgramie już nie jest cofany wskaźnik pozycji
pisania do pliku
najlepiej i najprosciej jest przepisac wszystkie dane do tablicy, zmodyfikowac tablice w programie, a pozniej zawsze na koncu, wyzerowac plik (np. otwierajac jeszcze raz z flaga 0_TRUNC) i wpisac cala tablice od początku:
fwrite(bibl, rozmiar, ilosc_elementow_po_modyfikacjach, pksiazki);
Offline
Strony: 1