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
[quote=hubot]Czemu zczytanie jedynki powoduje, że nie chce się wczytać tytuł?[/quote]
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)[/quote]
i będzie działać tak jak chciał autor
GPG Key ID: [url=http://keys.gnupg.net/pks/lookup?op=get&search=0x8D55F13761AF5230]0x8D55F13761AF5230[/url]
Fingerprint: B884 468A D6DC 0516 2B43 6675 8D55 F137 61AF 5230
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
[b]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);[/b]
Offline
Strony: 1
Time (s) | Query |
---|---|
0.00011 | SET CHARSET latin2 |
0.00004 | SET NAMES latin2 |
0.00118 | SELECT u.*, g.*, o.logged FROM punbb_users AS u INNER JOIN punbb_groups AS g ON u.group_id=g.g_id LEFT JOIN punbb_online AS o ON o.ident='18.118.140.78' WHERE u.id=1 |
0.00083 | REPLACE INTO punbb_online (user_id, ident, logged) VALUES(1, '18.118.140.78', 1732181144) |
0.00074 | SELECT * FROM punbb_online WHERE logged<1732180844 |
0.00084 | SELECT t.subject, t.closed, t.num_replies, t.sticky, f.id AS forum_id, f.forum_name, f.moderators, fp.post_replies, 0 FROM punbb_topics AS t INNER JOIN punbb_forums AS f ON f.id=t.forum_id LEFT JOIN punbb_forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id=3) WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.id=30333 AND t.moved_to IS NULL |
0.00006 | SELECT search_for, replace_with FROM punbb_censoring |
0.00316 | SELECT u.email, u.title, u.url, u.location, u.use_avatar, u.signature, u.email_setting, u.num_posts, u.registered, u.admin_note, p.id, p.poster AS username, p.poster_id, p.poster_ip, p.poster_email, p.message, p.hide_smilies, p.posted, p.edited, p.edited_by, g.g_id, g.g_user_title, o.user_id AS is_online FROM punbb_posts AS p INNER JOIN punbb_users AS u ON u.id=p.poster_id INNER JOIN punbb_groups AS g ON g.g_id=u.group_id LEFT JOIN punbb_online AS o ON (o.user_id=u.id AND o.user_id!=1 AND o.idle=0) WHERE p.topic_id=30333 ORDER BY p.id LIMIT 0,25 |
0.00119 | UPDATE punbb_topics SET num_views=num_views+1 WHERE id=30333 |
Total query time: 0.00815 s |