5 WSKAŹNIKI I TABLICE _______——
Ćwiczenie 5.16. Dodaj opcję -d (kolejność słownikowa) sprawiającą, że w porównaniu biorą udział tylko litery, liczby i odstępy. Upewnij się, że program działa poprawnie w połączeniu z opcją —f.
Ćwiczenie 5.17. Dodaj mechanizm obsługi pól tak, by można było przeprowadzić porządkowanie zawartości pól wewnątrz wierszy, stosując dla każdego pola niezależny zestaw opcji. (Skorowidz angielskiego oryginału tej książki był sortowany z użyciem opcji -df dla haseł i -n dla numerów stron.)
Język C jest czasami „karcony” za składnię deklaracji, a szczególnie za deklaracje wymagające wskaźników do funkcji. Składnia ta jest próbą pogodzenia deklaracji obiektu i jego użycia. Założenie to sprawdza się dla prostych przypadków, ale <dla trudniejszych może być kłopotliwe, ponieważ deklaracji nie da się czytać od lewej strony do prawej, a także trzeba „nadużywać” nawiasów. Różnica między deklaracjami
int *f (); /* f: funkcja zwracająca wskaźnik do int */
i
int (*pf) () /* pf: wskaźnik do funkcji zwracającej int */
ilustruje ten problem: operator adresu * jest operatorem przedrostkowym i ma niższy priorytet niż nawiasy funkcji (), wobec czego „dodatkowe” nawiasy są konieczne w celu wymuszenia prawidłowego powiązania składowych.
W praktyce rzadko spotyka się naprawdę skomplikowane deklaracje, ważne jest jednak to, by je należycie rozumieć i - jeśli zajdzie taka potrzeba - wiedzieć, jak je tworzyć. Jednym z dobrych sposobów syntetyzowania deklaracji jest metoda małych kroków, korzystająca z definicji typów typedef, o której jest mowa w p. 6.7. Tu proponujemy inny sposób: prezentujemy parę programów, które zamieniają poprawny tekst napisany w języku C na zwykły opis słowny i odwrotnie. Opis słowny czyta się od lewej strony do prawej.
Pierwszy z programów, dcl, jest bardziej skomplikowany*. Jego zadaniem jest zamiana deklaracji C na opis słowny, jak w następujących przykładach:
+
Aby nie komplikować jeszcze bardziej tego programu, nie będziemy tu zajmować się deklinacją polskich słów. - Przyp. tłum.
powered by
5.12 SKOMPLIKOWANE DEKLARACJE
char **argv I ■
argv: wskaźnik do wskaźnik do char int (*daytab)[13]
daytab: wskaźnik do tablica[13] o elementach int int *daytab[13]
daytab: tablica[13] o elementach wskaźnik do int void *comp ()
comp: funkcja zwracająca wskaźnik do void void (*comp)()
comp: wskaźnik do funkcja zwracająca void char (*(*x ())[])()
x: funkcja zwracająca wskaźnik do tablica[] o elementach wskaźnik do funkcja zwracająca char char (*(*x[3])()) [5]
x: tablica[3] o elementach wskaźnik do funkcja zwracająca wskaźnik do tablica[5] o elementach char
Program dcl działa na podstawie gramatyki, którą wprowadza deklarator, szczegółowo opisany w dodatku A8.5. Tutaj przedstawiamy uproszczoną postać reguł składniowych:
deklarator:
opcjonalne *-i bezpośredni-deklarator
bezpośredn i - dekla ra to r: nazwa (deklarator)
bezpośredni-deklarator() bezpośredni-deklaratoĄopcjonalny rozmiar]
Mówiąc prościej, deklarator jest bezpośrednim deklaratorem być może poprzedzonym znakami *. Bezpośredni deklarator jest albo nazwą, albo deklaratorem ujętym w nawiasy okrągłe, albo bezpośrednim deklaratorem, po którym następują nawiasy okrągłe, albo bezpośrednim deklaratorem, po którym następują nawiasy kwadratowe ewentualnie zawierające rozmiar.
Z tej gramatyki można skorzystać przy rozbiorze deklaracji. Rozważmy na przykład deklarator
Fragment pfa zostanie zidentyfikowany jako nazwa, a zatem jako bezpośredni-deklarator. Wobec tego konstrukcja pfa[ ] także jest bezpośrednim deklaratorem. Potem
167