Przetwarzanie danych w pliku rekordowym

0

Witam, mam zrobić na informatykę taki program:
W pliku rekordowym o nazwie 'dane.dat' umieszczono ciąg liczb całkowitych których wartości w założeniach miały być kolejno: większe i mniejsze od zera (równe zeru potraktować jak mniejsze). Napisać procedure lub funkcję z których:

a) pierwsza, sprawdzi czy rzeczywiście tak jest,
b) druga, przepisze do n elementowej tablicy A liczby dodatnie (n należy podać jako argument, proces przerwać po znalezieniu n-tego elementu).

Napisałem coś takiego i procedura z podpunktu b działa ale z funkcją z podpunktu a mam problem. A mianowicie funkcja działa dobrze jeśli wprowadzam parzystą ilość liczb, a dla nieparzystej ilości nie chce działać. Funkcja nazywa się Sprawdź. Pomoże ktoś??
Pisałem ten program w Lazarusie IDE v1.6.

program zestaw1_poprawka3;
uses Crt;
type Tplik=file of integer;
     Ttab=array[1..100] of integer;
var p:Tplik;
    A:Ttab;
    n:byte;
{...........}
procedure Wprowadz(var p:Tplik; n:integer);
var x:integer;
    i:integer;
begin
Rewrite(p);
if n>=100 then exit;
for i:=1 to n do
    begin
    write(i,' znak: '); readln(x);
    write(p,x);
    end;
Close(p);
end;
{............}
function Sprawdz(var p:Tplik):boolean;              
var x,y:integer;
begin
Reset(p);
if not eof(p) then
read(p,x);
while not eof(p) do
begin
read(p,y);
if ((x>0) and (y<=0)) or ((x<=0) and (y>0)) then
Sprawdz:=true
else
Sprawdz:=false;
end;
Close(p);
end;
{..........}
procedure Wyswietl(var p:Tplik);
var x:integer;
begin
Reset(p);
while not eof(p) do
begin
     read(p,x);
     writeln(x:3);
     end;
Close(p);
end;
{................}
procedure Przepisz(var p:Tplik; var A:Ttab; var n:byte);
var x:integer; i:integer;
begin
Reset(p);
i:=0;
while not eof(p) do
begin
if n>=100 then break;
read(p,x);
if x>0 then
begin
i:=i+1;
A[i]:=x;
end;
end;
Close(p);
end;
{................}
procedure Wyswietl_tab(var n:byte; var A:Ttab);
var i:integer;
begin
for i:=1 to n do
    write(A[i]:5,' ');
end;
{...........}
begin
  ClrScr;
  write('Ile bedzie znakow: '); readln(n);
  Assign(p,'dane.dat');
  Wprowadz(p,n);
  writeln;
  Sprawdz(p);
  Writeln(Sprawdz(p));
  Wyswietl(p);
  writeln;
  Przepisz(p,A,n);
  writeln('Przepisana tablica: ');
  Wyswietl_tab(n,A);
  Readkey;
end.
0

Pomoże ktoś??

0
program zestaw1_poprawka3;

uses Crt;

type
  Tplik = file of integer;
  Ttab = array [1 .. 100] of integer;

var
  p: Tplik;
  A: Ttab;
  n: byte;

  { ........... }
procedure Wprowadz(var p: Tplik; n: integer);
var
  x: integer;
  i: integer;
begin
  Rewrite(p);
  if n >= 100 then
    exit;
  for i := 1 to n do
  begin
    write(i, ' znak: ');
    readln(x);
    write(p, x);
  end;
  Close(p);
end;

{ ............ }
function Sprawdz(var p: Tplik): boolean;
var
  x, y: integer;
begin
  Reset(p);
  if not eof(p) then
    read(p, x);
  while not eof(p) do
  begin
    read(p, y);
    if ((x > 0) and (y <= 0)) or ((x <= 0) and (y > 0)) then
      Sprawdz := true
    else
      Sprawdz := false;
  end;
  Close(p);
end;

{ .......... }
procedure Wyswietl(var p: Tplik);
var
  x: integer;
begin
  Reset(p);
  while not eof(p) do
  begin
    read(p, x);
    writeln(x:3);
  end;
  Close(p);
end;

{ ................ }
procedure Przepisz(var p: Tplik; var A: Ttab; var n: byte);
var
  x: integer;
  i: integer;
begin
  Reset(p);
  i := 0;
  while not eof(p) do
  begin
    if n >= 100 then
      break;
    read(p, x);
    if x > 0 then
    begin
      i := i + 1;
      A[i] := x;
    end;
  end;
  Close(p);
end;

{ ................ }
procedure Wyswietl_tab(var n: byte; var A: Ttab);
var
  i: integer;
begin
  for i := 1 to n do
    write(A[i]:5, ' ');
end;

{ ........... }
begin
  ClrScr;
  write('Ile bedzie znakow: ');
  readln(n);
  Assign(p, 'dane.dat');
  Wprowadz(p, n);
  writeln;
  Sprawdz(p);
  writeln(Sprawdz(p));
  Wyswietl(p);
  writeln;
  Przepisz(p, A, n);
  writeln('Przepisana tablica: ');
  Wyswietl_tab(n, A);
  Readkey;

end.
0

??

0

aha, ok a może wiesz dlaczego program nie działa poprawnie??

0

Napisałem coś takiego i procedura z podpunktu b działa ale z funkcją z podpunktu a mam problem. A mianowicie funkcja działa dobrze jeśli wprowadzam parzystą ilość liczb, a dla nieparzystej ilości nie chce działać. Funkcja nazywa się Sprawdź.

Jak tak opisujesz problem to nie dziw się, że nie ma chętnych do pomocy.

0

No ok, mój błąd. Mógłby ktoś napisać mi tą funkcje bo próbowałem na różne sposoby a i tak nie działa. Pomoże ktoś?? Albo da jakieś wskazówki jak to napisać??

0

Najpierw wytłumacz mi co ma ten kod:

function Sprawdz(var p: Tplik): boolean;
var
  x, y: integer;
begin
  Reset(p);
  if not eof(p) then
    read(p, x);
  while not eof(p) do
  begin
    read(p, y);
    if ((x > 0) and (y <= 0)) or ((x <= 0) and (y > 0)) then
      Sprawdz := true
    else
      Sprawdz := false;
  end;
  Close(p);
end;

do poniższych wymagań:

W pliku rekordowym o nazwie 'dane.dat' umieszczono ciąg liczb całkowitych których wartości w założeniach miały być kolejno: większe i mniejsze od zera (równe zeru potraktować jak mniejsze).

Jakoś nie widzę korelacji.

0

Masz dwa błędy w funkcji Sprawdz

  • porównujesz kolejne liczby z pierwszą liczbą z pliku
  • rezultatem funkcji jest wynik porównania pierwszej i ostatniej liczby z pliku

Tak bym to widział, pisane z głowy bez sprawdzenia

function Sprawdz(var p: Tplik): boolean;
var
  x, y: integer;
begin
  Sprawdz := true;
  Reset(p);
  if not eof(p) then
    read(p, x);
  while not eof(p) do
  begin
    read(p, y);
    Sprawdz := ((x > 0) and (y <= 0)) or ((x <= 0) and (y > 0));
    if not Sprawdz then
      break;
    x := y;
  end;
  Close(p);
end;
0

@grzegorz_so: jeśli plik jest pusty to taki plik nie spełnia założeń, więc funkcja powinna zwrócić False, a Twoja propozycja zwróci True. Poza tym do ustawiania wartości zwracanej służy zmienna Result, więc należy z niej korzystać, bo jest to dużo bardziej czytelne. Nazwy funkcji używało się trzydzieści lat temu i nie ma sensu dziś uczyć tak starych technik. Już nie wspomnę o tym, że funkcja powinna pobierać ścieżkę pliku, a nie zmienną plikową.

Moja propozycja:

type
  TIntFile = file of Integer;

  function CheckIntFile(const AFileName: String): Boolean;
  var
    IntFile: TIntFile;
    A, B: Integer;
  begin
    AssignFile(IntFile, AFileName);
    Reset(IntFile);
    try
      if FileSize(IntFile) = 0 then Exit(False);

      Read(IntFile, A);

      while not EoF(IntFile) do
      begin
        Read(IntFile, B);

        if ((A > 0) and (B > 0)) or ((A <= 0) and (B <= 0)) then
          Exit(False);

        A := B;
      end;

      Result := True;
    finally
      CloseFile(IntFile);
    end;
  end;
0

sprawdziłem obydwie opcje i nie działają one poprawnie ale dzięki za pomoc

0

Tak? Ciekawe, bo sprawdzałem na różnych danych i kod działa poprawnie. W takim razie podaj kilka informacji:

  • jaką wartość ma zwrócić funkcja, jeśli plik jest pusty,
  • jaką wartość ma zwrócić funkcja, jeśli w pliku jest jedna liczba,
  • przykładowy ciąg liczb (co najmniej dwie), który nie spełnia założeń,
  • przykładowy ciąg liczb (co najmniej dwie), który spełnia założenia.

Wtedy zobaczymy kto ma rację i czy podany kod jest prawidłowy czy nie.

Poza tym założenia nie gwarantują, że w pliku znajduje się prawidłowy ciąg liczb, więc zwrócenie przez funkcję wartości False nie oznacza z góry błędnego działania algorytmu.

0

Czyli że jak napisałem ten warunek taki jak ty if ((A > 0) and (B > 0)) or ((A <= 0) and (B <= 0)) then i wtedy funkcja jest "False" a jeśli nie to "True" i jak wprowadzę kilka liczb i wyskoczy mi że jest źle (a z warunku wychodzi że powinno być dobrze) to nie znaczy że jest źle. I gdybym napisał coś takiego na sprawdzianie na kartce a nie w programie to bym zaliczył, bo zamysł jest dobry??

function Sprawdz(var p:Tplik):boolean;
var x,y:integer;
begin
Reset(p);
Sprawdz:=true;
if not eof(p) then
read(p,x);
while not eof(p) do
begin
read(p,y);

if ((x > 0) and (y > 0)) or ((x <= 0) and (y <= 0))   then
begin Sprawdz:=false; exit; end;


end;
 x:=y;
Close(p);
end;  
0

Nic z tego bełkotu nie da się zrozumieć, więc albo skup się i napisz sensownie o co chodzi, albo zakończmy ten wątek. Poza tym podany kod jest nieprawidłowy i na pewno nie będzie zwracał prawidłowych wyników.

0

@furious programming:

jeśli plik jest pusty to taki plik nie spełnia założeń, więc funkcja powinna zwrócić False, a Twoja propozycja zwróci True.

pewnie masz trochę racji, ale warunek zadania nie określa wprost co w sytuacji gdy nie ma pliku albo jest pusty albo zawiera tylko jedną liczbę .. True czy False ?

W pliku rekordowym o nazwie 'dane.dat' umieszczono ciąg liczb całkowitych których wartości w założeniach miały być kolejno:....

Więc założenie jest takie że w pliku coś jednak jest ...

A co do sposobu zapisu wyniku funkcji to myślę że każdy sposób akceptowalny przez kompilator Delphi (Lazarus) jest niemal równie dobry i czytelny.

Zapis

exit(coś_tam)

jest może nieco bardziej zwięzły bo w jednej instrukcji zastępuje dwie

 result:= coś_tam;
 exit;

Myślę że dyskusja o formie zapisu rezultatu funkcji jest czysto akademicka i nic nie wnosi do prawidłowości działania samego algorytmu .

Poza tym do ustawiania wartości zwracanej służy zmienna Result, więc należy z niej korzystać, bo jest to dużo bardziej czytelne.

więc dlaczego zamiast zapisu result=.... używasz Exit(False); ?

Mój post dotyczył głównie błędu w algorytmie polegającym na porównywaniu kolejnych wartości liczbowych z pliku zawsze do pierwszej liczby z pliku a nie do poprzedniej liczby

@gosc123456789:

Czyli że jak napisałem ten warunek taki jak ty if ((A > 0) and (B > 0)) or ((A <= 0) and (B <= 0)) then i wtedy funkcja jest "False" a jeśli nie to "True" i jak wprowadzę kilka liczb i wyskoczy mi że jest źle (a z warunku wychodzi że powinno być dobrze) to nie znaczy że jest źle. I gdybym napisał coś takiego na sprawdzianie na kartce a nie w programie to bym zaliczył, bo zamysł jest dobry??

jeśli oczekujesz pomocy to napisz to jeszcze raz w prosty i zrozumiały sposób

0

pewnie masz trochę racji, ale warunek zadania nie określa wprost co w sytuacji gdy nie ma pliku albo jest pusty albo zawiera tylko jedną liczbę .. True czy False ?

Jeśli założenia nie określają pewnych aspektów to należy wziąć problem na logikę. Funkcja ma sprawdzać, czy w pliku znajduje się prawidłowy ciąg liczb - pusty plik to brak jakiegokolwiek ciągu, więc nie spełnia założeń. Jeśli w pliku znajduje się tylko jedna liczba to plik spełnia założenia, dlatego że zawiera ciąg liczb (równy jednemu elementowi, więc nie jest to plik pusty) oraz zawiera prawidłowy ciąg liczb, bo nie łamie zasady, iż kolejny wyraz ciągu jest po przeciwnej stronie osi (nie ma kolejnego wyrazu, więc zasada nie zostaje złamana).

Jeśli plik zawierający tylko jedną liczbę też ma być traktowany jako nieprawidłowy to wystarczy zmiana operatora i literału w jednym warunku:

if FileSize(IntFile) < 2 then Exit(False);

Ktoś kto będzie sprawdzał poprawność kodu, na pewno użyje do tego co najmniej kilku plików testowych, aby sprawdzić czy rezultaty zwracane przez funkcję są prawidłowe dla kilku przypadków. Istnieje kilka sposobów na wyłożenie tej funkcji, więc przed każdym z nich trzeba się zabezpieczyć.

A co do sposobu zapisu wyniku funkcji to myślę że każdy sposób akceptowalny przez kompilator Delphi (Lazarus) jest niemal równie dobry i czytelny.

Może być akceptowalny, ale tylko i wyłącznie dlatego, że jest składniowo poprawny (kompilowalny) i zapewnia wsteczną kompatybilność (jeśli jest ona wymagana). Natomiast nie powinno być sugerowane, bo jest to rozwiązanie przestarzałe, na które łatką zwiększającą czytelność było dodanie niejawnej zmiennej Result. Ta zmiena istnieje w każdej funkcji, więc sprawdzając co dana funkcja może zwrócić, odruchowo szuka się właśnie tej zmiennej, a nie wystąpień nazwy funkcji. A już całkowity misz-masz powstaje w funkcjach rekurencyjnych.

Tak więc nazwy funkcji jako nośnika wartości rezultatu powinno się używać tylko wtedy, gdy kod ma być skompilowany starym kompilatorem, który zmiennej Result nie rozpoznaje (np. TP7). Nikt już nie pisze w ten sposób kodu, więc należy uczyć (się) najnowszych trendów, aby kod był zrozumiały dla wszystkich, a nie tylko dla autora. Takie jest moje zdanie - nikt nie musi się z nim zgadzać.

Zapis

exit(coś_tam)

jest może nieco bardziej zwięzły bo w jednej instrukcji  zastępuje dwie 

```dephi

result:= coś_tam;
exit;

No nie dwie, a wręcz cztery linijki. Jeżeli po spełnieniu danego warunku ma zostać określona i zwrócona jakaś wartość, a funkcja przerwana, to Exit z parametrem zajmie tylko jedną linijkę. Natomiast jeśli by użyć starodawnej konstrukcji to oprócz przypisania wartości do Result lub nazwy funkcji i wywołania Exit, trzeba zgrupować te instrukcje za pomocą bloku begin end. Jedna instrukcja może nie być zgrupowana, ale dwie już muszą.

W "naszym" problemie, jeśli warunek zostanie spełniony, funkcja ma zwrócić False i zakończyć swoje działanie - nic więcej. Dlatego najlepszym rozwiązaniem w tym przypadku jest właśnie skorzystanie z Exit z parametrem. Tym bardziej że kod napisany jest w taki sposób, aby wartość zmiennej Result ustalana była dopiero po sprawdzeniu zawartości pliku.

Pascal ma wystarczająco rozwlekłą składnię i nie należy jeszcze bardziej jej rozciągać. Współczesne dialekty (już od dawna) mają nieco lukru składniowego, pozwalającego na skracanie kodu. A im mniej kodu, tym mniej czasu potrzeba na jego analizę.

Mój post dotyczył głównie błędu w algorytmie polegającym na porównywaniu kolejnych wartości liczbowych z pliku zawsze do pierwszej liczby z pliku a nie do poprzedniej liczby

I ten błąd nadal jest powielany przez pytacza - przepisanie liczby z jednej zmiennej do drugiej wpakował poza pętlę :]

0

chodzi mi o to że jeśli napisałbym taką funkcje na sprawdzianie, który pisałbym na kartce papieru i oceniany byłby tok rozumowania to zaliczyłbym sprawdzian czy nie??
według was, jeśli mielibyście oceniać całą procedure to dostałbym za to 50% punktów??
chodzi mi o ten kawałek moich wypocin:

function Sprawdz(var p:Tplik):boolean;
var x,y:integer;
begin
Reset(p);
Sprawdz:=true;
if not eof(p) then
read(p,x);
while not eof(p) do
begin
read(p,y);
 
if ((x > 0) and (y > 0)) or ((x <= 0) and (y <= 0))   then
begin Sprawdz:=false; exit; end;
 
end;
 x:=y;
Close(p);
end;
0

według was, jeśli mielibyście oceniać całą procedure to dostałbym za to 50% punktów??

Przecież ta funkcja nie działa prawidłowo, więc co to oceniać? Kod który nie spełnia założeń i zwraca złe wyniki (co wynika z braku wiedzy na temat danego języka), dla mnie jest kodem bezużytecznym, nie podlegającym ocenie. Do tego jego formatowanie jest wybitnie tragiczne, znacząco obniżające czytelność kodu, co z kolei jest wynikiem niedbalstwa i braku znajomości choćby podstaw dotyczących pisania czytelnego kodu.

Ja rozumiem, że chodzi o głupią kartkówkę czy sprawdzian w szkole, ale to nie zmienia faktu, że kod nie spełnia założeń. Dotarłeś może do połowy drogi ku poprawnemu rozwiązaniu. Ale to tyle - jeszcze dużo brakuje, aby funkcja działała prawidłowo.

0

aha ok dzięki za pomoc

1 użytkowników online, w tym zalogowanych: 0, gości: 1