You are on page 1of 22

IDZ DO

PRZYKADOWY ROZDZIA
SPIS TRECI

KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG

Programowanie
w jzyku C. FAQ
Autor: Steve Summit
Tumaczenie: Przemysaw Kowalczyk
ISBN: 83-7361-094-4
Tytu oryginau: C Programming FAQs
Format: B5, stron: 400

TWJ KOSZYK
DODAJ DO KOSZYKA

CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK

CZYTELNIA
FRAGMENTY KSIEK ONLINE

Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl

Przysowie kto pyta, nie bdzi nie zawiera caej prawdy. Nie wystarczy pyta, trzeba
jeszcze znajdowa odpowiedzi. Ksika Programowanie w jzyku C. FAQ to zbir
kilkuset odpowiedzi na najczciej zadawane pytania na temat tego jzyka
programowania. Z pewnoci cz z przedstawionych tu pyta ju pojawia si
w Twojej praktyce programistycznej (pamitasz, ile czasu stracie poszukujc
odpowiedzi?). Inne problemy dopiero si pojawi i jeli na Twojej pce bdzie ta
ksika, szybko znajdziesz w niej zwize, ale wyczerpujce rozwizanie czsto
wzbogacone przykadem kodu rdowego.
Chocia ksika adn miar nie powinna by traktowana jako podrcznik, z ktrego
mona nauczy si programowania w C, z pewnoci przyda si kadej osobie
uywajcej tego jzyka w codziennej praktyce. Autor porusza wiele przydatnych
zagadnie obejmujcych szeroki zestaw tematw.
Omwiono midzy innymi:
Deklaracje
Struktury i unie
Puste wskaniki
Wyraenia
Makroprocesor
Alokacj pamici
Rnice midzy standardami C
Standardow bibliotek wejcia-wyjcia
Kwestie zwizane z systemami operacyjnymi

Spis treci
Pytania.............................................................................................. 9
Przedmowa...................................................................................... 37
Wprowadzenie ................................................................................. 41
Jak korzysta z tej ksiki? ......................................................................................41
Format pyta..........................................................................................................43
Przykady kodu ......................................................................................................43
Organizacja ksiki .................................................................................................44

Rozdzia 1. Deklaracje i inicjalizacja................................................................... 47


Podstawowe typy....................................................................................................47
Deklaracje wskanikw ...........................................................................................50
Styl deklaracji.........................................................................................................51
Klasy pamici.........................................................................................................54
Definicje typw ......................................................................................................55
Kwalifikator const ..................................................................................................59
Zoone deklaracje ..................................................................................................59
Rozmiary tablic ......................................................................................................62
Problemy z deklaracjami .........................................................................................64
Przestrze nazw......................................................................................................65
Inicjalizacja............................................................................................................69

Rozdzia 2. Struktury, unie i typy wyliczeniowe................................................... 73


Deklaracje struktur..................................................................................................73
Dziaania na strukturach ..........................................................................................78
Wyrwnywanie pl struktur.....................................................................................80
Dostp do pl struktur.............................................................................................82
Rne pytania na temat struktur ...............................................................................83
Unie ......................................................................................................................84
Typy wyliczeniowe .................................................................................................85
Pola bitowe ............................................................................................................86

Rozdzia 3. Wyraenia........................................................................................ 89
Kolejno obliczania ...............................................................................................89
Inne pytania na temat wyrae.................................................................................96
Reguy zachowywania........................................................................................... 100

Programowanie w jzyku C. FAQ

Rozdzia 4. Wskaniki...................................................................................... 103


Podstawy ............................................................................................................. 103
Dziaania na wskanikach...................................................................................... 105
Wskaniki jako parametry funkcji .......................................................................... 106
Rne zastosowania wskanikw ........................................................................... 110

Rozdzia 5. Wskaniki puste ............................................................................ 113


Wskaniki puste i literay wskanika pustego .......................................................... 113
Makrodefinicja NULL........................................................................................... 116
Retrospektywa...................................................................................................... 121
Co mona znale pod adresem 0? ......................................................................... 124

Rozdzia 6. Tablice i wskaniki......................................................................... 127


Podstawowe zwizki midzy tablicami i wskanikami.............................................. 128
Tablicom nie mona przypisywa wartoci.............................................................. 131
Retrospektywa...................................................................................................... 132
Wskaniki do tablic............................................................................................... 134
Dynamiczne tworzenie tablic ................................................................................. 136
Funkcje a tablice wielowymiarowe ......................................................................... 140
Rozmiary tablic .................................................................................................... 143

Rozdzia 7. Przydzielanie pamici ..................................................................... 145


Podstawowe problemy z przydzielaniem pamici..................................................... 145
Wywoywanie funkcji malloc................................................................................. 149
Problemy z funkcj malloc..................................................................................... 152
Zwalnianie pamici ............................................................................................... 155
Rozmiar przydzielonych blokw ............................................................................ 158
Inne funkcje przydzielajce pami ........................................................................ 159

Rozdzia 8. Znaki i napisy................................................................................ 165


Rozdzia 9. Wyraenia i zmienne logiczne ......................................................... 171
Rozdzia 10. Preprocesor jzyka C ..................................................................... 175
Makrodefinicje ..................................................................................................... 175
Pliki nagwkowe ................................................................................................. 180
Kompilacja warunkowa......................................................................................... 183
Zaawansowane przetwarzanie ................................................................................ 186
Makrodefinicje ze zmienn liczb argumentw........................................................ 189

Rozdzia 11. Standard ANSI/ISO jzyka C .......................................................... 193


Standard .............................................................................................................. 193
Prototypy funkcji .................................................................................................. 195
Kwalifikator const ................................................................................................ 198
Funkcja main........................................................................................................ 200
Waciwoci preprocesora ..................................................................................... 203
Inne sprawy zwizane ze Standardem ANSI............................................................ 205
Stare lub niezgodne ze Standardem kompilatory ...................................................... 208
Kwestie zgodnoci ................................................................................................ 211

Rozdzia 12. Standardowa biblioteka wejcia-wyjcia ......................................... 215


Podstawy obsugi wejcia-wyjcia .......................................................................... 216
Formaty dla funkcji printf ...................................................................................... 218
Formaty dla funkcji scanf ...................................................................................... 222
Problemy z funkcj scanf ...................................................................................... 224
Inne funkcje z biblioteki wejcia-wyjcia ................................................................ 228

Spis treci

7
Otwieranie plikw i operacje na nich ...................................................................... 232
Przekierowywanie strumieni stdin i stdout............................................................... 235
Obsuga wejcia-wyjcia w trybie binarnym ............................................................ 237

Rozdzia 13. Funkcje biblioteczne ...................................................................... 241


Funkcje operujce na napisach ............................................................................... 241
Sortowanie ........................................................................................................... 247
Data i czas ........................................................................................................... 251
Liczby losowe ...................................................................................................... 254
Inne funkcje biblioteczne....................................................................................... 261

Rozdzia 14. Liczby zmiennoprzecinkowe............................................................ 265


Rozdzia 15. Listy argumentw o zmiennej dugoci............................................ 273
Wywoywanie funkcji o zmiennej liczbie argumentw ............................................. 274
Implementacja funkcji o zmiennej liczbie argumentw............................................. 275
Pobieranie argumentw z listy................................................................................ 280
Trudniejsze problemy............................................................................................ 283

Rozdzia 16. Dziwne problemy............................................................................ 287


Rozdzia 17. Styl ............................................................................................... 293
Rozdzia 18. Narzdzia i zasoby.......................................................................... 299
Narzdzia............................................................................................................. 299
Program lint ......................................................................................................... 301
Zasoby................................................................................................................. 303

Rozdzia 19. Kwestie zalene od systemu operacyjnego...................................... 309


Klawiatura i ekran................................................................................................. 310
Inne operacje wejcia-wyjcia ................................................................................ 316
Pliki i katalogi ...................................................................................................... 318
Bezporedni dostp do pamici .............................................................................. 324
Polecenia systemowe ............................................................................................ 326
rodowisko procesu .............................................................................................. 329
Inne operacje zalene od systemu........................................................................... 330
Retrospektywa...................................................................................................... 333

Rozdzia 20. Rnoci........................................................................................ 335


Przydatne techniki................................................................................................. 336
Bity i bajty ........................................................................................................... 343
Wydajno ........................................................................................................... 348
Instrukcja switch................................................................................................... 352
Rne kwestie jzykowe ....................................................................................... 354
Inne jzyki ........................................................................................................... 358
Algorytmy............................................................................................................ 359
Inne..................................................................................................................... 364

Sownik ......................................................................................... 369


Bibliografia .................................................................................... 379
Skorowidz ..................................................................................... 383

Rozdzia 6.

Tablice i wskaniki
Sia jzyka C wynika midzy innymi z ujednoliconego traktowania tablic i wskanikw. Bardzo atwo jest za pomoc wskanikw operowa na tablicach czy symulowa tablice tworzone dynamicznie. Tak zwana odpowiednio wskanikw i tablic
jest tak dua, e niektrzy programici zapominaj o zasadniczych rnicach, mylc,
e s one identyczne, albo zakadajc nieistniejce midzy nimi podobiestwa.
Podstaw odpowiednioci tablic i wskanikw w jzyku C jest fakt, e odwoania
do tablic degeneruj si do wskanikw do pierwszego elementu tablicy, co opisuje
pytanie 6.3. Z tego powodu tablice s obywatelami drugiej kategorii w C nigdy
nie posugujesz si tablicami jako caymi obiektami (na przykad aby skopiowa je
albo przekaza do funkcji). Kiedy uyjesz nazwy tablicy, w wyraeniu pojawi si
wskanik zamiast caej tablicy. Nawet operator indeksowania tablic  w rzeczywistoci operuje na wskaniku. Wyraenie  jest rwnowane wyraeniu wskanikowemu .
Dua cz tego rozdziau (szczeglnie pytania retrospektywne 6.8 6.10) moe
wydawa si powtarzaniem wci tych samych wiadomoci. Wielu programistw ma
jednak spore kopoty ze zrozumieniem zwizkw i rnic midzy wskanikami i tablicami, w tym rozdziale staram si wyjani je najlepiej, jak tylko potrafi. Jeeli
nudz Ci takie powtrki, moesz przeskoczy do nastpnego rozdziau. Jeeli jednak
masz kopoty z tablicami lub wskanikami, przeczytaj uwanie odpowiedzi, a poszczeglne czci ukadanki na pewno wskocz na swoje miejsca.

128

Programowanie w jzyku C. FAQ

Podstawowe zwizki
midzy tablicami i wskanikami
6.1
Pytanie: W jednym z plikw rdowych mam definicj , a w innym deklaracj
  . Dlaczego to nie dziaa?
Odpowied: Zmienna zadeklarowana przy uyciu
  nie jest typu tablicowego, nie pasuje wic do rzeczywistej definicji. Typ wskanik do typu  nie jest
tym samym, co typ tablica elementw typu . Uyj deklaracji
 .
Referencje: ANSI 3.5.4.2
ISO 6.5.4.2
CT&P 3.3, 4.5

6.2
Pytanie: Ale przecie syszaem, e  i   to to samo. Czy to prawda?
Odpowied: Nie, to nie jest prawda (to, co syszae, odnosio si do parametrw formalnych funkcji, zobacz pytanie 6.4). Tablice nie s wskanikami, chocia s blisko
z nimi zwizane (zobacz pytanie 6.3) i korzysta si z nich podobnie (zobacz pytania
4.1, 6.8, 6.10 i 6.14).
Deklaracja tablicy   powoduje przydzielenie miejsca na sze znakw i powizanie go z nazw . Innymi sowy,  stanowi adres obszaru pamici, w ktrym
zmieci si sze znakw. Z drugiej strony, deklaracja wskanika    powoduje
przydzielenie miejsca na wskanik i powizanie go z nazw . Wskanik ten moe
wskazywa praktycznie gdziekolwiek: na pojedyncz zmienn typu  , na cig
tablic elementw typu  albo nigdzie 1 (zobacz te pytania 1.30 i 5.1).
Jak zwykle w takich sytuacjach, obrazek wart jest tysica sw. Deklaracje:
 

   

powoduj utworzenie i zainicjalizowanie struktur danych, ktre mona zobrazowa


nastpujco:

Nie naley jednak interpretowa poj gdziekolwiek i nigdzie zbyt szeroko. Aby wskanik mia
poprawn warto, musi wskazywa na prawidowo przydzielony obszar pamici (zobacz pytania 7.1,
7.2 i 7.3). Aby wskazywa nigdzie, musi by wskanikiem pustym (zobacz pytanie 5.1).

Rozdzia 6. Tablice i wskaniki

129

Naley pamita, e wyraenie


 tumaczone jest przez kompilator odmiennie,
w zalenoci od tego, czy
to wskanik, czy tablica. W zasigu widocznoci powyszych deklaracji wyraenie  powoduje wygenerowanie nastpujcego kodu: we
adres tablicy , dodaj do niego 3 i pobierz znak stamtd. Z kolei wyraenie  tumaczone jest jako: we adres wskanika , pobierz jego warto, dodaj do niej 3
i pobierz znak stamtd. Innymi sowy, wyraenie  odnosi si do znaku odlegego
o 3 miejsca od pocztku obiektu o nazwie , natomiast  to znak odlegy o 3 miejsca
od obiektu wskazywanego przez . W naszym przykadzie zarwno , jak i 
odnosz si do litery , ale nie s to te same litery i ich adresy obliczane s inaczej.
Referencje: K&R2 5.5
CT&P 4.5

6.3
Pytanie: Co w takim razie oznacza odpowiednio wskanikw i tablic w C?
Odpowied: Wiele nieporozumie dotyczcych tablic i wskanikw w jzyku C bierze
si wanie z niewaciwego rozumienia tego pojcia. Odpowiednio nie oznacza,
e s one identyczne, ani nawet, e mog by uywane wymiennie. Definicj owej
odpowiednioci mona przedstawi nastpujco: referencja do obiektu o typie tablica elementw typu , degeneruje si w wyraeniach (z trzema wyjtkami) do
wskanika do pierwszego elementu tablicy. Jest on typu wskanik do typu  (Wspomniane wyjtki to: kiedy nazwa tablicy jest argumentem operatora  , operatora 
albo jest literaem napisowym w inicjalizatorze tablicy znakw 2. Zobacz pytania 6.23,
6.12 i 1.32, odpowiednio).
Z takiej definicji wynika, e zastosowanie operatora  do tablic i wskanikw nie rni si tak bardzo 3, mimo e s to odmienne obiekty. Jeeli  to tablica, a  to wskanik, wyraenie w postaci  powoduje, e odwoanie do tablicy zamieniane jest
niejawnie na wskanik do pierwszego elementu, zgodnie z powysz regu. Dalsze
operacje s identyczne jak w przypadku indeksowania wskanika w wyraeniu 
(chocia obliczenie rni si operacjami odczytu pamici, jak wyjaniem w pytaniu
6.2). Jeeli przypiszesz do wskanika adres tablicy:


to wyraenia  i  bd si odnosi do tego samego elementu.


2

Za litera napisowy w inicjalizatorze tablicy znakw uwaamy take literay inicjalizujce tablice
znakw .
Mwic cile, operator  zawsze jest stosowany do wskanikw, zobacz pytanie 6.10, punkt 2.

130

Programowanie w jzyku C. FAQ

Dziki temu wanie wskaniki mona tak atwo stosowa do operacji na tablicach,
uywa ich zamiast tablic jako argumentw funkcji (zobacz pytanie 6.4) czy symulowa tablice dynamiczne (zobacz pytanie 6.14).
Zobacz te pytania 6.8 i 6.10.
Referencje: K&R1 5.3
K&R2 5.3
ANSI 3.2.2.1, 3.3.2.1, 3.3.6
ISO 6.2.2.1, 6.3.2.1, 6.3.6
H&S 5.4.1

6.4
Pytanie: Jeeli wic tablice i wskaniki rni si tak bardzo, dlaczego mona
uywa ich wymiennie jako parametrw formalnych funkcji?
Odpowied: Dla wygody.
Poniewa w wyraeniach tablice staj si wskanikami, do funkcji przekazywane s
zawsze wskaniki, a nigdy tablice. Moesz udawa, e funkcja oczekuje jako parametru tablicy i podkreli to w kodzie rdowym, deklarujc funkcj jako:



Jednak taka deklaracja, zinterpretowana dosownie, nie ma zastosowania, gdy funkcja i tak otrzyma wskanik, wic dla kompilatora rwnowana jest z deklaracj:



Nie ma nic niewaciwego w mwieniu, e funkcja otrzymuje jako parametr tablic,


jeeli jest on wewntrz funkcji traktowany jako tablica.
Wymienne stosowanie tablic i wskanikw dopuszczalne jest jedynie w deklaracjach
parametrw formalnych funkcji i w adnym innym przypadku. Jeeli podmiana tablicy
na wskanik w deklaracji funkcji przeszkadza Ci, deklaruj parametry jako wskaniki.
Wiele osb uwaa, e zamieszanie, jakie powoduj takie deklaracje, znacznie przewaa nad korzyciami z faktu, e parametr wyglda, jakby by tablic (Zauwa rwnie, e taka konwersja zachodzi tylko raz; parametr typu    jest nieprawidowy. Zobacz pytania 6.18 i 6.19).
Zobacz te pytanie 6.21.
Referencje: K&R1 5.3, A10.1
K&R2 5.3, A8.6.3, A10.1
ANSI 3.5.4.3, 3.7.1, 3.9.6
ISO 6.5.4.3, 6.7.1, 6.9.6
H&S 9.3
CT&P 3.3
Ritchie, The Development of the C Language

Rozdzia 6. Tablice i wskaniki

131

Tablicom nie mona


przypisywa wartoci
Jeeli tablica pojawia si po prawej stronie operatora przypisania, kopiowany jest
wskanik do pierwszego elementu, a nie caa tablica. Co wicej, tablica nie moe si
pojawi po lewej stronie operatora przypisania (midzy innymi dlatego, e i tak nie
mona jej przypisa caej tablicy, jak wynika z poprzedniego zdania).

6.5
Pytanie: Czemu tablicom nie mona przypisywa wartoci? Poniszy kod nie dziaa:






  !" # 

Odpowied: Tablice s obywatelami drugiej kategorii w jzyku C. Nie mona im,


midzy innymi, przypisywa wartoci (zobacz te pytanie 6.7). Kiedy chcesz skopiowa elementy z jednej tablicy do drugiej, musisz to wyrazi jawnie. W przypadku napisw, pamitanych jako  , odpowiednia jest najczciej funkcja  :
$%
  !" # 

Jeeli chcesz operowa na tablicach bez kopiowania ich zawartoci, moesz uywa
wskanikw wtedy wystarczy zwyke przypisanie. Zobacz te pytania 4.1 i 8.2.
Referencje: ANSI 3.2.2.1
ISO 6.2.2.1
H&S 7.9.1

6.6
Pytanie: Jeeli nie mog przypisywa wartoci tablicom, w jaki sposb dziaa ten
kod?
&

&'('
 )$



Odpowied: W tym przypadku  jest parametrem funkcji. Jego deklaracja jest


podmieniana przez kompilator, jak opisaem to w pytaniu 6.4. Innymi sowy, 
jest wskanikiem (typu  ), mona wic mu przypisa warto.

132

Programowanie w jzyku C. FAQ

6.7
Pytanie: W jaki sposb tablica moe by l-wartoci, jeeli nie mona do niej przypisa?
Odpowied: Termin l-warto nie oznacza w rzeczywistoci czego, czemu mona
przypisa warto. Lepsz definicj byoby co, co posiada adres w pamici4. Standard ANSI/ISO jzyka C definiuje rwnie pojcie modyfikowalnej l-wartoci. Tablica ni nie jest. Zobacz te pytanie 6.5.
Referencje: ANSI 3.2.2.1
ISO 6.2.2.1
Rationale 3.2.2.1
H&S 7.1

Retrospektywa
Poniewa zwizki midzy tablicami i wskanikami powoduj tyle nieporozumie, kilka nastpnych pyta dotyczy wanie przyczyn tych nieporozumie.

6.8
Pytanie: Jaka jest praktyczna rnica midzy tablicami i wskanikami?
Odpowied: Tablica jest pojedynczym, przydzielonym wczeniej cigym obszarem
pamici, zawierajcym elementy tego samego typu. Posiada stay rozmiar i pooenie.
Wskanik to odniesienie do dowolnego elementu (okrelonego typu) gdziekolwiek.
Wskanikowi naley przypisa adres przydzielonego w jaki sposb obszaru pamici,
ale mona jego warto modyfikowa (a obszarowi pamici, jeeli zosta przydzielony dynamicznie, mona zmieni rozmiar). Wskanik moe wskazywa na elementy
tablicy i mona go uy (wraz z funkcj ) do symulowania dynamicznych tablic. Wskaniki s jednak znacznie bardziej ogln struktur danych (zobacz rwnie
pytanie 4.1).
Z powodu tak zwanej odpowiednioci wskanikw i tablic (zobacz pytanie 6.3)
moe si wydawa, e tablic i wskanikw mona uywa wymiennie. Wskanik do
obszaru pamici przydzielonego przez funkcj  jest czsto traktowany jako tablica (moe by nawet argumentem operatora ). Zobacz pytania 6.14 i 6.16 (Pamitaj o zachowaniu ostronoci przy uyciu operatora  , zobacz pytanie 7.28).
Zobacz te pytania 1.32, 6.10 i 20.14.
4

Pierwotna definicja l-wartoci rzeczywicie mwia o lewej stronie operatora przypisania.

Rozdzia 6. Tablice i wskaniki

133

6.9
Pytanie: Kto wyjani mi, e tablice to w rzeczywistoci stae wskaniki. Czy to
prawda?
Odpowied: To zbyt uproszczone wyjanienie. Nazwa tablicy jest sta w tym sensie, e nie mona jej przypisa wartoci. Jednak tablica to nie wskanik, co powinna
wyjani odpowied na pytanie 6.2. Zobacz te pytania 6.3, 6.8 i 6.10.

6.10
Pytanie: Cigle nie do koca rozumiem. Czy wskanik jest rodzajem tablicy, czy
moe tablica jest rodzajem wskanika?
Odpowied: Tablica nie jest wskanikiem, a wskanik nie jest tablic. Referencja do tablicy (czyli uycie nazwy tablicy w kontekcie wyraenia) jest zamieniana na wskanik
(zobacz pytania 6.2 i 6.3).
S przynajmniej trzy prawidowe interpretacje tej sytuacji:
1. Wskaniki mog symulowa tablice (ale to nie jedyne ich zastosowanie,

zobacz pytanie 4.1).


2. W jzyku C w zasadzie nie ma tablic z prawdziwego zdarzenia (s obywatelami
drugiej kategorii). Nawet operator  jest w rzeczywistoci operatorem

dziaajcym na wskaniku.
3. Na wyszym poziomie abstrakcji wskanik do cigego obszaru pamici moe

by uwaany za tablic (chocia s te inne zastosowania wskanikw).


Z drugiej strony, nie naley myle w ten sposb:
4. S dokadnie takie same (nieprawda, zobacz pytanie 6.2).
5. Tablice to stae wskaniki (nieprawda, zobacz pytanie 6.9).

Zobacz te pytanie 6.8.

6.11
Pytanie: Spotkaem si z dowcipnym kodem, zawierajcym wyraenie  .
Dlaczego jest ono poprawne?
Odpowied: Moe to zabrzmi niewiarygodnie, ale indeksowanie tablic jest dziaaniem przemiennym 5 w jzyku C. Ten ciekawy fakt wynika ze wskanikowej definicji
5

Przemienno dotyczy tylko argumentw operatora . Wyraenie &* jest w oczywisty sposb
rne od wyraenia *&.

134

Programowanie w jzyku C. FAQ

operatora . Wyraenie   jest rwnowane   dla dowolnych dwch wyrae  i , jeeli tylko jedno z nich jest wyraeniem wskanikowym, a drugie cakowitym. Dowd przemiennoci mgby wyglda tak:
   jest z definicji rwnowane:
   jest rwnowane na mocy przemiennoci dodawania:
   jest z definicji rwnowane:
 .

Nieoczekiwana przemienno operatora  traktowana jest zazwyczaj w tekstach o jzyku C jako powd do dumy, chocia nie ma sensownych zastosowa poza Konkursami Zaciemnionego Kodu w C (zobacz pytanie 20.36).
Poniewa napisy w jzyku C s tablicami elementw typu  , wyraenie  !
" jest cakowicie poprawne. Jego wartoci jest litera . Moesz uwaa to za
skrcon posta wyraenia:
+ ,

+-

W pytaniu 20.10 znajdziesz bardziej realistyczny przykad.


Referencje: Rationale 3.3.2.1
H&S 5.4.1, 7.4.1

Wskaniki do tablic
Poniewa tablice zwykle zamieniane s na wskaniki, szczeglnie atwo o nieporozumienia, kiedy operujemy na wskanikach do caych tablic (zamiast, jak zwykle, do
ich pierwszych elementw).

6.12
Pytanie: Jeeli odwoania do tablic przeksztacane s na wskaniki, jaka jest rnica midzy  i  (przy zaoeniu, e  to jaka tablica)?
Odpowied: Wyraenia te rni si typem.
Standard jzyka C stanowi, e wyraenie   jest typu wskanik do tablicy elementw typu  i zwraca wskanik do caej tablicy (wczeniejsze kompilatory generalnie ignoroway operator  w takim kontekcie, czasem tylko zgaszajc ostrzeenie).
We wszystkich kompilatorach jzyka C odwoanie do nazwy tablicy (bez operatora )
zwraca wskanik, typu wskanik do typu , do pierwszego elementu tablicy.

Rozdzia 6. Tablice i wskaniki

135

W przypadku tablicy jednowymiarowej, jak na przykad:


&

odwoanie do  jest typu wskanik do typu  , a  wskanik do tablicy 10


elementw typu  . W przypadku tablic dwuwymiarowych:
&$./0 1.20345.1

odwoanie do   jest typu wskanik do tablicy #$%&'(#) elementw typu  , natomiast   wskanik do tablicy #*%+) tablic o #$%&'(#) elementw typu  .
Zobacz te pytania 6.3, 6.13 i 6.18.
Referencje: ANSI 3.2.2.1, 3.3.3.2
ISO 6.2.2.1, 6.3.3.2
Rationale 3.3.3.2
H&S 7.5.6

6.13
Pytanie: Jak zadeklarowa wskanik do tablicy?
Odpowied: Zastanw si, czy rzeczywicie go potrzebujesz. Kiedy kto mwi o wskaniku do tablicy, ma zazwyczaj na myli wskanik do jej pierwszego elementu.
Zamiast wskanika do tablicy czasem lepiej uy wskanika do jednego z elementw
tablicy. Tablice elementw typu  staj si w wyraeniach wskanikami do typu 
(zobacz pytanie 6.3), co jest bardzo wygodne. Indeksowanie albo zwikszanie powstaego tak wskanika pozwala na dostp do elementw tablicy. Rzeczywiste wskaniki do tablic, kiedy s indeksowane lub zwikszane, przechodz przez cae tablice
i s przydatne tylko, gdy operujemy na tablicach tablic6 (zobacz pytanie 6.18).
Jeeli naprawd potrzebujesz wskanika do caej tablicy, zadeklaruj go na przykad
tak:  #, gdzie # to rozmiar tablicy (zobacz te pytanie 1.21). Jeeli rozmiar
tablicy jest nieznany, # mona teoretycznie pomin, ale zadeklarowany w ten sposb
wskanik do tablicy nieznanego rozmiaru jest bezuyteczny.
Ponisze przykady pokazuj rnice midzy zwykymi wskanikami a wskanikami
do tablic. Przy zaoeniu, e obowizuj deklaracje:
&6%%7
&7766%8%-%9%:%;
&& <=!&= $)&<
&6 <=!&= , &$6

+
>$)&<

moemy uy wskanika do typu  , , aby operowa na jednowymiarowej tablicy ,:


6

Rozumowanie to dotyczy oczywicie rwnie tablic trj- i wicejwymiarowych.

136

Programowanie w jzyku C. FAQ


&
& ? %&
&@@
& ?( %&

Ten fragment kodu wydrukuje:




Jednak prba uycia wskanika do tablicy, , na ,:


A
& ? %
@@ <B3C<
& ?( % <D &
&
D
&& 
<

spowodowaaby wypisanie 0 i zachowanie niezdefiniowane (od wypisania przypadkowej wartoci do bdu w czasie wykonania) w momencie drugiego wywoania funkcji   . Wskanik do tablicy moe si przyda, kiedy operujemy na tablicy tablic,
na przykad :
7
& ??( %%
@@ <D
 D&+$ E
* , &$<
& ??( %%

Ten fragment kodu drukuje:


68
9:

Zobacz te pytanie 6.12.


Referencje: ANSI 3.2.2.1
ISO 6.2.2.1

Dynamiczne tworzenie tablic


Bliski zwizek tablic i wskanikw uatwia symulowanie tablic o rozmiarze okrelonym w czasie dziaania programu za pomoc wskanikw do dynamicznie przydzielonych obszarw pamici.

6.14
Pytanie: Jak okreli rozmiar tablicy w czasie dziaania programu? Jak unikn
tablic o z gry ustalonym rozmiarze?
Odpowied: Odpowiednio tablic i wskanikw (zobacz pytanie 6.3) pozwala symulowa tablice dynamiczne za pomoc wskanika do obszaru pamici, dostarczonego przez funkcj . Po wykonaniu:

Rozdzia 6. Tablice i wskaniki

137

F& )
G &,HI
&$$&+ &D
&

(i jeeli wywoanie funkcji  si powiedzie) moesz odwoywa si do !   (dla  od 0 do 9) tak, jakby !   bya zwyk, statycznie utworzon tablic
( ,.). Zobacz rwnie pytania 6.16, 7.28 i 7.29.

6.15
Pytanie: Jak zadeklarowa lokaln tablic o rozmiarze rwnym tablicy przekazanej jako parametr?
Odpowied: W jzyku C nie mona tego zrobi. Rozmiary tablic musz by znane
w czasie kompilacji (Kompilator GNU C dopuszcza moliwo deklarowania tablic
o zmiennym rozmiarze jako rozszerzenie; znalazo si ono rwnie w standardzie
C99). Moesz uy funkcji , aby stworzy tablic dynamiczn, ale pamitaj o zwolnieniu jej funkcj  . Zobacz te pytania 6.14, 6.16, 6.19, 7.22 i moe
rwnie 7.32.
Referencje: ANSI 3.4, 3.5.4.2
ISO 6.4, 6.5.4.2

6.16
Pytanie: Jak dynamicznie przydzieli pami dla tablicy wielowymiarowej?
Odpowied: W wikszoci przypadkw najlepiej stworzy tablic7 wskanikw do
wskanikw, a nastpnie kademu ze wskanikw przypisa adres dynamicznie przydzielonego wiersza. Oto przykad dla tablicy dwuwymiarowej:
F& )
G &,HI
&$&+  &D
&
 & &G  &@@
$&&+  )+&D
&

W rzeczywistym kodzie naleaoby oczywicie sprawdzi wszystkie wartoci zwrcone przez funkcj .
Jeeli nie zamierzasz zmienia dugoci wierszy, a za to chciaby, aby przydzielony
tablicy obszar pamici by cigy, wystarczy odrobina arytmetyki na wskanikach:
&$7&+  &D
&
$7&+   )+&D
&
 & &G  &@@
$7&$7@& )+
7

Mwic cile, nie s to tablice, ale raczej obiekty uywane jak tablice, zobacz pytanie 6.14.

138

Programowanie w jzyku C. FAQ

W obu przypadkach (to znaczy tablic  , i  ) tablice dynamiczne mona indeksowa za pomoc normalnych operatorw:  Z/ (dla .01#*%+) i .0
/1#$%&'(#)). Poniszy rysunek przedstawia schematycznie ukad wierszy w tablicach  , i  .

Jeeli dwa odwoania do pamici w tym schemacie s z jakich powodw nie do przyjcia8, moesz zasymulowa tablic dwuwymiarow dynamicznie stworzon tablic
jednowymiarow:
&$6&+   )+&D
&

Jednak w takim przypadku obliczanie indeksw musisz wykonywa wasnorcznie.


Aby odwoa si do elementu o wsprzdnych ,/, naleaoby uy wyraenia  9
 2 / . Takiej tablicy nie mona jednak przekaza do funkcji, ktra akceptuje tablic wielowymiarow. Zobacz te pytanie 6.19.
Moesz te uy wskanikw do tablic:
&$8.20345.1
&.20345.1+  &D
$8

Zauwa jednak, e dwukrotne odwoanie do tablicy nie musi by wcale mniej efektywne ni jawne
mnoenie indeksw.
Jawne obliczanie indeksu mona ukry w makrodefinicji, na przykad: F
&
J$
%&%*
& )+@*. Jednak wywoanie takiej makrodefinicji, z nawiasami i przecinkami,
nie kojarzyoby si z normaln skadni dostpu do tablic. Makrodefinicja musiaaby mie rwnie
dostp do jednego z wymiarw tablicy.

Rozdzia 6. Tablice i wskaniki

139

albo nawet:
&$-./0 1.20345.1
&./0 1.20345.1+ &D
$-

Jednak skadnia odwoania do elementw wskazywanych tablic robi si coraz bardziej skomplikowana (w przypadku  " trzeba pisa  "/). Najwyej
jeden wymiar tablicy mona okreli w czasie dziaania programu.
Uywajc tych technik, nie mona oczywicie zapomnie o zwolnieniu przydzielonej
pamici, kiedy nie jest ju potrzebna. W przypadku tablic  , i   wymaga to
kilku krokw (zobacz te pytanie 7.23):
 & &G  &@@


K &$&


K &$


K &$7


K &$7

Nie moesz te miesza tablic przydzielonych dynamicznie ze zwykymi, utworzonymi statycznie (zobacz pytanie 6.20, a take 6.18).
Powysze techniki mona oczywicie rozszerzy na trzy i wicej wymiarw. Oto trjwymiarowa wersja pierwszego sposobu:
&6&+ &+&D
&
 & &G&+ &@@
6&&+ $&+&D
&
 * *G$&+ *@@
6&*&+ D&+&D
&


Zobacz te pytanie 20.2.

6.17
Pytanie: Wpadem na fajny pomys jeeli napisz:
&
 $
&$A
 $L

mog traktowa tablic  tak, jakby jej indeksy zaczynay si od 1. Czy to
poprawne?
Odpowied: Chocia taka technika moe wydawa si atrakcyjna (bya nawet uywana w starszych wydaniach ksiki Numerical Recipes in C), nie jest zgodna ze Standardem jzyka C. Arytmetyka wskanikw zdefiniowana jest tylko, jeeli warto
wskanika pozostaje w obrbie tego samego przydzielonego bloku pamici albo
umownego kocowego elementu tu za nim. W przeciwnym wypadku zachowanie
programu jest niezdefiniowane, nawet jeeli nie nastpuje dereferencja wskanika.
Kod w pytaniu oblicza wskanik do obszaru przed pocztkiem tablicy  .

140

Programowanie w jzyku C. FAQ

W momencie odejmowania offsetu moe wystpi bd wygenerowania nieprawidowego adresu (na przykad gdyby obliczenie adresu spowodowao zawinicie wok
pocztku segmentu pamici).
Referencje: K&R2 5.3, 5.4, A7.7
ANSI 3.3.6
ISO 6.3.6
Rationale 3.2.2.3

Funkcje a tablice wielowymiarowe


Trudno jest przekazywa tablice wielowymiarowe do funkcji z zachowaniem penej
oglnoci. Podmiana parametrw tablicowych na wskaniki (zobacz pytanie 6.4)
oznacza, e funkcja, ktra akceptuje zwyke tablice, moe rwnie przyjmowa tablice o dowolnej dugoci, co jest wygodne. Jednak podmiana dotyczy tylko najbardziej
zewntrznej tablicy, pozostae wymiary nie mog by zmienne. Problem ten wynika z faktu, e w jzyku C wymiary tablic musz by zawsze znane w czasie kompilacji. Nie mona ich okreli, przekazujc na przykad dodatkowy parametr.

6.18
Pytanie: Mj kompilator zgasza bdy, kiedy przekazuj tablic dwuwymiarow
do funkcji przyjmujcej wskanik do wskanika. Dlaczego?
Odpowied: Zasada (zobacz pytanie 6.3), na mocy ktrej tablice degeneruj si do
wskanikw, nie dziaa rekurencyjnie. Tablica dwuwymiarowa (czyli w jzyku C tablica tablic) staje si wskanikiem do tablicy, nie wskanikiem do wskanika. Wskaniki do tablic powoduj duo nieporozumie, dlatego naley ich uywa ostronie.
Zobacz pytanie 6.13 (nieporozumienia wzmaga fakt, e istniej kompilatory, w tym
stare wersje  i oparte na nich wersje programu  , ktre niepoprawnie pozwalaj
przypisywa wielowymiarowe tablice do wskanikw na wskaniki).
Jeeli przekazujesz dwuwymiarow tablic do funkcji:
&$./0 1.20345.1
$

jej deklaracja musi mie posta:


&.20345.1


albo:
&.20345.1< =!&=, &E<


Rozdzia 6. Tablice i wskaniki

141

W przypadku pierwszej deklaracji kompilator wykonuje podmian typu parametru


z tablicy tablic na wskanik do tablicy (zobacz pytania 6.3 i 6.4). W drugiej deklaracji jawnie okrelamy typ jako wskanik do tablicy. Poniewa wywoywana funkcja nie przydziela pamici dla tablicy, nie musi zna jej obu wymiarw liczba
wierszy, #*%+), moe zosta pominita w deklaracji. Ksztat tablicy jest jednak wci
wany, wic wymiar #$%&'(#) (i wszystkie kolejne w przypadku tablic wielowymiarowych) musi zosta wyspecyfikowany.
Jeeli deklaracja funkcji wskazuje, e oczekuje ona wskanika do wskanika, najprawdopodobniej nie mona przekaza jej tablicy dwuwymiarowej bezporednio. Moe by wtedy potrzebny pomocniczy wskanik:


&&
&&A$
A& <MNO50PCB3C<

Taki sposb wywoania jest jednak mylcy i prawie na pewno nieprawidowy. Tablica zostaa spaszczona stracilimy informacj o jej szerokoci.
Zobacz te pytania 6.12 i 6.15.
Referencje: K&R1 5.10
K&R2 5.9
H&S 5.4.3

6.19
Pytanie: Jak tworzy funkcje, ktre przyjmuj tablice dwuwymiarowe, jeeli nie
znam ich szerokoci w czasie kompilacji?
Odpowied: To nie jest atwe. Jednym ze sposobw jest przekazanie wskanika do
elementu o indeksach .. wraz z obydwoma wymiarami i rczne obliczanie indeksw:
7&$%& %& )+
$& )+@*<  "&
 

+
)$&*<

Aby jawnie obliczy indeks elementu, potrzebujemy wartoci 2  (szerokoci


kadego wiersza), nie 3 (liczby wierszy). atwo si tu pomyli.
Funkcji tej mona przekaza tablic   z pytania 6.18 w nastpujcy sposb:
7A$%./0 1%.20345.1

Trzeba jednak zauway, e program, w ktrym indeksy w tablicy wielowymiarowej


obliczane s rcznie, nie jest cile zgodny ze Standardem ANSI jzyka C. Zgodnie
z oficjaln interpretacj, dostp do elementu  ..
 jest niezdefiniowany,
jeeli
45#$%&'(#).

142

Programowanie w jzyku C. FAQ

Kompilator GNU C pozwala definiowa lokalne tablice o rozmiarach ustalonych przez


argumenty funkcji, moliwo ta pojawia si te w Standardzie C99.
Jeeli chcesz stworzy funkcj, ktra przyjmowa bdzie tablice wielowymiarowe
o rnych rozmiarach, jednym z rozwiza jest dynamiczne symulowanie takich tablic, jak w pytaniu 6.16.
Zobacz te pytania 6.15, 6.18 i 6.20.
Referencje: ANSI 3.3.6
ISO 6.3.6

6.20
Pytanie: Jak korzysta jednoczenie z wielowymiarowych tablic przydzielanych
statycznie i dynamicznie przy przekazywaniu ich do funkcji?
Odpowied: Nie ma jednej, uniwersalnej metody. Majc deklaracje:
&$./0 1.20345.1
&$ <=Q$&
D  , <
&$7 <&R"$ ,D+&E&<
&$6 <, & "DD  <
&$8.20345.1
&$-./0 1.20345.1

gdzie wskaniki s zainicjalizowane tak, jak w pytaniu 6.16, i funkcje, zadeklarowane


jako:
&.20345.1%& %& )+
7&$%& %& )+
6&%& %& )+

gdzie funkcja , akceptuje zwyk tablic dwuwymiarow, funkcja  spaszczon tablic dwuwymiarow, a funkcja  tablic symulowan przez wskanik
do wskanika (zobacz pytania 6.18 i 6.19), ponisze wywoania funkcji dziaaj
zgodnie z oczekiwaniami:
$%./0 1%.20345.1
$8% %.20345.1
$-%./0 1%.20345.1
7A$%./0 1%.20345.1
7$%./0 1%.20345.1
7$7% % )+
7$6% % )+
7$8% %.20345.1
7$-%./0 1%.20345.1
6$% % )+
6$7% % )+

Rozdzia 6. Tablice i wskaniki

143

Ponisze dwa wywoania powinny dziaa prawidowo na wikszoci systemw, ale


wymagaj podejrzanych rzutowa i dziaaj tylko, jeeli dynamiczna warto 2  rwna jest statycznej #$%&'(#):
&.20345.1$7% % )+
&.20345.1$6% % )+

Z wyej wymienionych tylko funkcja  moe przyjmowa tablice statyczne i przydzielone dynamicznie, chocia nie bdzie dziaa dla tradycyjnej implementacji  ,,
czyli kady wiersz osobno. Pamitaj jednak, e przekazywanie  .. (albo
 ) do funkcji  nie jest cile zgodne ze Standardem zobacz pytanie 6.19.
Jeeli rozumiesz, dlaczego wszystkie wyej wymienione sposoby przekazywania tablic
wielowymiarowych do funkcji dziaaj oraz dlaczego kombinacje, ktrych tu nie przedstawiono, nie dziaaj, moesz uzna, e bardzo dobrze rozumiesz tablice i wskaniki
w jzyku C.
Zamiast jednak zaprzta sobie gow tymi wszystkimi trudnymi reguami, moesz
zastosowa duo prostsze rozwizanie: wszystkie tablice wielowymiarowe twrz dynamicznie, jak w pytaniu 6.16. Jeeli nie bdzie statycznych tablic wielowymiarowych wszystkie bd przydzielane jak  , lub   w pytaniu 6.16 wtedy
wszystkie funkcje mog mie deklaracje podobne do .

Rozmiary tablic
Operator   zwraca rozmiar tablicy, ale tylko wtedy, gdy jest on znany, a odniesienie do tablicy nie zredukowao si do wskanika.

6.21
Pytanie: Dlaczego operator   nie zwraca poprawnego rozmiaru tablicy, ktra
jest parametrem funkcji? Moja testowa funkcja wypisuje 4, zamiast 10:


&&&D

& ?( %&


Odpowied: Kompilator podmienia typ parametru z tablicy na wskanik (w tym przypadku  , zobacz pytanie 6.4). Operator   zwraca w tym wypadku rozmiar
wskanika. Zobacz te pytania 1.24 i 7.28.
Referencje: H&S 7.5.2

144

Programowanie w jzyku C. FAQ

6.22
Pytanie: Jak kod w pliku, w ktrym tablica zadeklarowana jest jako
 (jest
zdefiniowana i jej rozmiar jest okrelony w innym pliku), moe okreli jej wielko? Operator   nie dziaa na niej.
Odpowied: Zobacz pytanie 1.24.

6.23
Pytanie: Jak mog okreli liczb elementw tablicy, jeeli operator   zwraca
rozmiar w bajtach?
Odpowied: Po prostu podziel rozmiar caej tablicy przez rozmiar jednego elementu:
&$%7%6
&$&D
$<&D
$
Referencje: ANSI 3.3.3.4
ISO 6.3.3.4

You might also like