Problém snad se spojovým seznamem – Pascal – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Problém snad se spojovým seznamem – Pascal – Fórum – Programujte.comProblém snad se spojovým seznamem – Pascal – Fórum – Programujte.com

 

Hopeless0
Duch
24. 5. 2011   #1
-
0
-

Jsem ochotná zaplatit.
Potřebuji napsat program na následující zadání:

Vytvořte program, který bude realizovat následující operace se seznamem knih v knihovně:
vložení nové knihy do seznamu (realizováno procedurou VLOZ bez parametru)
vyhledaní knihy (realizováno procedurou HLEDEJ, jejímž parametrem bude řetezec, který mají obsahovat údaje o knize)
vymazání knihy ze seznamu (procedura VYMAZ, kniha určena signaturou)
opravu údajů o knize (procedura OPRAV)
uložení seznamu na disk (procedura NaDisk, jejímž parametrem bude jméno souboru)
načtení uloženého seznamu z disku (procedura ZDisku, jejímž parametrem bude jméno souboru)
O každé knize budou v seznamu následující informace:
název
autor
signatura (např. 123456g)
poznámka (max 80 znaků)

Program realizujte pomocí dynamické struktury.

Zasílám, co mám:

Program Knihovna;




Const HMez = 3;

Type TPocknih = 0..HMez;

Type Tkniha = record
nazev: string[30];
autor: string [30];
signatura: string[11];
poznamka:string[30];
end;
Pkniha = ^Tkniha;
Tknihy = array[1..HMez] of Pkniha;

var Seznam: Tknihy;
Pocet: TPocknih;
a:Pkniha;


Procedure Menu(var Sezn: Tknihy; var Pocknih: TPocknih); forward;


Procedure Nactiknihy(var Sezn: Tknihy; var Pocknih: TPocknih);
var Zaplneno: boolean;

Jm: string;
begin


writeln('Zadani knih');
writeln('---------------');

writeln;
Zaplneno:=false;
repeat
if Pocknih>=HMez then Zaplneno:=true
else begin
inc(Pocknih);
write('Nazev knihy: ');
readln(Jm);
if Jm<>'' then begin
new(Seznam[Pocknih]);
if Seznam[Pocknih]<>nil then
with Sezn[Pocknih]^ do begin
nazev:=Jm;
write('Autor: ');
readln(autor);
write('Signatura: ');
readln(signatura);
write('Poznamka: ');
readln(poznamka);
end
else begin
writeln('Chyba pri alokaci polozky seznamu!');
Jm:=''; {dojde k ukonceni cyklu}
end;
end;
end;
writeln;
until (Zaplneno) or (Jm='');
if Jm='' then dec(Pocknih);
writeln('Udaje byly nacteny.');

Menu(Seznam, Pocet);
end;


Procedure Vypisknihy(var Sezn: Tknihy; var Pocknih: TPocknih);
var i: TPocknih;
begin

writeln('Vypis knih');
writeln('--------------');

writeln;
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');
for i:=1 to Pocknih do
with Sezn[i]^ do begin
write(nazev,' ');
write(autor:20,' ');
write(signatura:10,' ');
write(poznamka:20,' ');
writeln();
end;
writeln('-----------------------------------------------------------');
writeln('Celkem knih: ',Pocknih);

Menu(Seznam, Pocet);
end;


Procedure ZapisDoTXT(var Sezn: Tknihy; var Pocknih: TPocknih);
var i: TPocknih;
stxt: text;
JmSouboru: string;
chyba: boolean;
begin

writeln('Ulozeni seznamu do textoveho souboru');
writeln('------------------------------------');

writeln;
{$I-}
repeat
writeln('Zadejte nazev souboru: ');
readln(JmSouboru);
assign(stxt, JmSouboru);
append(stxt);
chyba:=(IOResult<>0);
if chyba then writeln('Chyba!');
until not chyba;

for i:=1 to Pocknih do
with Sezn[i]^ do begin
write(stxt, nazev,' ');
write(stxt, autor,' ');
write(stxt, signatura,' ');
write(stxt, poznamka,' ');
end;

close(stxt);
{$I+}
Menu(Seznam, Pocet);
end;

Procedure nacteniTXT(var Sezn: Tknihy; var Pocknih: TPocknih);
var i: TPocknih;
stxt: text;
JmSouboru: string;
chyba: boolean;
begin
writeln('Nacteni seznamu z textoveho souboru');
writeln('------------------------------------');

writeln;
{$I-}
repeat
writeln('Zadejte nazev souboru: ');
readln(JmSouboru);
assign(stxt, JmSouboru);
reset(stxt);
chyba:=(IOResult<>0);
if chyba then writeln('Chyba!');
until not chyba;

writeln('Vypis knih');
writeln('--------------');

writeln;
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');


for i:=1 to Pocknih do
with Sezn[i]^ do begin
read(stxt, nazev);
read(stxt, autor);
read(stxt, signatura);
read(stxt, poznamka);
write(nazev,' ');
write(autor:20,' ');
write(signatura:10,' ');
write(poznamka:20,' ');writeln();


end;

close(stxt);
{$I+}
Menu(Seznam, Pocet);
end;


Procedure VymazSeznam(var Sezn: Tknihy; var Pocknih: TPocknih);
var i: TPocknih;
begin

for i:=1 to Pocknih do begin
dispose(Seznam[i]);
Seznam[i]:=nil;
end;
Pocknih:=0;
writeln('Seznam byl vymazan.');

Menu(Seznam, Pocet);
end;


Procedure Vymaz(var Sezn: Tknihy; var Pocknih: TPocknih);
var i: TPocknih;
begin
for i:=1 to Pocknih do begin
dispose(Seznam[i]);
Seznam[i]:=nil;
end;
Pocknih:=0;
end;


Procedure Menu(var Sezn: Tknihy; var Pocknih: TPocknih);
var polozka: string;
begin
repeat

writeln('Evidence knih');
writeln('-----------------');

writeln;
writeln('1) Vkladani knih');
writeln('2) Vypis knih');
writeln('3) Ulozeni seznamu na disk');
writeln('4) Oprava udaju o knize');
writeln('5) Vymazani knihy dle signatury');
writeln('6) Vyhledani knihy dle nazvu');
writeln('7) Nacteni seznamu z disku');
writeln('8) Vymazani seznamu');
writeln('9) Konec programu');
writeln;
write('Vyberte pozadovanou akci (1-9): ');
readln(polozka);
if Length(polozka)=1 then
case polozka[1] of
'1': Nactiknihy(Seznam, pocet);
'2': Vypisknihy(Seznam, pocet);
'3': ZapisDoTXT(Seznam, pocet);
'4': ;
'5': ;
'6': ;
'7': nacteniTXT(Seznam,pocet);
'8': VymazSeznam(Seznam, pocet);
end;
until (polozka[1] in ['1'..'9']) and (Length(polozka)=1);
end;


begin

Pocet:=0;
Menu(Seznam, Pocet);



end.


Neumím vypsat obsah uloženého souboru a vůbec nevím, zda půjde vyhledávat, mazat atd. Prosím o poskytnutí podobného programu, příp. koupím vyřešení této blbiny.

Nahlásit jako SPAM
IP: 89.203.206.–
Mircosoft+1
Věrný člen
25. 5. 2011   #2
-
+1
-
Zajímavé

Tohle zadání už jsem několikrát viděl, asi tak před pěti lety. Zřejmě podobná nesmrtelná klasika jako návrh převodovky ve třetím ročníku na Strojárně :-).
(Ne, celé ti to nenapíšu ani za peníze. To jenom aby nedošlo k nedorozumění.)

Začneme rozborem zadání, ze kterého vyplyne pár dotazů, které bude nutně potřeba položit zadávajícímu.

"vložení nové knihy do seznamu (realizováno procedurou VLOZ bez parametru)" - tohle nechápu. Když má být bez parametru, tak jak pozná, jakou knihu má vložit? Buď je to chyba zadání, nebo se mají použít globální proměnné (což je IMHO prasárna), nebo se mají údaje číst z klávesnice. Zeptej se.

"vyhledaní knihy (realizováno procedurou HLEDEJ, jejímž parametrem bude řetezec, který mají obsahovat údaje o knize)" - vstupy jsou poněkud nejasné (není jasné, jestli se má prohledat jméno, autor, poznámka nebo všechno), ale dejme tomu. Horší je, že není vůbec jasné, jakým způsobem z té procedury dostaneme výsledky hledání. Mají se vypsat na obrazovku? Předat do nějaké globální proměnné? Nebo přes další parametr, o kterém zadání nic neříká?

"opravu údajů o knize (procedura OPRAV)" - málo informací. Selský rozum říká, že vstupním parametrem bude signatura knihy (nebo nějaký jiný údaj, podle kterého se kniha jednoznačně najde) a v dalších parametrech budou nové hodnoty. Ale radši bych se zeptal.

"uložení seznamu na disk (procedura NaDisk, jejímž parametrem bude jméno souboru)" - není dán typ souboru. Použil bych nejjednodušší možnost File of tkniha. Ale určitě je lepší se zeptat než to pak předělávat.

"O každé knize budou v seznamu následující informace:..." - kromě Poznámky není nikde řečeno, jak má být která položka dlouhá. Máš tři možnosti: délky si zvolit (může se stát, že to nebudou ty správné), udělat je dynamické (to jde, ale je to dost těžké) nebo se zeptat (to je nejjednodušší a nejjistější).

"Program realizujte pomocí dynamické struktury." - to znamená, že nemáš knihy ukládat do statického pole, jako to děláš teď. Nastuduj si něco o spojových seznamech, třeba http://mircosoft.ic.cz/texty/UKAZ.TXT.


Až seženeš odpovědi na výše uvedené otázky, stav se, poradíme ;-).

Nahlásit jako SPAM
IP: 208.232.182.–
Chceš-li lepší odpověď, polož lepší otázku.
Moje stránka.
Hopeless0
Duch
26. 5. 2011   #3
-
0
-

To Mircosoft :

Děkuji za odpověď. Úkol je to hrozný - z pedag. fakulty, to jsem už pochopila. Studuji při zaměstnání a bez výuky. Abych upřesnila ty ostatní záležitosti - jak to udělám je v celku jedno - co není zadané, si mohu zvolit. Hlavní kritérium je - co nejjednodušeji. Pomozte mi prosím nějak začít, vytvořila jsem již několik verzí, ale zřejmě jsem začala špatně, takže pak už to nefungovalo.

Vstupy budou stačit z klávesnice, výstup na obrazovku.

Nahlásit jako SPAM
IP: 89.203.206.–
Mircosoft+1
Věrný člen
26. 5. 2011   #4
-
0
-

Výborně, tím se nám to zjednodušuje.

Potřebuješ znát:
- Co to jsou ukazatele (typ Pointer nebo ^něco), jak se dynamicky alokuje (New) a dealokuje (Dispose) paměť, jak se dostaneš k datům, na která ukazatel ukazuje (^), co si s pamětí můžeš dovolit a co ne (např. nikdy nesmíš zapisovat do paměti, kterou nemáš alokovanou).
- Spojové seznamy. Co to je, vkládání a mazání prvků, procházení prvek po prvku.
- Práce se soubory (datový typ File of něco). Propojení se souborem na disku (Assign), otevření pro čtení (Reset), pro zápis (Rewrite), zavření (Close), čtení (Read) a zápis (Write). Plus vědět, co znamenají chybové hlášky, které se občas můžou vyskytnout (např. "file not found").
- Práce s řetězci (typ String), především hledání podřetězců (Pos) a případně procházení znak po znaku a převod na velká písmena (Upcase).


V tom svém programu máš problém ve vzájemném volání procedur: Menu zavolá Vymazseznam, ta něco udělá a zase zavolá Menu, to zavolá nějakou další atd. a tak se zanořují čím dál tím hlouběji jedna do druhé a v extrémním případě to skončí přetečením systémového zásobníku (stack overflow). Lepší by bylo udělat Menu jako funkci, která vrací číslo volby (případně rovnou nastaví nějakou proměnnou "Akce"), a hlavní část programu potom udělat jako cyklus:

var akce:integer;


...

repeat
akce:=menu;
case akce of 1:vloz;
2:vypis;
...
else writeln('Tahle akce neni definovana, '+
'zadavejte pouze cisla od 1 do 9.');
end;
until akce=9;

...

Snaž se soustředit vždycky jenom na jednu věc: nejdřív napiš vkládání, pak výpis, aby se dal seznam kontrolovat, pak jedno po druhém to ostatní.

Nahlásit jako SPAM
IP: 141.202.248.–
Chceš-li lepší odpověď, polož lepší otázku.
Moje stránka.
Hopeless0
Duch
27. 5. 2011   #5
-
0
-

Pokusila jsem se něco napsat. Můžeš se podívat, jestli je to dobře?



Program knihovna;

type

UkNaZaznam=^data;

zaznam =
record
autor:string[20];
nazev: string[25];
signatura: string[10];
poznamka: string[80];
end;

data=
record
hodnota:zaznam;
dalsi:UkNaZaznam;
end;

var akce, menu,pocet,i:integer;
novy,vybrany:UkNaZaznam;



procedure vloz;
begin
write('Zadej pocet zaznamu:');
readln(pocet);
for i:=1 to pocet do
begin
new(novy);
write('Autor: ');
readln(novy^.hodnota.autor);
write('Nazev knihy: ');
readln(novy^.hodnota.nazev);
write('Signatura: ');
readln(novy^.hodnota.signatura);
write('Poznamka: ');
readln(novy^.hodnota.poznamka);
novy^.dalsi:=vybrany;
vybrany:=novy;
end;
writeln();
end;

procedure vypis;
begin
if novy<>nil then
begin
novy:=vybrany;
writeln('Vypis databaze:');
writeln('--------------');
writeln;
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');

repeat
writeln(novy^.hodnota.autor,novy^.hodnota.nazev:20,novy^.hodnota.signatura:15,novy^.hodnota.poznamka:15);
novy:=novy^.dalsi;
until novy=nil;
writeln();
end
else
writeln('Databaze je prazdna.');
end;
procedure uloz;
begin

end;

procedure nacti;
begin

end;

procedure vyhledej;
begin

end;
procedure oprav;
begin

end;

procedure zrus;
begin

end;

begin
writeln(' ');
writeln('*******************************Knihovna*******************************');
writeln(' ');
repeat
writeln('Menu:');
writeln('1: Vlozit zaznam');
writeln('2: Vypis zaznam');
writeln('3: Uloz zaznamy do souboru');
writeln('4: Nacti zaznamy ze souboru');
writeln('5: Vyhledani zaznamu po zadani nazvu knihy');
writeln('6: Oprava zaznamu');
writeln('7: Zruseni zaznamu');
writeln('8: Konec');
writeln();

writeln('Zadej cislo akce');
readln(menu);
akce:=menu;
case akce of 1:vloz;
2:vypis;
3:uloz;
4:nacti;
5:vyhledej;
6:oprav;
7:zrus;
8:;
else writeln('Tahle akce neni definovana, '+
'zadavejte pouze cisla od 1 do 8.');
end;
until akce=8;
end.

Nahlásit jako SPAM
IP: 89.203.206.–
Mircosoft+1
Věrný člen
27. 5. 2011   #6
-
0
-

No vidíš, jde ti to docela dobře. Jen tak dál!

Pár poznámek:

- Spíš než "vybrany" bych ukazatel na začátek seznamu nazval "prvni", aby se mi to pak nepletlo. Jméno "vybrany" většinou používám pro pomocné ukazatele, kterými seznam procházím, a "novy" výhradně pro účely New. Je sice tvoje věc, překladači je to jedno a na funkci programu to nemá vliv, ale bacha, aby ses v tom potom neztratila.

- Do procedury Vloz bych přidal vypsání aktuální hodnoty i, aby uživatel věděl, kolikátou knihu už zadává a nebál se, že skončil v nějaké nekonečné smyčce. Ale to je jenom kosmetický detail, samotné vkládání máš v pořádku.

- Na začátku procedury Vypis je chybička, i když za běžných podmínek se neprojeví: if novy<>nil then vypisuj else databáze je prázdná. Jestli na začátek seznamu ukazuje Vybrany, testuj Vybrany a ne Novy. Teď ti to funguje, protože Novy zůstává nastavený po předchozím vkládání, ale jakmile ho něčím vyniluješ (třeba zrovna tím výpisem), bude ti to hlásit prázdnou databázi, i když v ní ve skutečnosti něco bude.

- Na začátku programu bys měla nastavit ukazatel na začátek seznamu na Nil. Sice se obvykle všechny globální proměnné na začátku nulují automaticky, ale lepší je na to nespoléhat.

- V hlavním cyklu máš "readln(menu); akce:=menu;". To je zbytečné, stačí napsat rovnou "readln(akce);". Ale fungovat to bude tak i tak.

Hlavně by sis měla zvyknout používat lokální proměnné. Jako globální potřebuješ mít jenom ukazatel na začátek seznamu a Akci. Všechno ostatní jsou pomocné věci, které by měly být deklarovány jenom v těch procedurách a funkcích, ve kterých se používají. Největší výhoda je, že se tím program velice zpřehlední a hlavně se omezí situace, že (obrazně řečeno) jedna procedura si něco někam položí a jiná o to pak zakopne (třeba zrovna tady ten ukazatel Novy, který používají Vloz a Vypis každá na něco jiného).

Nahlásit jako SPAM
IP: 208.232.182.–
Chceš-li lepší odpověď, polož lepší otázku.
Moje stránka.
Hopeless0
Duch
29. 5. 2011   #7
-
0
-

To Mircosoft :
Tak jsem zase kousek napsala. S těmi ukazateli jsi měl pravdu. Už jsem se v tom ztratila. Udělala jsem vyhledávání - to funguje

Potom rušení - nelze zrušit poslední záznam, skončí to chybou. Vím i kde je (řádek 173), ale nevím, jak to opravit.

Nevím, jestli je dobře ukládání a načítání ze souboru (je to práce s netypovým souborem?) - snažila jsem se to najít na netu, ale moc jsem toho nenašla.

To, co jsi mi radil jsem se pokusila opravit, nevím, jestli dobře.

Díky

M.





Program knihovna4;
const FileMode: Byte = 2;

type

UkNaZaznam=^data;

zaznam =
record
nazev: string[25];
autor:string[20];
signatura: string[10];
poznamka: string[80];
end;

data=
record
hodnota:zaznam;
dalsi:UkNaZaznam;
end;

var
akce:integer;
prvni:UkNaZaznam;
pocet:integer;

procedure vloz;
var
novy:UkNaZaznam;
i:integer;
begin
write('Zadej pocet zaznamu: ');
readln(pocet);
for i:=1 to pocet do
begin
new(novy);
writeln('Zaznam cislo: ',i);
write('Nazev knihy: ');
readln(novy^.hodnota.nazev);
write('Autor: ');
readln(novy^.hodnota.autor);
write('Signatura: ');
readln(novy^.hodnota.signatura);
write('Poznamka: ');
readln(novy^.hodnota.poznamka);
novy^.dalsi:=prvni;
prvni:=novy;
end;
writeln();
end;

procedure vypis;
var
akt:UkNaZaznam;
begin
akt:=prvni;
if akt<>nil then
begin

writeln('Vypis databaze:');
writeln('--------------');
writeln;
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');

repeat
writeln(akt^.hodnota.nazev,akt^.hodnota.autor:20,akt^.hodnota.signatura:15,akt^.hodnota.poznamka:15);
akt:=akt^.dalsi;
until akt=nil;
writeln();
akt:=prvni;
end
else
writeln('Databaze je prazdna.');
writeln();
end;
procedure uloz;
var
f:file of zaznam;
kniha:zaznam;
begin
assign(f, 'knihy.txt');
rewrite(f);
BlockWrite(f,kniha,pocet);
close(f);
writeln('Databaze je ulozena do souboru knihy.txt');
writeln();
end;

procedure nacti;
var
f:file of zaznam;
kniha:zaznam;
begin
assign(f, 'knihy.txt');
reset(f);
while not eof(f) do
begin
BlockRead(f,kniha,pocet);
end;
close(f);
writeln('Databaze je nactena ze souboru knihy.txt');
writeln();
end;

procedure vyhledej;
var
klic:string;
akt,hledany:UkNaZaznam;
begin
akt:=prvni;
write('Zadej autora: ');
readln(klic);
while ((akt^.dalsi<>nil) and (akt^.hodnota.autor<>klic)) do
begin
akt:= akt^.dalsi;
end;
hledany:=akt;
if (hledany<>nil)and (akt^.hodnota.autor=klic) then
begin
writeln('Hledany zaznam:');
writeln();
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');
writeln(hledany^.hodnota.nazev,hledany^.hodnota.autor:20,hledany^.hodnota.signatura:15,hledany^.hodnota.poznamka:15);
writeln();
end
else writeln('Zaznam nenalezen');
writeln();
end;


procedure oprav;
begin

end;
procedure zrus;

var
klic:string;
akt,ruseny,pom,hledany: UkNaZaznam;
begin
write('Zadej signaturu: ');
readln(klic);

if prvni^.hodnota.signatura=klic then
begin
ruseny:=prvni;
dispose(ruseny);
end

else

begin
akt:=prvni;
while (akt^.dalsi<>nil) and (akt^.hodnota.autor<>klic) do
begin
pom:=akt;
akt:= akt^.dalsi;
end;
hledany:=akt;
if (hledany=nil) or (akt^.hodnota.autor<>klic) then writeln('Zaznam nenalezen');

end;

if hledany<>nil then

begin
ruseny:=hledany;
pom^.dalsi:=ruseny^.dalsi;
writeln('Tento zaznam bude zrusen:');
writeln();
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');
writeln(ruseny^.hodnota.nazev,ruseny^.hodnota.autor:20,ruseny^.hodnota.signatura:15,ruseny^.hodnota.poznamka:15);
dispose(ruseny);
end;
end;


begin
writeln(' ');
writeln('*******************************Knihovna*******************************');
writeln(' ');
prvni:=nil;
repeat
writeln('Menu:');
writeln('1: Vlozit zaznam');
writeln('2: Vypis zaznamu');
writeln('3: Uloz zaznamy do souboru');
writeln('4: Nacti zaznamy ze souboru');
writeln('5: Vyhledani zaznamu po zadani nazvu knihy');
writeln('6: Oprava zaznamu po zadani');
writeln('7: Zruseni zaznamu po zadani');
writeln('8: Konec');
writeln();

writeln('Zadej cislo akce: ');
readln(akce);
case akce of 1:vloz;
2:vypis;
3:uloz;
4:nacti;
5:vyhledej;
6:oprav;
7:zrus;
8:;
else writeln('Tahle akce neni definovana, '+
'zadavejte pouze cisla od 1 do 8.');
end;
until akce=8;
end.

Nahlásit jako SPAM
IP: 89.203.206.–
Mircosoft+1
Věrný člen
1. 6. 2011   #8
-
0
-

- "const FileMode: Byte = 2;" vyhoď. Zaprvé, Filemode je globální proměnná definovaná v jednotce System, takže jestli ji chceš měnit, udělej to normálně v programu (Filemode:=2) bez jakýchkoli deklarací. A zadruhé tuhle hodnotu (kombinovaný přístup pro čtení i zápis) stejně nebudeš potřebovat, vystačíš si s normálním čtením a zápisem. A navíc je 2 výchozí hodnota.

- Nevím, co přesně má dělat proměnná Pocet. První použití vidím v zadávání - kolik knih se bude zadávat. To vypadá spíš na lokální pomocnou proměnnou, protože se při každém volání Zadej přepíše a z hlediska hlavního programu nemá žádnou informační hodnotu. Jestli chceš něco, v čem se bude neustále udržovat aktuální počet knih v seznamu, tak to musí být proměnná, která se po každém vložení zvýší o 1, při vymazání se o 1 sníží a nikde jinde se měnit nebude. Ale to je podle mě celkem zbytečná práce, protože si seznam můžeš kdykoli projít a knížky spočítat.

- Hledání: místo "while ((akt^.dalsi<>nil) and (akt^.hodnota.autor<>klic)) do akt:= akt^.dalsi;" dej "while ((akt<>nil) and (akt^.hodnota.autor<>klic)) do akt:= akt^.dalsi;". Takhle budeš mít po skončení cyklu buď Akt=nil, tj. kniha se nenašla, nebo Akt<>nil, tj. kniha se našla a Akt přímo na ni ukazuje.

- Rušení knih: chyba je v tom "pom^.dalsi:=ruseny^.dalsi;". Pom je jenom pomocný ukazatel, který tou dobou na žádnou knihu neukazuje, takže pod něj do ^.dalsi nemůžeš nic ukládat. Ale i když tenhle řádek změníš, stejně ti to nevyjde, protože to znovupropojení seznamu nemáš dodělané. Je potřeba ošetřit tři případy:
1) Seznam je úplně prázdný, tj. Prvni=nil. Pak je potřeba hned skončit a nic nedělat.
2) V seznamu je jenom jedna kniha, tj. Prvni<>nil a Prvni^.dalsi=nil. Buď to zkontroluješ přímo takhle, porovnáš signaturu a podle toho tu jednu knihu vyhodíš nebo ne (nezapomeň pak Prvni nastavit na nil, aby bylo příště jasné, že je seznam prázdný), nebo to nebudeš řešit takhle odděleně, ale pak si musíš vhodně upravit další postup.
3) V seznamu je víc než jedna kniha, první krok tedy musí být nalezení té, která se má vyhodit. Hledání si buď můžeš napsat přímo tady, jak to máš teď, nebo využiješ už napsanou hledací funkci.

Pro hledání by podle mě bylo úplně nejlepší napsat si samostatnou nízkoúrovňovou funkci, které jako parametr dáš nějaké informace o knize (signaturu, autora apod. - nejspíš asi celý tzaznam a která položka bude vyplněná, ta bude směrodatná) a ona ti jako návratovou hodnotu předá buď nil (záznam nenalezen) nebo adresu první knihy, která vyhovuje zadání. Případně ještě jako další vstupní parametr může mít adresu, od které má začít hledání (nil = začni od začátku, cokoli = začni od cokoli^.dalsi), aby se daly řešit duplicity a úlohy typu "vypiš mi všechny knihy od Františka Nepila". Tuhle funkci pak můžeš využívat ve výpisech, vyhledávání i mazání. Hlavička by vypadala nějak takhle:
function Najdi(CoHledame:tzaznam; odkud:uknazaznam):uknazaznam;
Ale to jak chceš, nutné to není.

Zpátky k rušení knih:
- Podmínku v hledacím cyklu "while (akt^.dalsi<>nil)..." změň na "while (akt<>nil) ..." (viz výše). V druhé části podmínky máš fatální chybu: testuješ autora, jenže uživatel zadal signaturu.
- Správně si udržuješ ukazatel na předchozí knihu (Pom), ale před začátkem cyklu do něj ještě vlož nil. Tím se zjednoduší pozdější testy při mazání první knihy v seznamu (pak Pom zůstane nil, takže budeme vědět, že je potřeba posunout Prvni na druhou).
- "hledany:=akt; if (hledany=nil) or (akt^.hodnota.autor<>klic) ..." - tohle je dost nešťasntný zápis. Máš dva zdánlivě nesouvisící ukazatele a v podmíce testuješ oba dva, i když oba ukazují na totéž. Jeden bych zrušil, celé by to zvládnul samotný Hledany a bylo by to mnohem přehlednější. Druhá věc: test klíče je tady zbytečný, protože předchozí cyklus se na jiné než na hledané knize nezastaví (buď to bude ona, nebo bude Hledany=nil).

Uf. Takže teď máme ukazatel na knihu, která se má smazat (Hledany, později i Ruseny, což je podle mě zase zbytečné, Hledany by tu funkci zastal i dál) a ukazatel na předchozí (Pom), teď to vlastní mazání. Možné situace jsou:
1) Mažeme první knihu (Hledany=Prvni, případně Pom=nil). Postup: Prvni posuň na druhou knihu, smaž Hledany (Dispose) a konec. Pokud byla v seznamu jenom jedna kniha, Prvni bude Nil (protože poslední kniha má vždy Dalsi=nil), takže OK.
2) Mažeme něco uprostřed nebo na konci (Hledany<>Prvni, Pom<>nil). Postup: nejdřív "pom^.dalsi:=hledany^.dalsi;". Tím zajistíš znovupropojení seznamu, takže se vyhozením knihy nepřeruší. Potom smaž Hledany a konec. Pokud se mazala poslední kniha (tj. Hledany^.dalsi=nil), přenesl se nil do předposlední knihy, takže OK.

Tohle ti zatím prakticky úplně chybí, takže dopiš.

- Ukládání:
file of zaznam, Assign, Rewrite - správný začátek, ale pokračování už ne.
Zaprvé, "file of zaznam" je typový soubor, takže do něj budeš zapisovat procedurou Write (write(f,kniha);).
Zadruhé, celý spojový seznam najednou zapsat nemůžeš. Je potřeba ho projít od začátku knihu po knize (to už umíš) a zapsat do souboru každou zvlášť (Write). Proměnná Kniha je celkem k ničemu, protože můžeš zapisovat rovnou write(f,aktualni^.hodnota);.
Závěr (close) je v pořádku.

- Načítání:
file of zaznam, Assign, Reset, while not eof(f)... - začátek dobře, ale každou načtenou knihu budeš muset do seznamu samostatně vložit. Proměnná Kniha se tentokrát asi bude hodit. Vkládání už jsi jednou napsala, možná by stálo za pokus napsat si univerzální procedurku na vkládání (vstupní parametr: vyplněná proměnná typu zaznam) a tu pak využívat jak při ručním zadávání, tak při "zadávání" ze souboru.
Jo, a před načtením ze souboru nezapomeň celý seznam smazat, ať se ti do něj soubor nekopíruje vícekrát.

Nahlásit jako SPAM
IP: 208.232.182.–
Chceš-li lepší odpověď, polož lepší otázku.
Moje stránka.
Hopeless0
Duch
3. 6. 2011   #9
-
0
-

To Mircosoft :

Děkuji strašně moc za rady. Už mi to celkem funguje, akorát ještě jeden problém. Nejde mi udělat tu vyhledávací funkci. Podle zadání by to mělo vyhledávat řetězce ve všech položkách záznamu. Dokázala jsem to jen v jedné.

Hrozně moc si mi pomohl. nemohu to nějak oplatit?

Díky

M.



Program knihovna6;



type

UkNaZaznam=^data;

zaznam =
record
nazev: string[25];
autor:string[20];
signatura: string[10];
poznamka: string[80];
end;

data=
record
hodnota:zaznam;
dalsi:UkNaZaznam;
end;

var
akce:integer;
prvni:UkNaZaznam;
pocet:integer;
jmsouboru:string;
klic, klic1:string;

procedure vloz;
var
novy:UkNaZaznam;
i:integer;
begin
write('Zadej pocet zaznamu: ');
readln(pocet);
for i:=1 to pocet do
begin
new(novy);
writeln('Zaznam cislo: ',i);
write('Nazev knihy: ');
readln(novy^.hodnota.nazev);
write('Autor: ');
readln(novy^.hodnota.autor);
write('Signatura: ');
readln(novy^.hodnota.signatura);
write('Poznamka: ');
readln(novy^.hodnota.poznamka);
novy^.dalsi:=prvni;
prvni:=novy;
end;
writeln();
end;

procedure vypis;
var
akt:UkNaZaznam;
begin
akt:=prvni;
if akt<>nil then
begin

writeln('Vypis databaze:');
writeln('--------------');
writeln;
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');

repeat
writeln(akt^.hodnota.nazev,akt^.hodnota.autor:20,akt^.hodnota.signatura:15,akt^.hodnota.poznamka:15);
akt:=akt^.dalsi;
until akt=nil;
writeln();
akt:=prvni;
end
else
writeln('Databaze je prazdna.');
writeln();
end;
procedure uloz(var soubor:string);
var
f:file of zaznam;
akt:UkNaZaznam;


begin

assign(f, soubor);
rewrite(f);
akt:=prvni;
repeat
write(f,akt^.hodnota);
akt:=akt^.dalsi;

until akt=nil;
writeln();
akt:=prvni;
close(f);
writeln('Databaze je ulozena do souboru ',soubor);
writeln();
end;

procedure nacti(var soubor:string);
var
f:file of zaznam;
kniha:zaznam;
akt:UkNaZaznam;

begin
akt:=prvni;
if (akt<> nil) then
begin
while akt <> nil do
begin
prvni:=akt^.dalsi;
dispose(akt);
akt:=prvni;
end;
end;
assign(f, soubor);
{$I-}
reset(f);
if ioresult <> 0 then begin
writeln('Soubor neexistuje!!!');
{$I+}
end
else
begin
while not eof(f) do
begin
new(akt);
read(f,kniha);
akt^.hodnota.nazev:=kniha.nazev;
akt^.hodnota.autor:=kniha.autor;
akt^.hodnota.signatura:=kniha.signatura;
akt^.hodnota.poznamka:=kniha.poznamka;
akt^.dalsi:=prvni;
prvni:=akt;
end;
close(f);
writeln('Databaze je nactena ze souboru ',soubor);
end;
writeln();
end;

procedure vyhledej(var key1:string);
var
akt,hledany:UkNaZaznam;
begin
akt:=prvni;

while ((akt<>nil) and ((Pos(key1,akt^.hodnota.nazev)=0)))
do
begin
akt:= akt^.dalsi;
end;
hledany:=akt;
if (hledany<>nil) then
begin
writeln('Hledany zaznam:');
writeln();
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');
writeln(hledany^.hodnota.nazev,hledany^.hodnota.autor:20,hledany^.hodnota.signatura:15,hledany^.hodnota.poznamka:15);
writeln();
end
else writeln('Zaznam nenalezen');
writeln();
end;


procedure oprav;

var
klic1:string;
akt,pom,hledany: UkNaZaznam;
begin
write('Zadej autora: ');
readln(klic1);
akt:=prvni;
pom:=nil;
while ((akt<>nil) and (akt^.hodnota.autor<>klic1)) do
begin
pom:=akt;
akt:= akt^.dalsi;
end;
hledany:=akt;
if hledany=nil then
begin
writeln('Zaznam nenalezen');
akt:=nil;
end
else
begin
if (hledany=prvni) then
begin

writeln('Zaznam urceny k oprave:');
writeln();
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');
writeln(hledany^.hodnota.nazev,hledany^.hodnota.autor:20,hledany^.hodnota.signatura:15,hledany^.hodnota.poznamka:15);

writeln('Puvodni nazev knihy: ',hledany^.hodnota.nazev);
write('Novy nazev knihy: ');
readln(prvni^.hodnota.nazev);
writeln('Puvodni autor knihy: ',hledany^.hodnota.autor);
write('Novy autor: ');
readln(prvni^.hodnota.autor);
writeln('Puvodni signatura: ',hledany^.hodnota.signatura);
write('Nova signatura: ');
readln(prvni^.hodnota.signatura);
writeln('Puvodni poznamka: ',hledany^.hodnota.nazev);
write('Nova poznamka: ');
readln(prvni^.hodnota.poznamka);

end
else
begin

writeln('Zaznam urceny k oprave:');
writeln();
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');
writeln(hledany^.hodnota.nazev,hledany^.hodnota.autor:20,hledany^.hodnota.signatura:15,hledany^.hodnota.poznamka:15);


writeln('Puvodni nazev knihy: ',hledany^.hodnota.nazev);
write('Novy nazev knihy: ');
readln(pom^.hodnota.nazev);
writeln('Puvodni autor knihy: ',hledany^.hodnota.autor);
write('Novy autor: ');
readln(pom^.hodnota.autor);
writeln('Puvodni signatura: ',hledany^.hodnota.signatura);
write('Nova signatura: ');
readln(pom^.hodnota.signatura);
writeln('Puvodni poznamka: ',hledany^.hodnota.nazev);
write('Nova poznamka: ');
readln(pom^.hodnota.poznamka);

end;
end;
writeln();
end;

procedure zrus(var key:string);

var

akt,pom,hledany: UkNaZaznam;
begin

akt:=prvni;
pom:=nil;
while ((akt<>nil) and (akt^.hodnota.signatura<>key)) do
begin
pom:=akt;
akt:= akt^.dalsi;
end;
hledany:=akt;
if hledany=nil then
begin
writeln('Zaznam nenalezen');
akt:=nil;
end
else
begin
if (hledany=prvni) then
begin
prvni:=prvni^.dalsi;
dispose(hledany);
writeln('Tento zaznam bude zrusen:');
writeln();
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');
writeln(hledany^.hodnota.nazev,hledany^.hodnota.autor:20,hledany^.hodnota.signatura:15,hledany^.hodnota.poznamka:15);
end
else
begin
pom^.dalsi:=hledany^.dalsi;
writeln('Tento zaznam bude zrusen:');
writeln();
writeln('nazev knihy | autor | signatura | poznamka' );
writeln('-----------------------------------------------------------');
writeln(hledany^.hodnota.nazev,hledany^.hodnota.autor:20,hledany^.hodnota.signatura:15,hledany^.hodnota.poznamka:15);
dispose(hledany);
end;
end;
writeln();
end;





begin
writeln(' ');
writeln('*******************************Knihovna*******************************');
writeln(' ');
prvni:=nil;
repeat
writeln('Menu:');
writeln('1: Vlozit zaznam');
writeln('2: Vypis zaznamu');
writeln('3: Uloz zaznamy do souboru');
writeln('4: Nacti zaznamy ze souboru');
writeln('5: Vyhledani zaznamu po zadani retezc vyskytujiciho se v nazvu knihy');
writeln('6: Oprava zaznamu po zadani autora');
writeln('7: Zruseni zaznamu po zadani signatury');
writeln('8: Konec');
writeln();

writeln('Zadej cislo akce: ');
readln(akce);
case akce of 1:vloz;
2:vypis;
3:begin
write('Zadej nazev souboru: ');
readln(jmsouboru);
uloz(jmsouboru);
end;
4:begin
write('Zadej nazev souboru: ');
readln(jmsouboru);
nacti(jmsouboru);
end;
5:
begin
write('Zadej nazev knihy (mozno i cast retezce): ');
readln(klic1);
vyhledej(klic1);
end;
6:oprav;
7:begin
write('Zadej signaturu: ');
readln(klic);
zrus(klic);
end;
8:;
else writeln('Tahle akce neni definovana, '+
'zadavejte pouze cisla od 1 do 8.');
end;
until akce=8;
end.

Nahlásit jako SPAM
IP: 89.203.206.–
nervak0
Věrný člen
4. 6. 2011   #10
-
0
-

Prostě otestuj všechny položky, operátor pro "nebo" je OR. A zároveň by to asi mělo vyhledat všechny odpovídající záznamy, nejen první. Takže nějak takhle:

akt := prvni;

while akt <> nil do begin
if JeVeJmeneAutora or JeVNazvuKnihy or ... then
vypisknihu;
akt := akt^.dalsi;
end;

Nahlásit jako SPAM
IP: 213.211.51.–
nervak0
Věrný člen
4. 6. 2011   #11
-
0
-

A ještě pár připomínek.

V uloz používáš prvni bez kontroly. V nacti ho zase zbytečně testuješ dvakrát (if+while).

V nacti asi nemusíš přiřazovat hodnoty po jedné, mělo by fungovat hodnota := kniha.

V oprav je asi zbytečné vypisovat původní hodnoty při načítání nových, když je všechny vypisuješ hned předtím. A zbytečně tam to načítání máš dvakrát, je jedno jestli je ten záznam první.

Ve zrus taky nemusíš vypisovat ten záznam pro obě varianty zvlášť.

A když je tam to vypisování tolikrát, tak by se mohlo hodit do samostané procedury. U některých ifů by se dalo hned ukončit proceduru (exit) místo zbytečného zanořování zbytku do else, a nakonec jsem tam viděl několik zbytečných přiřazení, ale na tom celkem nezáleží.

Málem bych zapoměl... Když je tam typ zaznam, tak je trochu matoucí, když UkNaZaznam není ukazatel na zaznam :)

Nahlásit jako SPAM
IP: 213.211.51.–
Mircosoft+1
Věrný člen
6. 6. 2011   #12
-
0
-

Jo jo, ukládání v téhle podobě může skončit v dost ošklivé a s trochou smůly i nekonečné smyčce. Ale stačí místo Repeatu použít While a bude to v pohodě.

Ještě pár dalších drobností:

- Při načítání radši otoč pořadí: nejdřív zkus otevřít soubor a až teprve jestli se to povede, tak smaž seznam. Na funkci programu to vliv nemá, ale na uživatelovy nervy jo :-).

- Opravování: přijde mi dost divné hledat záznam k opravení podle jména autora. Neměla by to být spíš signatura nebo aspoň název knihy?

- Při hledání je dobré si zkoumané texty dočasně převést na velká písmena, aby uživatel nemusel zadávat slova přesně tak, jak jsou v databázi uložena. Šlo by to třeba takhle:

procedure vyhledej...
...
key1:=NaVelka(key1);
...
while ... and ((Pos(key1,NaVelka(akt^.hodnota.nazev))=0)) ...
...

Funkce NaVelka by vzala zadaný řetězec, prošla by ho znak po znaku, na každý by použila standardní funkci Upcase a výsledek by předala v návratové hodnotě.

Ale jestli to nemáš v zadání, tak to není nutné.

- Nevím jestli to dělá při vkládání fórum nebo jestli opravdu píšeš takhle bez odsazování a s vynecháváním řádků v dost neobvyklých místech. Jestli ti nedělá problémy se v tom vyznat, tak OK. Ale možná by stálo za to myslet na ty, co ti pak budou hotovou práci kontrolovat, a co nejvíc jim to usnadnit ;-).

Nahlásit jako SPAM
IP: 141.202.248.–
Chceš-li lepší odpověď, polož lepší otázku.
Moje stránka.
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 1 host

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý