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

Użytkownik


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
Użytkownik

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
Użytkownik

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

Użytkownik


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
Użytkownik

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