Funkcja wywoływana dwa razy daje te same parametry (błąd) + procedura która sumuje dwie tablice

0

program ma działać następująco:

  • prosi użytkownika o podanie zakresu liczb jakie mają być wpisywane do tablic;
  • funkcja wczytajTablice generuje losowe wartości z podanego zakresu i wpisuje je do tablic;
  • procedura pokazTablice wyświetla zawartość tablicy na ekranie podanej jako parametr;
  • procedura zsumujTablice pobiera dwie tablice (tab1 i tab2) i oblicza elementy trzeciej (tab3) jako sumę elementów dwóch wcześniej wymienionych.

Do tej pory napisałem takie procedury i funkcje:

function wczytajtablice(var z:integer):typtablica;
var
 i:integer;

 begin
  randomize;
  for i:=0 to n-1 do
  result[i]:=random(z);
 end;

procedure pokaztablice(tablica:typtablica);
var
 i:integer;

 begin
   writeln('--------------------------');
   i:=0;
   repeat
     write('e[',i+1:2,']=',tablica[i]:4,'   ');
     writeln();
     i:=i+1;
   until i>=n;
 end;                 

kod wygląda następująco:

begin


  write('Podaj zakres liczb: ');
  readln(zakres);

  tab1:=wczytajTablice(zakres);
  tab2:=wczytajTablice(zakres);

  pokazTablice(tab1);
  pokazTablice(tab2);

  zsumujTablice(tab1,tab2,tab3);
  pokazTablice(tab3);

  readln;
end.     

Do tej pory natknąłem się na pierwszy problem, a mianowicie gdy wywołuje się procedura "pokaztablice" to pokazuje ona dwie identyczne tablice.
Co trzeba zrobić, aby wyświetlane tablice były różne?
Jak powinien wyglądać kod procedury "zsumujTablice", aby ta dodała do siebie elementy dwóch tablic?

0

1) co to jest typtablica? Gdzieś sobie to musiałeś zdefiniować, bo "raczej" nie jest to żaden typ wbudowany w język, ale nie wkleiłeś tutaj tej definicji.
2) wiem, że to jest mały programik ćwiczeniowy, ale mógłbyś poprawić nazwy zmiennych. Teraz może pamiętasz czym są Z oraz I, ale za pewien czas to się pomiesza. Nazwy powinny być opisowe - tak, żeby ktokolwiek, kto siądzie do tego programu, mógł się od razu połapać, za co odpowiada dana zmienna.
3) nie widzę deklaracji zmiennych tab1, tab2 oraz n.

Czy możesz wkleić cały kod, a nie tylko fragmenty? Chyba przeoczyłeś kilka fragmentów, które mogą mieć znaczenie.
Napisz też w czym piszesz - Delphi, Lazarus, FPC?

1
  1. Zakres to a..b a nie jedna liczba. Trzeba zmienić opis z zakresu od 0 do ... albo wprowadzić dolną i górną granicę zakresu.
  2. Jeśli zakres jest to X, to random robisz z X+1.
  3. Gdzie masz zmienną 'n' bo odwołujesz się do niej a nie wiadomo co to jest.
  4. To co pisał @cerrato - co to typtablica? Co by to nie było to nie masz deklaracji rozmiaru tablic.
  5. Sumujesz podobnie do wczytywania (rozmiar tablic musi być oczywiście taki sam), czyli iteracja po rozmiarze i jak result będzie trzecia tablica a po prawej suma dwóch wejściowych.
  6. Podaj pełny kod bo z tego co podesłałeś raczej nic nie wychodzi.
0

Używam Lazarusa... Cały kod mam w trzech modułach dlatego tak to wkleiłem sorka... Poniżej mogłem namieszać w kolejności.


uses
  Classes, SysUtils, defunit,fununit2;

function wczytajtablice(var zakres1:integer):typtablica;
procedure pokazTablice(tablica: typtablica); 

implementation
function wczytajtablice(var zakres1:integer):typtablica;
var
 i:integer;

 begin
  randomize;
  for i:=0 to n-1 do
  result[i]:=random(zakres1)+1;
 end;

procedure pokaztablice(tablica:typtablica);
var
 i:integer;

 begin
   writeln('--------------------------');
   i:=0;
   repeat
     write('e[',i+1:2,']=',tablica[i]:4,'   ');
     writeln();
     i:=i+1;
   until i>=n;
 end;                         

const
n=10; 

type
typtablica = array[0..n-1] of integer;

var
  tab1,tab2,tab3:typTablica;
  zakres:integer;

begin

  write('Podaj zakres liczb: ');
  readln(zakres);

  tab1:=wczytajTablice(zakres);
  tab2:=wczytajTablice(zakres);

  pokazTablice(tab1);
  pokazTablice(tab2);

  zsumujTablice(tab1,tab2,tab3);
  pokazTablice(tab3);

  readln;
end.                 

tak to wygląda no i zamiast wyświetlać dwie różne tablice wyświetla to samo.

2
brotomasz napisał(a):

Co trzeba zrobić, aby wyświetlane tablice były różne?

Randomie woła się raz na cały program, więc najlepiej będzie, jeśli przeniesiesz wywołanie tej procedury go głównego bloku kodu, na sam jego początek. A Ty wołasz ją tuż przed każdym losowaniem, dlatego w tablicy lądują takie same wartości.

Poza tym nazwa funkcji wczytajtablice kłamie o przeznaczeniu tej funkcji, bo służy ona do losowania zawartości tablicy, a nie jej wczytywania. Zresztą te nazwy są złe – użyj angielskich i stosuj się do przyjętej konwencji.

Jak powinien wyglądać kod procedury "zsumujTablice", aby ta dodała do siebie elementy dwóch tablic?

Np. tak:

type
  TMyArray = array [0 .. n - 1] of Integer;
  
  procedure SumArrays(const ALeft, ARight: TMyArray; out ADest: TMyArray);
  var
    I: Integer;
  begin
    for I := Low(ADest) to High(ADest) do
      ADest[I] := ALeft[I] + ARight[I];
  end;
0

@furious programming: pozwolę sobie się nie zgodzić. Funkcja RANDOMIZE wrzuca do RANDSEED wartość wyznaczoną ma podstawie aktualnego zegara (https://www.freepascal.org/docs-html/rtl/system/randomize.html). Nie ma niczego złego w wywołaniu jej ile razy ma się ochotę.

Fakt, że wyniki są takie same jest jakby skutkiem ubocznym wywołania RANDOMIZE kilka razy - po prostu czas pomiędzy wywołaniami jest tak krótki, że do RANDSEED prawdopodobnie trafia dokładnie taka sama wartość. Dlatego - w tym przypadku masz rację i wystarczyło by (a nawet by było lepiej) wywołać to raz na samym początku, ale nie zmienia to faktu, że nie ma niczego złego w inicjowaniu generatora liczb losowych częściej (o ile się rozumie jak działa ten mechanizm i jak się powinno go używać).

0
cerrato napisał(a):

Nie ma niczego złego w wywołaniu jej ile razy ma się ochotę.

Fakt, że wyniki są takie same jest jakby skutkiem ubocznym wywołania RANDOMIZE kilka razy - po prostu czas pomiędzy wywołaniami jest tak krótki, że do RANDSEED prawdopodobnie trafia dokładnie taka sama wartość.

Te dwa zdania są ze sobą sprzeczne – albo nie ma niczego złego, albo są paskudne skutki uboczne. Tak więc sam sobie odpowiedziałeś na pytanie, dlaczego Randomize nie powinien być wołany wielokrotnie. A to że można tak zrobić, wynika wyłącznie ze specyfiki ustalania ziarna – to zwykła procedura, która nie jest w żaden sposób kontrolowana.

0

Czyli nie da się zrobić tak żeby tablice były różne? Może jakieś polecenie w procedurze, które zatrzymuje program na 1 sekundę

0

"Te dwa zdania są ze sobą sprzeczne" - nieladnie jest wyrywać fragment wypowiedzi z kontekstu i to w dodatku w taki sposób, żeby przekręcić jej wymowe.

Na końcu dodałem przecież, że można używać tego wiele razy, pod warunkiem że się rozumie jak to działa.

1

Przecież Ci napisałem – wywal Randomize z funkcji wczytajtablice i dodaj wywołanie tej procedury na samej górze głównego bloku kodu, tak abyś miał pewność, że wołana jest tylko raz:

function wczytajtablice(var z: integer): typtablica;
var
  i: integer;
begin
  for i:=0 to n-1 do
    result[i]:=random(z);
end;

{..}

begin
  randomize;

  write('Podaj zakres liczb: ');
  readln(zakres);

  {..}

Poza tym sformatuj sobie ten kod – jest nieco nieczytelny i chaotyczny.


cerrato napisał(a):

"Te dwa zdania są ze sobą sprzeczne" - nieladnie jest wyrywać fragment wypowiedzi z kontekstu i to w dodatku w taki sposób, żeby przekręcić jej wymowe.

Gdzie wyrwałem tę wypowiedź z kontekstu? Z pierwszego cytowanego paragrafu usunąłem definicję i działanie tej funkcji, bo nie ma ona tutaj większego znaczenia. Poza tym znam jej działanie, więc nie musisz mi tego opisywać.

W jednym paragrafie piszesz, że nie ma problemu w wywoływaniu jej wielokrotnie, a w drugim, że jednak jest problem powtarzalności emitowanych liczb. To się nie klei.

Na końcu dodałem przecież, że można używać tego wiele razy, pod warunkiem że się rozumie jak to działa.

Nie wiem czy są jakiekolwiek praktyczne powody, dla krótych wielokrotne wołanie Randomize ma sens – nie znam ani jednego. W końcu bez względu na liczbę wywołań, funkcja Random działać będzie z taką samą losowością, a jedyną różnicą będzie powtarzalność wyników, co zaletą wcale nie jest. W końcu te procedurki/funkcje mają zapobiegać powtarzalności, a nie ją powodować.

0

Dziękuję, działa, działa też z użyciem Delay(500); w kodzie funkcji...
Nie wiem jak napisać procedurę która zsumuje elementy tablicy, to chyba proste, ja napisałem coś takiego i nie działa:

procedure zsumujTablice(tablica1,tablica2,tablica3:typtablica);
var
 i:integer;

 begin
  for i:=0 to n-1 do
  tablica3[i]:=tablica1[i]+tablica2[i];
 end; 
0

Przecież @furious programming kilka postów wyżej dał Ci gotowa funkcje która sumuje tablice...

0
brotomasz napisał(a):

Dziękuję, działa, działa też z użyciem Delay(500); w kodzie funkcji...

Kompletnie bez sensu.

Nie wiem jak napisać procedurę która zsumuje elementy tablicy, to chyba proste, ja napisałem coś takiego i nie działa:

procedure zsumujTablice(tablica1,tablica2,tablica3:typtablica);
var
 i:integer;

 begin
  for i:=0 to n-1 do
  tablica3[i]:=tablica1[i]+tablica2[i];
 end; 

Działa i poprawnie wypełnia komórki trzeciej tablicy. Tyle że argument tablica3 jest lokalną kopią przekazanej macierzy, więc jej zmodyfikowana zawartość dostępna jest tylko wewnątrz tej procedury.

Jeśli chcesz, aby aktualizowana była tablica przekazana do tej procedury, czyli aby zmiany były widoczne poza tą procedurą to użyj modyfikatora var lub out. W tym przypadku wystarczy out, dlatego że tablica3 służy wyłącznie do modyfikacji.

0

dziękuję pięknie Panowie... Już wszystko śmiga i hula :D

0

Wyrzuć ten Delay i przerób kod tak, aby raz wołał Randomize.

Sam zawsze jawnie wywołuję tę procedurę na początku w głównym bloku kodu. Jeśli chcę wiedzieć czy faktycznie jej użyłem – sprawdzam początek tego bloku. Jeżeli jej tam nie ma to mam 100% pewności, że w całym projekcie nie została użyta i mogę ją śmiało dopisać.

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