Macierz z pliku w której jest podana ilość wierszy i kolumn

0

Mam taką macierz w pliku jakis.txt

3 4
1 1 2 2
1 1 2 2
1 1 1 1

z czego te dwie pierwsze liczby to są jej wymiary 3x4

Moim zadaniem jest napisanie programu, który będzie liczył sumę dwóch ostatnich wierszy i kolumn tej macierzy oraz iloczyn liczb w wybranym wierszu. Gdy robię to dla pliku który nie ma tam u góry podanych wymiarów wszystko działa. Jednak nie potrafię wykombinować co zrobić, żeby program nie wczytywał mi tego 'nagłówka z wymiarami'. Próbowałam coś takiego:

uses
  SysUtils;
  type tablica=array[1..10,1..10] of integer   ;
  var f:text;
  s,w,k,i,j,iloczyn:word;
  M: tablica;

begin
  assign (f, 'jakis.txt');
  reset (f);
        w:=0;
  while not seekeof (f) do
  begin
  w:=w+1;
         k:=0;
  while not seekeoln (f) do
  begin
  k:=k+1;

  begin

  readln (f, w,k);
  end;
  end;
  readln (f);
  end;
  close (f);
  writeln ('macierz M[',w,',',k,']');


  for i:=w-2 to w do
  begin
  for j:=k-2 to k do

  s:=s+M[i,j];
  end;
  begin
  iloczyn:=0;
  repeat
  writeln ('podaj wiersz do obliczenia iloczynu');
  readln (i);
  until (i>0) and (i<5)  ;

iloczyn:=M[i,1]*M[i,2]*M[i,3]*M[i,4];
  end;

writeln ('suma wynosi',s);
writeln ('iloczyn wynosi',iloczyn);
readln;
writeln ('program napisala blackapple');
readln;

end.

Program się kompiluje, ale za każdym razem podaje, że macierz M to M[1,1] oraz suma i iloczyn wynoszą 0.
Co tu zmienić, żeby zadziałało?

1
  1. Zapoznaj się z pojęciem formatowania kodu: http://4programmers.net/Forum/998482
  2. Wklejaj kod w znaczniki <``code>Tu kod<``/code>
  3. Po kiego ci seekeof i seekeoln skoro na początku podano wymiary?
  4. for j:=k-2 to k do czemu zakładasz że masz zawsze trzy kolumny skoro w pliku jest zapisano ile?
0

Założyłam for j:=k-2 to k, ponieważ na wykładzie zaznaczono nam, że tak trzeba zrobić, aby obliczyć tą nieszczęsną sume 2 ostatnich kolumn i wierszy. To samo z SeekEof i SeekEoln. Pragnę jednak zauważyć, że moje pytanie dotyczyło głównie tego co zrobić, aby wczytało mi tą macierz bez uwzględniania tego pierwszego wiersza dotyczącego jej wymiarów.

0

Wywalić to badziewie i napisać od nowa.

0

uses
  SysUtils;
  type tablica=array[1..10,1..10] of integer   ;
  var f:text;
  s,w,k,i,j,iloczyn:word;
  M: tablica;

begin
  assign (f, 'jakis.txt');
  reset (f);
   readln (f, w,k);

  readln (f);
   close (f);
  writeln ('macierz M[',w,',',k,']');
                              begin
                              s:=s+M[w,k];
                              end;
  begin
  iloczyn:=0;
  repeat
  writeln ('podaj wiersz do obliczenia iloczynu');
  readln (w);
  until (w>0) and (w<5)  ;

iloczyn:=M[w,1]*M[w,2]*M[w,3]*M[w,4];
  end;

writeln ('suma wynosi',s);
writeln ('iloczyn wynosi',iloczyn);
readln;
writeln ('program');
readln;

end.

Wywaliłam, nadal coś jest źle oraz nadal nie rozumiem czemu nie może być k-2 skoro, jeśli dawałam wcześniej do pliku normalną macierz to liczyło poprawnie?

1

Zacznij od rozdzielenia fragmentów programu do osobnych procedur, zamiast pisania wszystkiego na kupę;

Proponuję poniższy schemat, wykorzystujący dynamiczną, dwuwymiarową macierz (a właściwie macierz macierzy, bo tym jest typ TNumbersArr); Ładowanie zawartości pliku do macierzy jest zaimeplementowane w procedurze LoadNumbers, natomiast ShowNumbers dodane jest dla sprawdzenia poprawności i jako przykład odwoływania się do poszczególnych komórek macierzy;

type
  TNumbersArr = array of array of Integer;

  procedure LoadNumbers(const AFileName: String; out ANumbers: TNumbersArr);
  var
    fInput: TextFile;
    intRowsCnt, intColumnsCnt, intRowIdx, intColumnIdx: Integer;
  begin
    AssignFile(fInput, AFileName);
    Reset(fInput);
    try
      Read(fInput, intRowsCnt);
      Read(fInput, intColumnsCnt);

      SetLength(ANumbers, intRowsCnt);

      for intRowIdx := 0 to intRowsCnt - 1 do
      begin
        SetLength(ANumbers[intRowIdx], intColumnsCnt);

        for intColumnIdx := 0 to intColumnsCnt - 1 do
          Read(fInput, ANumbers[intRowIdx][intColumnIdx]);
      end;
    finally
      CloseFile(fInput);
    end;
  end;

  procedure ShowNumbers(const ANumbers: TNumbersArr);
  var
    intRowIdx, intColumnIdx: Integer;
  begin
    for intRowIdx := 0 to High(ANumbers) do
    begin
      for intColumnIdx := 0 to High(ANumbers[intRowIdx]) do
        Write(ANumbers[intRowIdx][intColumnIdx]:2);

      WriteLn();
    end;
  end;

var
  naNumbers: TNumbersArr;
begin
  LoadNumbers('C:\Array.txt', naNumbers);
  ShowNumbers(naNumbers);

  ReadLn();
end.

Teraz pozostało dorobić funkcje wykonujące obliczenia; Dla danych podanych z pierwszego posta, procedura ShowNumbers wyświetli w konsoli poniższą zawartość:

 1 1 2 2
 1 1 2 2
 1 1 1 1

Co oznacza, że dane zostały pomyślnie załadowane z pliku do pamięci.

0

Wszystko pięknie, tylko my w ogóle czegoś takiego nie używaliśmy na ćwiczeniach i nie sądzę, żebym była w stanie to pojąć przed egzaminem, który jest w czwartek, skoro w ogóle raczej mało co z programowania rozumiem

0
  1. Który wiersz/wierszy wg ciebie odpowiadają wczytaniu kolejnych elementów macierzy?
  2. Co to s:=s+M[w,k]; wg ciebie jest? Dodajesz tylko jeden jedyny element.
  3. iloczyn:=0; - przypomnij sobie matmę, iloczyn zerowej ilości elementów wynosi 1 nie 0
  4. iloczyn:=M[w,1]*M[w,2]*M[w,3]*M[w,4]; czemu zakłądasz że będzie akurat cztery kolumny?
0
  1. Zakładam, że pierwszy.
  2. No to miała być suma moich dwóch ostatnich kolumn i wierszy i jak już mówiłam, w pierwotnej wersji mojego programu, w którym nie miałam podanych wymiarów macierzy i dawałam prawie wszystko tak samo jak w tym pierwszym moim komentarzu, z jedną jedyną różnicą taką, że było readln (f, M[w,k]);
  3. Ok, czyli ma być iloczyn:=1?
  4. Zakładam, że będą 4 kolumny, ponieważ w mojej podanej macierzy, mam 4 kolumny a piszę program dla pliku który zawiera konkretnie tą macierz, a nie jakiś uniwersalny.
1
  1. Zakładam, że pierwszy.

Nie zakładaj, a testuj;

  1. Zakładam, że będą 4 kolumny, ponieważ w mojej podanej macierzy, mam 4 kolumny a piszę program dla pliku który zawiera konkretnie tą macierz, a nie jakiś uniwersalny.

Gdyby poproszono Cię o napisanie programu tylko i wyłącznie dla konkretnej liczby komórek macierzy, to pierwszy wiersz w pliku nie zawierałby jej wymiarów;


Nie sądziłem, że aż tak krucho u Ciebie @blackapple z podstawami; Być może błędnie założyłem, że takie elementy jak procedury już braliście; Natomiast obsługa macierzy dynamicznych jest banalnie prosta (wystarczy nadać im rozmiar za pomocą SetLength) i widać znów błędnie sądziłem, że poradzisz sobie z tym;

W takim razie poniżej szablon typowo szkolnego kodu:

type
  TNumbersArr = array [1 .. 10, 1 .. 10] of Integer;

var
  fInput: TextFile;
  naNumbers: TNumbersArr;
  intRowsCnt, intColumnsCnt, intRowIdx, intColumnIdx: Integer;
begin
  { ----- ładowanie liczb z pliku do macierzy --------------- }

  AssignFile(fInput, 'C:\Array.txt');
  Reset(fInput);

  Read(fInput, intRowsCnt);
  Read(fInput, intColumnsCnt);

  for intRowIdx := 1 to intRowsCnt do
    for intColumnIdx := 1 to intColumnsCnt do
      Read(fInput, naNumbers[intRowIdx, intColumnIdx]);

  CloseFile(fInput);

  { ----- kontrolne wyświetlenie zawartości macierzy -------- }

  for intRowIdx := 1 to intRowsCnt do
  begin
    for intColumnIdx := 1 to intColumnsCnt do
      Write(naNumbers[intRowIdx, intColumnIdx]:2);

    WriteLn();
  end;

  { ----- tu dopisz kod wykonujący obliczenia --------------- }

  ReadLn();
end.

Teraz już możesz dodać swój kod do obliczeń; Zmienne intRowIdx i intColumnIdx wykorzystaj do indeksowania pętli podczas sumowania elementów;

PS: Pisz kod czytelnie i unikaj jednoliterowych identyfikatorów; Liczba znaków kodu nie ma większego znaczenia dla samego działającego programu, natomiast ma ogromne znaczenie dla programisty, który musi bez problemu rozumieć kod, bez jego dogłębnej analizy.

PPS: W ramach ciekawostki:

a piszę program dla pliku który zawiera konkretnie tą macierz, a nie jakiś uniwersalny.

Nawet jeśli wymiary macierzy nie będą zapisane w pierwszym wierszu w pliku, to nadal będzie możliwe napisanie uniwersalnego kodu; W takim przypadku będzie można skorzystać właśnie z funkcji SeekEoln do prawidłowego wczytywania liczb z danego wiersza, a także SeekEof do indeksowania głównej pętli, której liczba iteracji będzie równa liczbie wierszy pliku:

intRowIdx := 1;

while not SeekEoF(fInput) do
begin
  intColumnIdx := 1;

  while not SeekEoLn(fInput) do
  begin
    Read(fInput, naNumbers[intRowIdx, intColumnIdx]);
    Inc(intColumnIdx);
  end;
end;

Jednak pozostaje kwestia wielkości macierzy, której rozmiar po szkolnemu jest stały, więc wymiary macierzy w pliku źródłowym nie mogą być większe.

1
  1. uses? WTF?
  2. Kompilator nie potrafi odczytać to co masz w głowie, więc jeżeli nie sumujesz w pętli to sumujesz tylko raz. To: readln(f,M[w,k]); właśnie mogło by czytać kolejne komórki tablicy, ale nie może bo masz mętlik w nazewnictwie.
  3. Nawet koniecznie inaczej nie dasz rady tego iloczynu obliczyć.
  4. Nie, masz podany plik w którym może okazać się 10 kolumn albo 2 kolumny, to co podano na początku to jedynie przykład takiego pliku.
0

Braliśmy procedury, chodziło mi o to, że nie braliśmy macierzy dynamicznych. I nie chodzi mi o to, żeby ktoś mi napisał cały kod (którego nadal do końca nie pojmuje) tylko wytłumaczył jak najbardziej łopatologicznie co ja mam w ogóle zrobić.

PS: jestem na geodezji, nie wiem co przedmiot taki jak programowanie, do tego w Delphi 7 którego nawet ciężko zainstalować jak się nie dysponuje Windowsem XP robi i chcę po prostu to zdać.

_13th_Dragon napisał(a):
  1. uses? WTF? - uses zapewne niepotrzerbnie przekopiowalam z Delphi?

  2. Nie, masz podany plik w którym może okazać się 10 kolumn albo 2 kolumny, to co podano na początku to jedynie przykład takiego pliku = jeśli chodzi o to, że wpisałam sobie array [1..10,1..10] to po prostu moje niedpoatrzenie i to nie jest przykład, tylko po prostu taką macierz mieślimy podną w zadniu i dokładnie niej mieliśmy użyć, więc nadal nie rozumiem

a jeśli chodzi o mój mętlik w nazewnictwie to cóż znowu jest nie tak?

1

Braliśmy procedury, chodziło mi o to, że nie braliśmy macierzy dynamicznych. I nie chodzi mi o to, żeby ktoś mi napisał cały kod (którego nadal do końca nie pojmuje) tylko wytłumaczył jak najbardziej łopatologicznie co ja mam w ogóle zrobić.

W kolejnym swoim poście podałem Ci prostsze rozwiązanie, takie właśnie łopatologiczne, bardziej szkolne;

a jeśli chodzi o mój mętlik w nazewnictwie to cóż znowu jest nie tak?

Nic nie mówiące jednoliterowe identyfikatory; Dopóki nie przeanalizuje się kodu, nie wiadomo czym jest np. magiczna zmienna w;

Natomiast w swoim kodzie pokazałem Ci jak sensownie nadawać nazwy zmiennym; Weźmy na przykład zmienną intRowIdx - prefiks int zgodnie z notacją węgierską oznacza, że zmienna jest typu Integer; Kolejne słówko Row oznacza wiersz, natomiast Idx oznacza indeks; W ogóle nie trzeba przeglądać kodu ani zaglądać do deklaracji tej zmiennej, aby dowiedzieć się, że ta zmienna służy do przechowywania indeksu wiersza w postaci liczby całkowitej;

PS: Wspomniana notacja węgierska nie musi być w ogóle używana do nazywania zmiennych; Niektórzy jej nie lubią, konwencje nazewnictwa w niektórych językach wykluczają jej używanie, jednak ja się jej stosuję i proponuję ją do nazywania zmiennych, jeśli chodzi o języki wywodzące się z Pascala (czyli np. w Delphi czy Free Pascalu).

0

Dziękuję teraz już lepiej, po prostu nie miałam pojęcia o co chodzi np z tym InRow ponieważ na zajęciach dla wierszy uzywalismy zawsze W dla kolumn K i generalnie zwykle wszystko było na tej zasadzie

1
Blackapple napisał(a):

a jeśli chodzi o mój mętlik w nazewnictwie to cóż znowu jest nie tak?
Raz masz w,k jako rozmiary tablicy a chwile później w,k to są indeksy tablicy. Spójrz na nazewnictwo stosowane przez @furious programming wszystko jasne czym jest, owszem ja zmieniłbym nazwy iteratorów pętli z: intRowIdx, intColumnIdx na: y, x lub: r, c (tylko iteratorów) - ale to już kwestia upodobań. Chodzi o to że przy takim nazewnictwie autor nie ma szans pomylić ilość z indeksem bo nazwa zmiennej o tym mówi.

1

Iteratory pętli z reguły powinny być krótkie (nawet jednoliterowe), szczególnie w przypadku wykorzystania ich w ciele pętli, np. do dostępu do odpowiedniej komórki macierzy czy w przypadku przekazywania wartości do procedur/funkcji; Jednak to nie zmienia faktu, iż skróty czy literki powinny być dobierane z głową, a nie byle jak; Na przykład X i Y jeśli określają współrzędne, czy R i C jako Row (wiersz) i Column (kolumna).

0
program ten;
{$APPTYPE CONSOLE}

uses
  SysUtils;

type tablica = array [1..10,1..10] of Integer;
var sum,ilo,i,j,k,w   : Integer;
M:tablica;
f:text;

function suma(M:tablica; w,k:Integer): Integer;
var s,i,j: Integer;
begin
s:=0;
for i:=w-1 to w do
for j:=k-1 to k do
s:=s+M[i,j];
suma:=s;
end;

function iloczyn(M:tablica; w,k:Integer): Integer;
var il,i,j: Integer;
begin
il:=1;
Repeat
writeln ('Podaj wiersz do obliczenia iloczynu');
readln(i);
Until (i>0) and (i<=w);
For j:=1 to k do
il:=il*M[i,j];
iloczyn:=il;
end;

begin
assign(f,'b.txt');
reset(f);
readln(f,w,k);

for i:=1 to w do
begin
for j:=1 to k do
begin
read(f,M[i,j]);
write(M[i,j]:5);
end;
readln(f);
writeln;
end;
close(f);

sum:=suma(M,w,k);
Writeln('Suma wynosi ',sum);
ilo:=iloczyn(M,w,k);
writeln('Iloczyn wynosi ',ilo);
Readln;


end.

Powodzenia na egzaminie :)

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