5 WSKAŹNIKI I TABLICE_______—-'
Oprócz tej różnicy w zapisie tablicę dwuwymiarową traktuje się w bardzo podobny sposób, jak w innych językach programowania. Elementy są umieszczane w pamięci wierszami, a więc skrajnie prawy indeks (numer kolumny) zmienia się najszybciej, gdy elementy są obsługiwane w kolejności ich położenia w pamięci.
Tablicę inicjuje się listą wartości początkowych umieszczoną w nawiasach klamrowych; każdy wiersz tablicy dwuwymiarowej jest inicjowany odpowiednią podlistą. W tablicy daytab pierwszą kolumnę wypełniliśmy zerami, numery miesięcy można zatem zmieniać w sposób naturalny od 1 do 12, a nie od 0 do 11. Chociaż tracimy pamięć, jest to bardziej czytelne niż przesuwanie indeksów.
Gdy funkcji trzeba przekazać tablicę dwuwymiarową, wówczas w deklaracji odpowiedniego parametru funkcji musimy podać liczbę kolumn; liczba wierszy nie jest istotna, gdyż funkcji zostanie przekazany, tak jak poprzednio, wskaźnik do tablicy wierszy (gdzie każdy wiersz jest tablicą 13 liczb typu int*). W tym szczególnym przypadku jest to wskaźnik do obiektów, które są tablicami 13 liczb całkowitych. A zatem, jeśli tablica daytab ma być przekazana funkcji f, to deklaracja tej funkcji powinna mieć taką postać:
f (int daytab[2][13]) {...}
albo taką:
f (int daytabf] [13]) {...}
ponieważ liczba wierszy nie jest ważna, lub też taką: f (int (*daytab)[13]) (...)
Ta ostatnia deklaracja mówi, że parametr jest wskaźnikiem do tablicy 13 liczb całkowitych. Nawiasy okrągłe są w tym przypadku konieczne, gdyż nawiasy kwadratowe [] mają wyższy priorytet niż operator adresowania pośredniego *. Bez nawiasów okrągłych deklaracja
int *daytab[13]
wprowadza tablicę 13 wskaźników do obiektów całkowitych. Ogólniej mówiąc, tylko pierwszy wymiar (indeks) tablicy jest dowolny; wszystkie inne muszą być jawnie określone.
Dalszą dyskusję na temat skomplikowanych deklaracji prowadzimy w punkcie 5.12.
Ćwiczenie 5.8. W funkcjach day_of_year i month-day nie ma żadnego sprawdzania poprawności danych. Napraw tę usterkę.
Autorzy zapomnieli już, że zadeklarowali daytab jako dwuwymiarową tablicę elementów typu char. Aby dalsze rozważania miały sens, musimy teraz przyjąć, żc tablica ma elementy całkowite (int) - Przyp. tb&'
Spróbujemy napisać funkcję month_name(n), która zwraca wskaźnik do nazwy fi-tego miesiąca. Jest to idealny przykład zastosowania wewnętrznej tablicy statycznej. Funkcja month_name zawiera prywatną tablicę tekstów i po wywołaniu wraca ze wskaźnikiem do odpowiedniego tekstu. Tutaj pokażemy, jak zainicjować taką tablicę.
Składnia jest podobna do tej z poprzednich inicjowań:
' i* month_name: podaj nazwę n-tego miesiąca */ char *month_name(int n)
static char *name[ ] = {
"błędny miesiąc”,
"styczeń”, "luty”, "marzec",
"kwiecień”, "maj”, "czerwiec”,
"lipiec”, "sierpień”, "wrzesień”,
"październik”, "listopad”, "grudzień”
return (n < 1 || n > 12) ? name[0]: namefn];
Deklaracja name jako tablicy wskaźników znakowych jest taka sama, jak deklaracja lineptr w przykładzie sortowania. Inicjatorem jest lista napisów. Każdy napis jest przypisywany odpowiedniej pozycji tablicy, a dokładniej: znaki i-tego napisu zostaną umieszczone gdzie indziej, natomiast elementowi tablicy name[i] przypisuje się wskaźnik do początku tego napisu. W deklaracji nie podano rozmiaru tablicy, wobec tego kompilator sam określa ten rozmiar, zliczając podane wartości początkowe.
Początkujący programiści mają czasem kłopoty z przyswojeniem sobie różnicy między tablicą dwuwymiarową a tablicą wskaźników, taką jak name w poprzednim przykładzie. Po następujących definicjach:
int a[ 10] [20];
int *b[10];
155