home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1997 #3 / amigamamagazinepolishissue03-1 / ma_1995 / 05 / ami034.txt < prev    next >
Text File  |  1997-04-07  |  12KB  |  445 lines

  1. /* wyraûenia zawarte w >...< proszë pogrubiê */
  2.  
  3. AMIGA E9
  4.  
  5. <a>Rafaî Wiosna
  6.  
  7. <txt>Hej, ludzie! Idzie wiosna, zarówno za oknem, jak i na
  8. papierze. Tym razem przeprowadzë akcjë promocyjnâ kasety
  9. "Greatest Hits" Budki Suflera. Jak miîo znów odegraê stare
  10. ôwietne przeboje tej formacji. Czëôê z Czytelników moûe nie
  11. wiedzieê, co to jest ta ta Budka Suflera. Przypominam wiëc, ûe
  12. jest to POLSKI zespóî grajâcy DOBR MUZYKË, który w dodatku
  13. istnieje dîuûej niû niektórzy z Was. W nim zaczynali
  14. Borysewicz, Urszula, Trojanowska... Lata osiemdziesiâte coraz
  15. silniej powracajâ na scenë muzycznâ (u nas Perfect, Budka
  16. Suflera, u nich np. Human Leauge). A i dobrze, bo duûa czëôê
  17. "pamiëtliwych" kawaîków powstaîa wîaônie wtedy. Ale co ja plotë,
  18. mamy rozwaûaê o Amiga E, a nie o muzyce...
  19.  
  20. <sr>Tablice
  21.  
  22. <txt>Bardzo czësto sië zdarza, ûe dane uûywane przez program
  23. muszâ byê w pewien sposób poukîadane, gîównie dlatego, aby dostëp
  24. do nich byî szybszy lub îatwiejszy. Najprostszym sposobem na
  25. wprowadzenie takiego porzâdku jest tablica, w E oznaczana jako
  26. typ ARRAY. Najpierw trochë teorii.
  27.  
  28. Skombinuj sobie kartkë papieru. Narysuj na niej prostokât.
  29. Podziel go pionowymi liniami na mniejsze prostokâty. Proszë
  30. bardzo! Masz tablicë! Jest ona jednowymiarowa, gdyû wszystkie
  31. powstaîe prostokâty majâ wysokoôê tego, który narysowaliômy na
  32. poczâtku. Poîoûenie danego prostokâta moûesz okreôliê tylko jednâ
  33. liczbâ. Zacznij od pierwszego z lewej -- nad nim napisz zero.
  34. Potem nad drugim od lewej napisz jedynkë i postëpuj tak z resztâ.
  35.  
  36. Teraz narysuj dowolnâ liczbë poziomych linii, od pierwszej do
  37. ostatniej linii pionowej naszej tablicy. Widzisz? Uzyskaîeô
  38. tablicë dwuwymiarowâ. Ponumeruj rzëdy tak poêwiartowanego
  39. prostokâta-tablicy, poczynajâc od górnego (jemu nadaj numer 0).
  40.  
  41. Weú teraz kilka innych czystych kartek i przerysuj to, co jest na
  42. pierwszej. Nastëpnie kaûdâ z kartek ponumeruj, zaczynajâc od
  43. zera. Brawo!  Zrobiîeô tablicë trójwymiarowâ (zaiste trudno w tym
  44. przykîadzie pokazaê trzeci wymiar na jednej kartce, która jest
  45. przecieû obiektem majâcym znikomâ wysokoôê -- a wiëc
  46. dwuwymiarowym).
  47.  
  48. Teraz narysuj kropkë w dowolnym prostokâcie (tym maîym) na
  49. dowolnej kartce.  Spróbuj okreôliê jego poîoûenie, np. trzecia
  50. kartka, czwarty rzâd, pierwsza kolumna. Moûna zapisaê to tak:
  51.  
  52. tablica[2,3,0]
  53.  
  54. Dlaczego nie [3,4,1]? A no dlatego, ûe przyjëliômy numeracjë od zera.
  55.  
  56. Ten maîy przykîad miaî wyjaôniê cechy typowej tablicy. A wiëc:
  57.  
  58. ^* ma ona jeden lub wiëcej wymiarów,
  59.  
  60. ^* ma skoïczonâ, i co waûniejsze, z góry okreôlonâ liczbë pozycji,
  61.  
  62. ^* kaûdy element tablicy ma swój "adres".
  63.  
  64. Amiga E pozwala na definiowanie tablic, ale niestety tylko
  65. >jednowymiarowych<. Robi sië to w nastëpujâcy sposób:
  66.  
  67. <l>DEF    a[132]:ARRAY,
  68.  
  69.     table[21]:ARRAY OF LONG,
  70.  
  71.     ints[3]:ARRAY OF INT,
  72.  
  73.     objs[54]:ARRAY OF mójobiekt
  74.  
  75. <txt>Jak widzisz, >wielkoôê< tablicy jest okreôlana w nawiasach
  76. kwadratowych, natomiast >typ danych< jest okreôlany na samym
  77. koïcu. Domyôlnym typem jest CHAR, czyli znak (bajt), ale moûe
  78. to byê równieû LONG, INT i dowolny obiekt (o nich opowiem w
  79. nastëpnych odcinkach). Zauwaû, ûe typ LONG moûe równie dobrze byê
  80. wykorzystany jako wskaúnik do dowolnego innego obiektu.
  81.  
  82. Po zdefiniowaniu tablicy mamy swobodny dostëp do jej elementów.
  83. Jak w wypadku naszego eksperymentu z kartkami i prostokâtami,
  84. kaûdy z nich ma swój "adres". Poniewaû jednak to sîowo w
  85. kontekôcie programowania uûywane jest do innego celu, umówmy sië,
  86. ûe do okreôlenia poîoûenia elementu w tablicy bëdziemy uûywaê
  87. angielskiego sîowa "indeks". (Tych, którzy chcâ mówiê "offset",
  88. informujë, ûe jest to nawet i poprawne, ale przydatne tylko w
  89. wypadku tablic jednowymiarowych o elementach typu CHAR...).
  90.  
  91. Pierwszy element w dowolnym wymiarze tablicy zawsze ma indeks 0,
  92. drugi -- 1, trzeci -- 2 itp, aû do elementu ostatniego, n-tego (n
  93. oznacza tu wartoôê, którâ okreôlamy przy definiowaniu tablicy, w
  94. nawiasach kwadratowych), który ma indeks równy n-1. Moûe brzmi to
  95. bardzo dziwnie i nieintuicyjnie, ale tak wîaônie dziaîajâ
  96. komputery, a na domiar zîego Amiga E nie pozwala jeszcze na
  97. okreôlenie podstawy obliczania indeksu tablicy, tak jak ma to
  98. miejsce w inych jëzykach programowania, gdzie moûna zdefiniowaê
  99. tablicë o wymiarze [1945:1999]. My musimy zadowoliê sië
  100. sformuîowaniem [55].
  101.  
  102. Pora na przykîad. Spójrz na programik poniûej:
  103.  
  104. <l>DEF a[10]:ARRAY
  105.  
  106.      
  107.  
  108. PROC main()
  109.  
  110.     DEF i
  111.  
  112.     FOR i:=0 TO 9
  113.  
  114.  
  115.         a[i]:=i*i
  116.  
  117.     ENDFOR
  118.  
  119.     WriteF('Siódmy element tablicy ma wartoôê \d\n', a[6])
  120.  
  121.     a[a[2]]:=10
  122.  
  123.     WriteF('Teraz tablica wyglâda nastëpujâco:\n')
  124.  
  125.     FOR i:=0 TO 9
  126.  
  127.         WriteF(' a[\d] = \d\n', i, a[i])
  128.  
  129.     ENDFOR
  130.  
  131. ENDPROC
  132.  
  133. <txt>Powinieneô zrozumieê caîy program bez problemu. Kîopoty
  134. moûesz mieê jedynie z liniâ ósmâ. Spróbuj sië domyôliê, jak
  135. zostanie ona wykonana. Tak jest, w tym wypadku indeks tablicy
  136. jest pobierany z jednego z jej elementów! Na przyszîoôê pamiëtaj,
  137. ûe stosowanie takich sztuczek moûe byê niebezpieczne -- nie tylko
  138. zaciemnia kod úródîowy, ale teû moûe doprowadziê do zîego
  139. dziaîania programu -- wystarczy, ûeby element tablicy, którego
  140. wartoôê brana jest za offset, sam miaî wartoôê wiëkszâ od
  141. rozmiaru tablicy... Nasz przykîadowy program powinien sprawdziê,
  142. czy na pewno element a[2] jest mniejszy od 10, czyli
  143. zadeklarowanego rozmiaru tablicy a[]. Jeûeli twój program zacznie
  144. mazaê po nie istniejâcych elementach tablicy, dziwne rzeczy mogâ
  145. sië zdarzyê.  Zdarzenie moûe w ogóle nie zostaê zauwaûone, ale
  146. takûe moûe to wywoîaê wizytë Guru, gdy nie istniejâcy indeks
  147. wypadnie akurat na kawaîku wykonywanego lub majâcego sië wykonaê
  148. kodu maszynowego.
  149.  
  150. Oto, co powyûszy program wypluwa na konsolë:
  151.  
  152. <l>Siódmy element tablicy ma wartoôê 36
  153.  
  154. Teraz tablica wyglâda nastëpujâco:
  155.  
  156.  a[0] = 0
  157.  
  158.  a[1] = 1
  159.  
  160.  a[2] = 4
  161.  
  162.  a[3] = 9
  163.  
  164.  a[4] = 10
  165.  
  166.  a[5] = 25
  167.  
  168.  a[6] = 36
  169.  
  170.  a[7] = 49
  171.  
  172.  a[8] = 64
  173.  
  174.  a[9] = 81
  175.  
  176. <txt>Pewnym uîatwieniem dla programisty jest skrót, który moûna
  177. zastosowaê przy korzystaniu z pierwszego (zerowego) elementu
  178. tablicy. Zamiast pisaê a[0], moûna po prostu napisaê a[].
  179.  
  180. >Wskaúniki do tablicy<
  181.  
  182. Gdy zadeklarujesz tablicë, jej poczâtek w pamiëci bëdzie zapisany w
  183. zmiennej o nazwie takiej, jak tablica, ale bez nawiasów kwadratowych.
  184.  
  185. **************** RYSUNEK DO WYKONANIA PRZEZ GRAFICZNY ***************
  186.  
  187. Program: DEF a[20]:ARRAY OF INT
  188.  
  189.          +--------+
  190.          |zmienna |                           +-------+
  191.          |  'a'   |                           |indeks |
  192.          |--------|                           |+-----+|
  193.          | adres  +----\                      || typ ||
  194.          +--------+     \                     +=======+
  195.                          \
  196.                           \
  197.               +-------+ +--\----+ +-------+     +-------+ +-------+
  198.               |  ???  | | a[0]  | | a[1]  |     | a[19] | |  ???  |
  199.      Pamiëê:  |+-----+| |+-----+| |+-----+| ... |+-----+| |+-----+|
  200.               || ??? || || INT || || INT ||     || INT || || ??? ||
  201.               +=======+ +=======+ +=======+     +=======+ +=======+
  202.  
  203. *********************************************************************                           
  204.  
  205. Jak widaê na ilustracji, zmienna "a" jest wskaúnikiem do
  206. zarezerwowanego obszaru pamiëci, który zawiera elementy tablicy.
  207. Zarówno poniûej, jak i powyûej tego obszaru znajdujâ sië komórki
  208. pamiëci oznaczone symbolem "???", nie naleûâce do tablicy. Zmiana
  209. ich zawartoôci, np. "dziëki" niepoprawnemu indeksowi, moûe
  210. prowadziê do zawieszenia sië komputera.
  211.  
  212. Spójrz na poniûszy przykîad wykorzystujâcy wskaúnik do tablicy:
  213.  
  214. <l>DEF a[10]:ARRAY OF INT
  215.  
  216.     
  217.  
  218. PROC main()
  219.  
  220.     DEF ptr:PTR TO INT,i
  221.  
  222.     FOR i:=0 TO 9
  223.  
  224.         a[i]:=i
  225.  
  226.     ENDFOR
  227.  
  228.     ptr:=a
  229.  
  230.     ptr++
  231.  
  232.     ptr[]:=22
  233.  
  234.     FOR i:=0 TO 9
  235.  
  236.         WriteF('a[\d] = \d\n', i, a[i])
  237.  
  238.     ENDFOR
  239.  
  240. ENDPROC
  241.  
  242. <txt>A oto jego rezultat:
  243.  
  244. <l>a[0] = 0
  245.  
  246. a[1] = 22
  247.  
  248. a[2] = 2
  249.  
  250. a[3] = 3
  251.  
  252. a[4] = 4
  253.  
  254. a[5] = 5
  255.  
  256. a[6] = 6
  257.  
  258. a[7] = 7
  259.  
  260. a[8] = 8
  261.  
  262. a[9] = 9
  263.  
  264. <txt>Zauwaû, ûe ta dziwna, na razie nie znana Ci, technika,
  265. zaprezentowana w poprzednim listingu, w rezultacie zmienia drugi
  266. element tablicy.  Zapis "ptr++" zwiëksza wkaúnik "ptr" tak, aby
  267. wskazywaî on nastëpny element tablicy a[]. Waûne jest to, ûeby
  268. zmiennâ "ptr" zadeklarowaê jako PTR TO INT, czyli WSKAÚNIK DO
  269. INT. INT, poniewaû tablica skîada sië z elementów typu INT.
  270.  
  271. Zapis "ptr" jest w tym wypadku, po odpowiednim zdefiniowaniu
  272. zmiennej, równowaûny zapisowi "ptr[]", czyli "ptr[0]". Piszâc
  273. wiëc "ptr[1]" otrzymamy nastëpny element wskazywany przez zmiennâ
  274. "ptr", w tym wypadku trzeci element tablicy a[]. Przykîady
  275. uûycia:
  276.  
  277. <l>    ptr:=a  -> ptr wskazuje na a[0]
  278.  
  279.     ptr++    -> ptr wskazuje na a[1]
  280.  
  281.     ptr[3]:=22 -> zmiana elementu a[4]
  282.  
  283.     ptr[-1]:=99 -> zmiana elementu a[0]
  284.  
  285. <txt>Jak widzisz, jest moûliwe takûe stosowanie ujemnych
  286. indekstów dla zmiennych typu PTR TO COÔTAM. Pamiëtaj jednak, ûe
  287. taki styl programowania moûe byê zabójczy zarówno dla
  288. programisty, jak i dla programu...
  289.  
  290. A propos brzydkiego stylu programowania, to obie poniûsze
  291. definicje sâ poprawne:
  292.  
  293. <l>DEF a[20]:ARRAY OF INT
  294.  
  295.  
  296. DEF a:PTR TO INT
  297.  
  298. <txt>Jeûeli uûyjesz tej drugiej, musisz sam zadbaê o
  299. zarezerwowanie pamiëci dla tablicy, a takûe o to, aby za kilka
  300. tygodni poîapaê sië, o co chodzi w programie...
  301.  
  302. Przed chwilâ pokazaîem, jak w E zwiëkszaê zmiennâ-wskaúnik do
  303. elementu tablicy. Zmniejszanie takiej zmiennej (czyli ustawienie
  304. wskaúnika na poprzedni element tablicy) jest równie proste. Robi
  305. sië to tak:
  306.  
  307. <l>ptr--
  308.  
  309. <txt>Tak naprawdë zapis "ptr++" i "ptr--" to teû wskaúniki.
  310. Pierwszy oznacza element wskazywany przez ptr PRZED ZWIËKSZENIEM
  311. tej zmiennej, a drugi -- na element wskazywany przez ptr PO
  312. ZMNIEJSZENIU zmiennej.  Zapis wiëc:
  313.  
  314. <l>addr:=p
  315.  
  316. p++
  317.  
  318. <txt>to to samo co
  319.  
  320. <l>addr:=p++
  321.  
  322. <txt>a zapis
  323.  
  324. <l>p--
  325.  
  326. addr:=p
  327.  
  328. <txt>moûna zastâpiê przez
  329.  
  330. <l>addr:=p--
  331.  
  332. <txt>Moûesz spytaê, dlaczego piszë o uûywaniu "++" i "--" przy
  333. operacjach na wskaúnikach. Czyû nie moûna po prostu dodawaê i
  334. odejmowaê od wskaúników.  Otóû moûna, ale przenosisz wtedy na
  335. siebie koniecznoôê dbania o wielkoôê elementu, na który wskazuje
  336. zmienna. Maîe piwo, jeûeli jest to bajt (CHAR), dwa (INT) lub
  337. cztery (LONG). Problem przychodzi, jeûeli zdefiniujemy tablicë
  338. tak, ûe jej elementy bëdâ obiektami:
  339.  
  340. <l>MODULE 'intuition/screens'
  341.  
  342. PROC main()
  343.  
  344.     DEF ekrany[10]:ARRAY OF screen,
  345.  
  346.         ekran
  347.  
  348.     ekran:=ekrany
  349.  
  350.     ...
  351.  
  352. <txt>Jak teraz chcesz przejôê do nastëpnego ekranu w tablicy?
  353. Moûesz zrobiê to tak:
  354.  
  355. <l>    ekran:=ekran + SIZEOF screen
  356.  
  357. <txt>Ale czyû nie proôciej napisaê po prostu "ekran++"?
  358.  
  359. Jeûeli chcesz zobaczyê, co to obiekt (w jëzyku C... struktura!) i
  360. jak wyglâda definicja obiektu "screen", to poszukaj go w wydruku
  361. produkowanym przez polecenie:
  362.  
  363. <l>E:bin/ShowModule E:Modules/intuition/screens.m
  364.  
  365. <txt>
  366. >Przekazywanie tablic do procedur<
  367.  
  368. Zacznijmy od tego, ûe przekazywanie tablic do procedur, jako
  369. parametr, nie jest dozwolone w Amiga E. Na szczëôcie, korzystajâc
  370. ze wskaúników moûna bardzo îatwo to zasymulowaê. Spójrz:
  371.  
  372. <l>DEF a[10]:ARRAY OF INT
  373.  
  374.      
  375.  
  376. PROC main()
  377.  
  378.     DEF i
  379.  
  380.     wypelniaj(a, 10)
  381.  
  382.     FOR i:=0 TO 9
  383.  
  384.         WriteF('a[\d] = \d\n', i, a[i])
  385.  
  386.         ENDFOR
  387.  
  388. ENDPROC
  389.  
  390.      
  391.  
  392. PROC wypelniaj(ptr:PTR TO INT, x)
  393.  
  394.     DEF i
  395.  
  396.     FOR i:=0 TO x-1
  397.  
  398.         ptr[]:=i
  399.  
  400.         ptr++
  401.  
  402.     ENDFOR
  403.  
  404. ENDPROC
  405.  
  406.  
  407. <txt>Moûna teû potraktowaê zmiennâ "prt" w sposób bardziej
  408. przypominajâcy tablicë:
  409.  
  410. <l>PROC wypelniaj(ptr:PTR TO INT, x)
  411.  
  412.     DEF i
  413.  
  414.     FOR i:=0 TO x-1
  415.  
  416.         ptr[i]:=i
  417.  
  418.     ENDFOR
  419.  
  420. ENDPROC
  421.  
  422. <txt>Natomiast zaawansowani kursanci, którzy w dodatku pamiëtajâ
  423. mój wykîad sprzed miesiâca, w którym prezentowaîem alternatywnâ
  424. postaê pëtli FOR..ENDFOR, mogâ wklepaê coô takiego:
  425.  
  426. <l>PROC wypelniaj(ptr:PTR TO INT, x)
  427.  
  428.     DEF i
  429.  
  430.     FOR i:=0 TO x-1 DO ptr[]++:=i
  431.  
  432. ENDPROC
  433.  
  434. <txt>W takich "skrótach" miîujâ sië programiôci piszâcy w C. Aby
  435. nie zaciemniaê kodu úródîowego programu, proponujë nie uûywaê
  436. takich sposobików. Kto wie, kiedy przyjdzie Ci po pewnym czasie
  437. domyôlaê sië, co napisaîeô w tym kawaîku...
  438.  
  439. Powyûszy sposób przekazywania tablic do procedur ma wadë. Za
  440. kaûdym razem musisz zadbaê o to, aby w definicji procedury,
  441. której parametrem jest wskaúnik do tablicy, typ danej przez niego
  442. wskazywanej zgadzaî sië z typem elementu przekazywanej tablicy.
  443. Musisz teû w jakiô sposób przekazaê procedurze rozmiar tablicy.
  444. Powyûszy przykîad dobrze obrazuje rozwiâzania obu tych problemów.
  445.