Darmowy fragment publikacji:
Język C. Nowoczesne
programowanie. Wydanie II
Autor: K. N. King
Tłumaczenie: Przemysław Szeremiota
ISBN: 978-83-246-2805-6
Tytuł oryginału: C Programming: A Modern Approach, 2nd Edition
Format: B5, stron: 928
Język C żyje i ma się dobrze. Sprawdź, co nowego w wersji C99!
• Jak wygląda proces standaryzacji języka?
• Jak komentować kod?
• Jak przygotować projekt programu?
Język C należy do nielicznej grupy języków, które sprawdzają się w środowiskach produkcyjnych,
a jednocześnie nadają się do nauki programowania na uczelniach wyższych. Dzięki logicznej
i przejrzystej składni, jasno określonym zasadom wykorzystania oraz ogromnym możliwościom
język ten pomimo swojego wieku cieszy się popularnością i uznaniem. Nawet dziś, kiedy na rynku
panują niepodzielnie Java oraz .NET, język C znalazł swoją niszę i świetnie ją wypełnia. Na tym polu
żaden współczesny język nie ma z nim żadnych szans!
Kolejne wydanie książki rozszerzono między innymi o elementy zawarte w specyfikacji oznaczonej
numerem C99 (ISO 9899:1999). Co jeszcze wyróżnia tę książkę? Jej pierwsze wydanie było
wykorzystywane na kursach programowania prowadzonych przez 225 uczelni. Dzięki temu
zaliczana jest ona do najbardziej znaczących wydawnictw dotyczących języka C. Wydanie drugie
powiela zalety pierwszego, a dodatkowo zostało rozbudowane o jeszcze większą liczbę przykładów,
pytań, ćwiczeń i zadań programistycznych.
W trakcie pasjonującej lektury – zgadza się, K.N. King potrafi w ten sposób pisać o swoim ulubionym
języku – poznasz wszystkie aspekty programowania w języku C, począwszy od jego historii, poprzez
fundamentalne pojęcia funkcji, zmiennych, a skończywszy na zarządzaniu pamięcią oraz wykorzystaniu
wskaźników. „Język C. Nowoczesne programowanie. Wydanie II” to obowiązkowa pozycja dla
każdego studenta poznającego tajniki tego języka. Programiści znający język C niewątpliwie
docenią kunszt autora, a książka znajdzie zastosowanie jako przekrojowy przewodnik – taka
pozycja powinna być na półce każdego programisty!
Poznaj język C, korzystając z uznanego podręcznika!
Idź do
• Spis treści
• Przykładowy rozdział
Katalog książek
• Katalog online
• Zamów drukowany
katalog
Twój koszyk
• Dodaj do koszyka
Cennik i informacje
• Zamów informacje
o nowościach
• Zamów cennik
Czytelnia
• Fragmenty książek
online
Kontakt
Helion SA
ul. Kościuszki 1c
44-100 Gliwice
tel. 32 230 98 63
e-mail: helion@helion.pl
© Helion 1991–2010
SPIS TREĝCI
WstĊp
1. WPROWADZENIE
1.1.
Historia jĊzyka C
Początki
Standaryzacja
JĊzyki oparte na C
1.2. Mocne i sáabsze strony jĊzyka C
Mocne strony
SáaboĞci
Efektywne stosowanie jĊzyka C
2.
FUNDAMENTY JĉZYKA C
2.1.
Piszemy prosty program
WyĞwietlamy cytat
Kompilacja i konsolidacja
Zintegrowane Ğrodowiska programistyczne
2.2. Ogólna postaü prostego programu w C
2.3.
2.4.
Dyrektywy preprocesora
Funkcje
Instrukcje
Wypisywanie ciągów znakowych
Komentarze
Zmienne i przypisania
Typy
Deklaracje
Przypisania
Wypisywanie wartoĞci zmiennej
Obliczanie gabarytu przesyáki
Inicjalizacja
Wypisywanie wartoĞci wyraĪeĔ
19
29
29
29
30
31
32
33
33
34
39
39
40
40
41
42
43
43
44
45
46
48
48
48
49
50
51
52
53
5
6
Spis treĞci
3.
2.5. Wczytywanie danych
2.6.
2.7.
Obliczanie gabarytu przesyáki (podejĞcie drugie)
Definiowanie nazw dla staáych
Konwersja skali Fahrenheita na skalĊ Celsjusza
Identyfikatory
Sáowa kluczowe
2.8. Ogólny ukáad programu C
FORMATOWANIE WEJĝCIA-WYJĝCIA
3.1.
Funkcja printf
Specyfikatory konwersji
Wykorzystanie printf do formatowania liczb
Znaki sterujące
Funkcja scanf
Dziaáanie funkcji scanf
Zwykáe znaki w ciągu formatującym funkcji scanf
Skutki mylenia printf ze scanf
Dodawanie uáamków
3.2.
4. WYRAĩENIA
4.1. Operatory arytmetyczne
PierwszeĔstwo i áącznoĞü operatorów
Obliczanie cyfry kontrolnej kodu kreskowego
4.2. Operatory przypisania
Przypisania proste
L-wartoĞci
Przypisania záoĪone
4.3. Operatory inkrementacji i dekrementacji
4.4. Obliczanie wartoĞci wyraĪeĔ
KolejnoĞü obliczania podwyraĪeĔ
Instrukcje wyraĪeniowe
4.5.
5.
INSTRUKCJE WYBORU
5.1. WyraĪenia logiczne
Operatory relacji
Operatory porównaĔ
Operatory logiczne
Instrukcja if
Instrukcje blokowe
Klauzula else
Kaskadowe instrukcje if
Obliczanie prowizji brokera gieádowego
Problem „bezpaĔskiego” else
WyraĪenia warunkowe
WartoĞci boolowskie w C89
WartoĞci boolowskie w C99
Instrukcja switch
Rola instrukcji break
Wypisywanie daty w zapisie urzĊdowym
5.2.
5.3.
53
54
55
55
57
58
58
69
69
70
72
73
74
76
78
79
79
85
86
87
88
91
91
92
93
94
96
97
98
107
108
108
109
109
111
112
112
114
115
116
117
118
120
120
123
124
Spis treĞci
7
133
134
135
136
137
137
138
139
141
142
143
143
144
146
146
147
148
149
151
6.4.
6.5.
7.1.
7.2.
7.3.
7.4.
7.5.
6.
6.2.
6.3.
INSTRUKCJE PĉTLI
Instrukcja while
6.1.
PĊtle nieskoĔczone
Wypisywanie tabeli kwadratów liczb
Obliczanie sumy szeregu liczb
Instrukcja do
Obliczanie liczby cyfr w liczbie caákowitej
Instrukcja for
Idiomy instrukcji for
Pomijanie wyraĪeĔ w instrukcji for
Instrukcje for w C99
Operator przecinka
Wypisywanie tabeli kwadratów liczb (podejĞcie drugie)
Przerywanie pĊtli
Instrukcja break
Instrukcja continue
Instrukcja goto
Saldo konta
Instrukcja pusta
7. PODSTAWOWE TYPY C
161
Typy caákowite
161
Typy caákowite w C99
164
Literaáy caákowite
164
Literaáy caákowite w C99
166
Przepeánienie zakresu
166
Wczytywanie i wypisywanie wartoĞci caákowitych
166
Sumowanie szeregu liczb caákowitych (podejĞcie drugie)
167
Typy zmiennoprzecinkowe
168
Literaáy zmiennoprzecinkowe
170
Wczytywanie i wypisywanie wartoĞci zmiennoprzecinkowych
170
Typy znakowe
171
Operacje na znakach
172
Znaki ze znakiem i bez znaku
173
Typy arytmetyczne
173
Znaki sterujące
174
Funkcje do manipulowania znakami
176
Wczytywanie i wypisywanie znaków funkcjami scanf i printf
176
Wczytywanie i wypisywanie znaków funkcjami getchar i putchar 177
179
OkreĞlanie dáugoĞci komunikatu
180
Konwersja typów
181
Zwyczajne konwersje arytmetyczne
Konwersja przy przypisaniu
183
184
Niejawne konwersje w C99
185
Rzutowanie
186
Definicje typów
187
Zalety definicji typów
Definicje typów a przenoĞnoĞü programów
188
189
7.6. Operator sizeof
8
Spis treĞci
8.
9.
TABLICE
8.1.
Tablice jednowymiarowe
Indeksowanie tablic
Odwracanie szeregu liczbowego
Inicjalizacja tablicy
Inicjalizatory desygnowane
Sprawdzanie, czy liczba zawiera powtarzające siĊ cyfry
Operator sizeof dla tablic
Naliczanie odsetek
Tablice wielowymiarowe
Inicjalizowanie tablic wielowymiarowych
Staáe tablicowe
Rozdawanie kart
Tablice o zmiennej liczbie elementów (C99)
FUNKCJE
9.1.
8.2.
8.3.
9.2.
9.3.
9.4.
9.5.
9.6.
Definiowanie i wywoáywanie funkcji
Obliczanie Ğrednich
Odliczanie
WyĞwietlanie napisu (kolejne podejĞcie)
Definicja funkcji
Wywoáanie funkcji
Sprawdzanie, czy podana liczba jest liczbą pierwszą
Deklaracja funkcji
Argumenty
Konwersje argumentów
Argumenty tablicowe
Parametry tablicowe o zmiennym rozmiarze
Deklaracje parametrów tablicowych ze sáowem static
Literaáy tablicowe
Instrukcja return
ZakoĔczenie programu
Funkcja exit
Rekurencja
Algorytm quicksort
quicksort
10. ORGANIZACJA PROGRAMU
10.1. Zmienne lokalne
Zmienne statyczne funkcji
Parametry
10.2. Zmienne zewnĊtrzne
10.3. Bloki
10.4. ZasiĊg zmiennych
10.5. Organizacja programu w C
Siáa rozdania pokerowego
Przykáad. Stos implementowany na zmiennych zewnĊtrznych
Zalety i wady zmiennych zewnĊtrznych
Zgadywanka liczbowa
199
199
200
202
203
203
204
205
206
208
209
210
211
212
223
223
224
225
226
227
229
230
231
233
234
235
238
240
241
242
243
243
244
246
248
261
261
262
263
263
263
264
266
270
271
272
273
Spis treĞci
9
11. WSKAħNIKI
11.1. Zmienne wskaĨnikowe
Deklarowanie zmiennych wskaĨnikowych
11.2. Operator adresu i wyáuskania
Operator adresu
Operator wyáuskania
11.3. Przypisania a wskaĨniki
11.4. WskaĨniki jako argumenty funkcji
Wyszukiwanie najwiĊkszego i najmniejszego elementu tablicy
Ochrona argumentów za pomocą const
11.5. WskaĨniki jako wartoĞci zwracane
12. WSKAħNIKI A TABLICE
12.1. Arytmetyka wskaĨników
Dodawanie liczby do wskaĨnika
Odejmowanie liczby od wskaĨnika
Odejmowanie wskaĨnika od wskaĨnika
Porównywanie wskaĨników
WskaĨniki do literaáów tablicowych
12.2. Przetwarzanie tablic na bazie wskaĨników
àączenie operatorów * i ++
12.3. Nazwa tablicy jako wskaĨnik
Odwracanie szeregu liczbowego
Argumenty tablicowe (ponownie)
WskaĨnik jako nazwa tablicy
12.4. WskaĨniki a tablice wielowymiarowe
Przetwarzanie elementów tablicy wielowymiarowej
Przetwarzanie wierszy tablicy wielowymiarowej
Przetwarzanie kolumn tablicy wielowymiarowej
Nazwa tablicy wielowymiarowej jako wskaĨnik
12.5. WskaĨniki a tablice o zmiennym rozmiarze (C99)
13. CIĄGI ZNAKÓW
13.1. Literaáy napisowe
Znaki sterujące w literaáach napisowych
Kontynuacja literaáu napisowego w nowym wierszu
Literaáy napisowe a pamiĊü programu
Operacje na literaáach napisowych
Literaáy napisowe a literaáy znakowe
13.2. Zmienne napisowe
Inicjalizowanie zmiennej napisowej
Tablice znaków a wskaĨniki do znaków
13.3. Wczytywanie i wypisywanie napisów
Wypisywanie napisów funkcjami printf i puts
Wczytywanie ciągów znaków funkcjami scanf i gets
Wczytywanie napisów znak po znaku
13.4. Odwoáania do pojedynczych znaków w ciągu
13.5. Funkcje biblioteczne jĊzyka C
Funkcja strcpy (kopiowanie ciągów)
Funkcja strlen (dáugoĞü ciągu)
Funkcja strcat (áączenie ciągów)
283
283
284
285
285
286
287
289
291
293
293
301
302
303
303
304
304
304
305
306
307
308
309
311
311
311
312
313
314
314
323
323
324
324
325
326
326
327
328
329
330
330
331
333
334
335
336
338
338
10
Spis treĞci
13.6.
Funkcja strcmp (porównywanie ciągów)
Wypisywanie notatek kalendarzowych
Idiomy
Szukanie koĔca ciągu
Kopiowanie ciągu
13.7. Tablice ciągów znaków
Argumenty wywoáania programu
Weryfikacja nazw planet
14. PREPROCESOR
14.1. Jak dziaáa preprocesor
14.2. Dyrektywy preprocesora
14.3. Makrodefinicje
Makrodefinicje proste
Makrodefinicje sparametryzowane
Operator #
Operator ##
Ogólne wáaĞciwoĞci makrodefinicji
Nawiasy w makrodefinicjach
Tworzenie dáugich makrodefinicji
Makrodefinicje predefiniowane
Dodatkowe makrodefinicje predefiniowane w C99
Puste argumenty makrodefinicji
Makrodefinicje o zmiennej liczbie argumentów
Identyfikator __func__
14.4. Warunkowa kompilacja kodu
Dyrektywy #if i #endif
Operator defined
Dyrektywy #ifdef i #ifndef
Dyrektywy #elif i #else
Zastosowania warunkowej kompilacji kodu
Inne dyrektywy
Dyrektywa #error
Dyrektywa #line
Dyrektywa #pragma
Operator _Pragma
14.5.
15. DUĩE PROGRAMY
15.1. Pliki Ĩródáowe
15.2. Pliki nagáówkowe
Dyrektywa #include
Wspólne makrodefinicje i synonimy typów
Wspólne prototypy funkcji
Wspólne deklaracje zmiennych
ZagnieĪdĪone dyrektywy #include
Ochrona plików nagáówkowych
Dyrektywy #error w plikach nagáówkowych
15.3. Podziaá programu na pliki
Formatowanie tekstu
15.4. Budowanie programu z wielu plików
Pliki Makefile
BáĊdy konsolidowania programu
339
340
343
343
345
347
349
351
363
363
366
367
367
370
373
374
375
376
377
379
380
381
382
383
384
384
385
386
386
387
388
389
390
391
391
401
401
403
403
405
406
407
409
410
411
411
412
419
419
422
Spis treĞci
11
Przebudowa programu
Definiowanie makrodefinicji na zewnątrz programu
16. STRUKTURY, UNIE I WYLICZENIA
16.1. Zmienne strukturalne
Deklarowanie zmiennych strukturalnych
Inicjalizowanie zmiennych strukturowych
Inicjalizatory desygnowane
Operacje na strukturach
16.2. Typy strukturowe
Deklarowanie znacznika struktury
Definiowanie typu strukturowego
Struktury jako argumenty i wartoĞci zwracane funkcji
Literaáy strukturowe
16.3. Tablice i struktury zagnieĪdĪone
Struktury struktur
Tablice struktur
Inicjalizowanie tablic struktur
Zarządzanie bazą danych magazynu
16.4. Unie
Unie dla oszczĊdnoĞci
Unie jako mieszane struktury danych
Pole „wyróĪnika” w unii
16.5. Wyliczenia
Znaczniki i typy wyliczeniowe
Wyliczenia jako liczby caákowite
Wyliczenia jako wyróĪniki unii
17. ZAAWANSOWANE ZASTOSOWANIA WSKAħNIKÓW
17.1. Dynamiczny przydziaá pamiĊci
Funkcje przydziaáu pamiĊci
WskaĨniki puste
17.2. Dynamiczny przydziaá ciągów znaków
Przydziaá pamiĊci dla ciągu znaków za pomocą funkcji malloc
Przydziaáy dynamiczne
w funkcjach operujących na ciągach znaków
Tablice ciągów przydzielanych dynamicznie
Wypisywanie notatek kalendarzowych (podejĞcie drugie)
17.3. Tablice przydzielane dynamicznie
Przydziaá pamiĊci dla ciągu znaków za pomocą funkcji malloc
Funkcja calloc
Funkcja realloc
17.4. Zwalnianie pamiĊci
Funkcja free
Problem „wiszących” wskaĨników
17.5. Listy elementów
Deklarowanie typu wĊzáa
Tworzenie wĊzáa listy
Operator -
Wstawianie wĊzáa na początek listy
Przeszukiwanie listy
Usuwanie wĊzáa z listy
422
425
431
431
432
433
434
435
436
437
438
439
440
441
441
442
443
444
450
452
454
455
456
457
458
459
469
470
470
471
472
472
473
474
475
476
477
478
478
479
480
481
481
482
483
484
484
487
488
12
Spis treĞci
Listy uporządkowane
Zarządzanie bazą danych magazynu (drugie podejĞcie)
17.6. WskaĨniki do wskaĨników
17.7. WskaĨniki do funkcji
WskaĨniki do funkcji w roli argumentów
Funkcja qsort
Inne zastosowania wskaĨników do funkcji
Tablice funkcji trygonometrycznych
17.8. WskaĨniki zastrzeĪone (C99)
17.9. Elastyczne skáadowe tablicowe (C99)
18. DEKLARACJE
18.1. Skáadnia deklaracji
18.2. Klasy przydziaáu
WáasnoĞci zmiennych
Klasa przydziaáu auto
Klasa przydziaáu static
Klasa przydziaáu extern
Klasa przydziaáu register
Klasa przydziaáu funkcji
Podsumowanie
18.3. Kwalifikatory typów
18.4. Deklaratory
Rozszyfrowywanie zawiáych deklaracji
Stosowanie synonimów typów dla uproszczenia deklaracji
Inicjalizatory
Zmienne niezainicjalizowane
18.5.
18.6. Funkcje inline (C99)
Definicje rozwijane w miejscu wywoáania
Ograniczenia funkcji rozwijanych w miejscu wywoáania
Funkcje inline w GCC
19. PROJEKT PROGRAMU
19.1. Moduáy
SpójnoĞü i wspóázaleĪnoĞü
Rodzaje moduáów
19.2. Ukrywanie informacji
Moduá obsáugi stosu
19.3. Abstrakcyjne typy danych
Hermetyzacja
Typy niepeáne
19.4. Stos jako abstrakcyjny typ danych (ADT)
Definiowanie interfejsu stosu w wersji ADT
Implementacja stosu w wersji ADT (na bazie tablicy)
Zmiana typu elementu w stosie w wersji ADT
Implementowanie stosu ADT (na bazie tablicy dynamicznej)
Implementowanie stosu ADT (na bazie listy)
19.5. Problemy projektowe przy ADT
Nomenklatura
Obsáuga báĊdów
Uniwersalny typ ADT
ADT w nowszych jĊzykach programowania
490
491
496
497
497
498
501
502
503
505
517
517
519
519
520
521
522
523
524
525
526
528
529
531
531
533
533
534
536
536
545
546
548
548
549
550
553
554
554
555
555
557
559
560
562
564
564
565
565
566
20. PROGRAMOWANIE NISKOPOZIOMOWE
Spis treĞci
20.1. Operatory bitowe
Operatory przesuniĊü bitowych
Negacja, iloczyn, suma i suma wyáączająca
Operatory bitowe w odwoáaniach
do poszczególnych bitów wartoĞci liczbowych
Operatory bitowe w odwoáaniach do pól bitowych
Szyfrowanie XOR
20.3.
20.2. Pola bitowe w strukturach
Reprezentacja pól bitowych
Inne niskopoziomowe techniki programistyczne
Definiowanie typów maszynowych
Unie jako perspektywy
WskaĨniki jako adresy
Podgląd pamiĊci
Kwalifikator typu volatile
21. BIBLIOTEKA STANDARDOWA
21.1. Stosowanie biblioteki standardowej
Nazewnictwo w bibliotece standardowej
Funkcje ukrywane przez makrodefinicje
21.2. Przegląd biblioteki standardowej C89
Diagnostyka
Obsáuga znaków
BáĊdy
Cechy typów zmiennoprzecinkowych
Rozmiary typów caákowitoliczbowych
Lokalizacja programów
Matematyka
Skoki nielokalne
Obsáuga sygnaáów
Zmienne listy argumentów
Podstawowe definicje
WejĞcie-wyjĞcie
NarzĊdzia
Obsáuga ciągów znaków
Daty i godziny
21.3. Uzupeánienia i zmiany w C99
Arytmetyka liczb zespolonych
ĝrodowisko implementacji zmiennoprzecinkowej
Znakowe konwersje typów caákowitoliczbowych
Alternatywny zapis skáadni C
WartoĞci i typy logiczne
Typy caákowitoliczbowe
Matematyka na uniwersalnych typach
Operacje na znakach wielobajtowych
NarzĊdzia mapowania i klasyfikacji znaków wielobajtowych
21.4. Nagáówek stddef.h — definicje podstawowe
21.5. Nagáówek stdbool.h (C99) — typy i wartoĞci logiczne
13
571
571
572
573
574
576
577
578
580
581
581
582
584
584
586
593
593
594
595
596
596
596
596
596
596
597
597
597
597
597
597
597
598
598
598
598
599
599
599
599
599
599
599
600
600
600
601
14
Spis treĞci
22. WEJĝCIE-WYJĝCIE
22.1. Strumienie
WskaĨniki plikowe
Strumienie standardowe a przekierowania
Pliki tekstowe i pliki binarne
22.2. Operacje na plikach
Otwieranie pliku
Tryby dostĊpu do plików
Zamykanie pliku
Doáączanie pliku do otwartego strumienia
Pobieranie nazw plików z wiersza polecenia
Sprawdzanie moĪliwoĞci otwarcia pliku
Pliki tymczasowe
Buforowanie plików
Inne operacje na plikach
22.3. Formatowanie wejĞcia-wyjĞcia
Funkcje …printf
Specyfikatory konwersji dla funkcji …printf
Zmiany specyfikatorów konwersji w C99
Przykáady specyfikacji konwersji dla funkcji …printf
Funkcje …scanf
Ciągi formatujące funkcji …scanf
Specyfikacje konwersji funkcji …scanf
Zmiany specyfikatorów konwersji w C99
Przykáady dla funkcji scanf
Wykrywanie koĔca strumienia wejĞciowego i báĊdów
22.4. WejĞcie-wyjĞcie znakowe
605
606
606
607
608
609
610
611
612
613
613
614
615
616
618
619
619
620
622
624
626
627
628
631
631
632
635
635
636
637
638
638
639
640
641
643
644
645
646
668
Funkcje wyjĞcia
Funkcje wejĞcia
Kopiowanie pliku
Funkcje wyjĞcia
Funkcje wejĞcia
22.5. Wierszowe wejĞcie-wyjĞcie
22.6. Blokowe wejĞcie-wyjĞcie
22.7. Pozycjonowanie w plikach
Modyfikowanie pliku rekordów bazy danych
22.8. Funkcje wejĞcia-wyjĞcia w pamiĊci
Funkcje wyjĞcia
Funkcje wejĞcia
23. OBSàUGA LICZB I DANYCH ZNAKOWYCH
659
23.1. Nagáówek float.h — cechy typów zmiennoprzecinkowych 659
23.2. Nagáówek limits.h — rozmiary typów caákowitych
662
664
23.3. Nagáówek math.h — matematyka
664
665
666
666
667
BáĊdy
Funkcje trygonometryczne
Funkcje hiperboliczne
Funkcje wykáadnicze i logarytmiczne
Funkcje potĊgowe
NajbliĪsza liczba caákowita, wartoĞü bezwzglĊdna,
reszta z dzielenia
Spis treĞci
23.4. Nagáówek math.h — matematyka (C99)
Standard zmiennoprzecinkowy IEEE
Typy
Makrodefinicje
BáĊdy
Funkcje
Makrodefinicje klasyfikujące
Funkcje trygonometryczne
Funkcje hiperboliczne
Funkcje wykáadnicze i logarytmiczne
Funkcje potĊgowe i funkcje wartoĞci bezwzglĊdnej
Funkcje báĊdów i funkcje gamma
Funkcje zaokrąglania
Funkcje reszty z dzielenia
Funkcja manipulacji
Funkcje maksimum, minimum i róĪnicy dodatniej
Zmiennoprzecinkowy iloczyn-suma
Makrodefinicje porównaĔ
23.5. Nagáówek ctype.h — obsáuga znaków
Funkcje klasyfikacji znaków
Test funkcji klasyfikacji znaków
Funkcje mapowania wielkoĞci liter
Test funkcji zmiany wielkoĞci liter
23.6. Nagáówek string.h — obsáuga ciągów znaków
Funkcje kopiujące
Funkcje áączenia ciągów
Funkcje porównaĔ
Funkcje wyszukujące
RóĪne
24. OBSàUGA BàĉDÓW
24.1. Nagáówek assert.h — diagnostyka
24.2. Nagáówek errno.h — báĊdy
Funkcje perror i strerror
24.3. Nagáówek signal.h — obsáuga sygnaáów
Makrodefinicje sygnaáów
Funkcja signal
Predefiniowane funkcje obsáugi sygnaáów
Funkcja raise
Testowanie mechanizmu sygnaáów
24.4. Nagáówek setjmp.h — skoki nielokalne
Testowanie setjmp/longjmp
25. „MIĉDZYNARODÓWKA”
25.1. Nagáówek locale.h — Ğrodowiska jĊzykowe
Kategorie
Funkcja setlocale
Funkcja localeconv
25.2. Znaki wielobajtowe i znaki poszerzone
Znaki wielobajtowe
Znaki poszerzone
Unicode i uniwersalny zestaw znaków UCS
15
669
669
671
671
672
673
674
675
675
676
677
678
679
680
680
681
682
683
684
684
685
686
687
687
688
689
690
691
695
699
700
701
702
703
704
704
705
707
707
708
709
715
716
716
717
719
722
723
724
724
16
Spis treĞci
25.3. Dwuznaki i trójznaki
725
Kodowanie Unicode
Funkcje konwersji znaków poszerzonych i wielobajtowych
727
Funkcje konwersji ciągów znaków poszerzonych i wielobajtowych 729
729
730
731
731
732
Trójznaki
Dwuznaki
Nagáówek iso646.h — symbole alternatywne
25.4. Uniwersalne nazwy znaków (C99)
25.5. Nagáówek wchar.h (C99) — dodatkowe narzĊdzia
733
734
735
737
738
743
743
747
747
748
749
750
755
755
758
758
759
760
761
762
764
765
766
768
769
770
771
772
774
778
787
788
788
790
790
791
dla znaków poszerzonych i wielobajtowych
Orientacja strumienia
Funkcje formatowanego wejĞcia-wyjĞcia
dla znaków poszerzonych
Funkcje wejĞcia-wyjĞcia dla znaków poszerzonych
Obsáuga ciągów znaków poszerzonych
Funkcja konwersji dat i godzin na ciągi znaków poszerzonych
Dodatkowe funkcje konwersji znaków poszerzonych
i wielobajtowych
25.6. Nagáówek wctype.h (C99) — klasyfikacja
znaków poszerzonych
Funkcje klasyfikacji znaków poszerzonych
Rozszerzalne funkcje klasyfikacji znaków poszerzonych
Funkcje zmiany wielkoĞci liter dla znaków poszerzonych
Rozszerzalne funkcje zmiany wielkoĞci liter
znaków poszerzonych
26. RÓĩNE
26.1. Nagáówek stdarg.h — zmienna liczba argumentów
Wywoáanie funkcji o zmiennej liczbie argumentów
Funkcje v…printf
Funkcje v…scanf
26.2. Nagáówek stdlib.h — inne narzĊdzia
Funkcje konwersji liczbowych
Testowanie funkcji konwersji liczbowych
Funkcje sekwencji pseudolosowych
Testowanie funkcji generowania liczb pseudolosowych
Komunikacja ze Ğrodowiskiem wykonawczym
Wyszukiwanie i sortowanie
OkreĞlanie odlegáoĞci
Funkcje arytmetyki liczb caákowitych
26.3. Nagáówek time.h — daty i godziny
Funkcje operujące na datach i godzinach
Funkcje konwersji dat i godzin
Wypisywanie daty i godziny
27. ROZSZERZONE OPERACJE MATEMATYCZNE W C99
27.1. Nagáówek stdint.h — typy caákowite
Typy nagáówka stdint.h
Ograniczenia typów o okreĞlonym rozmiarze
Ograniczenia pozostaáych typów caákowitych
Makrodefinicje dla staáych caákowitych
Spis treĞci
27.2. Nagáówek inttypes.h — konwersje typów caákowitych
Makrodefinicje dla specyfikatorów konwersji
Funkcje obsáugi najszerszych typów
27.3. Liczby zespolone (C99)
Definicja liczb zespolonych
Arytmetyka liczb zespolonych
Typy zespolone w C99
Operacje na wartoĞciach zespolonych
Reguáy konwersji dla typów zespolonych
27.4. Nagáówek complex.h (C99) — arytmetyka
liczb zespolonych
Makrodefinicje nagáówka complex.h
CX_LIMITED_RANGE
Funkcje nagáówka complex.h
Funkcje trygonometryczne
Funkcje hiperboliczne
Funkcje wykáadnicze i logarytmiczne
Funkcje potĊgowe i funkcje wartoĞci bezwzglĊdnych
Inne
Szukanie pierwiastków równania kwadratowego
27.5. Nagáówek tgmath.h (C99) — matematyka bez typów
Makrodefinicje rozprowadzające wywoáania
funkcji matematycznych
Wywoáania makrodefinicji rozprowadzających
27.6. Nagáówek fenv.h (C99)
— Ğrodowisko zmiennoprzecinkowe
Stany i tryby jednostki zmiennoprzecinkowej
Makrodefinicje nagáówka fenv.h
FENV_ACCESS
Funkcje wyjątków zmiennoprzecinkowych
Funkcje zaokrąglania
Funkcje Ğrodowiska
Dodatek A Operatory jĊzyka C
Dodatek B C99 kontra C89
Dodatek C C89 kontra K R
Dodatek D Funkcje biblioteki standardowej
Dodatek E
Zestaw znaków ASCII
Bibliografia
Skorowidz
17
792
792
793
795
795
797
797
798
798
800
800
801
802
802
803
804
804
805
805
806
807
807
810
810
811
811
813
814
815
819
821
827
831
893
895
899
3 Formatowanie
wejĞcia-wyjĞcia
W poszukiwaniu nieosiągalnego na przeszkodzie staje tylko prostota.
Do najczĊĞciej wykorzystywanych funkcji bibliotecznych jĊzyka C naleĪą printf
i scanf, sáuĪące do obsáugi formatowanego wejĞcia i wyjĞcia programu. W tym
rozdziale przekonasz siĊ o moĪliwoĞciach tych funkcji, ale teĪ o koniecznej ostroĪ-
noĞci w ich stosowaniu. W podrozdziale 3.1 zajmiemy siĊ funkcją printf. Gáów-
nym zagadnieniem podrozdziaáu 3.2 bĊdzie funkcja scanf. W Īadnym z pod-
rozdziaáów nie zgáĊbimy jednak wszystkich detali — niektóre bĊdą musiaáy
poczekaü do rozdziaáu 22.
3.1. Funkcja printf
Funkcja printf sáuĪy do wypisywania na wyjĞciu programu zawartoĞci ciągu
znaków, okreĞlanego mianem ciągu formatującego, który moĪe zawieraü sym-
bole zastĊpcze dla wartoĞci zmiennych wstawianych do ciągu wypisywanego.
W wywoáaniu funkcji printf musi siĊ znajdowaü ciąg formatujący, uzupeániony
wartoĞciami, które mają byü podstawione w odpowiednie miejsca ciągu na wyjĞciu
programu:
printf(ciÈg-formatujÈcy, wyraĝenie1, wyraĝenie1, …);
WartoĞci przekazywane do podstawienia do ciągu formatującego mogą byü sta-
áymi, zmiennymi albo caáymi wyraĪeniami. Nie istnieje ograniczenie liczby war-
toĞci wypisywanych w ramach pojedynczego wywoáania funkcji printf.
Ciąg formatujący moĪe zawieraü zarówno zwyczajne znaki drukowalne, jak
i tak zwane specyfikatory konwersji, rozpoczynające siĊ od znaku . Specyfi-
kator konwersji to symbol zastĊpczy reprezentujący wartoĞü, która ma zostaü
wstawiona w dane miejsce ciągu formatującego, wraz z opisem sposobu wypisa-
nia wartoĞci. Informacje znajdujące siĊ za znakiem okreĞlają sposób konwersji
69
70
Rozdziaá 3. Formatowanie wejĞcia-wyjĞcia
przekazanej wartoĞci z jej reprezentacji wewnĊtrznej (binarnej) na reprezentacjĊ
drukowaną (znakową) — stąd pojĊcie „specyfikatora konwersji”. Na przykáad
specyfikator konwersji d mówi, Īe printf ma zamieniü przekazaną wartoĞü
typu int z jej reprezentacji binarnej na ciąg znaków kolejnych cyfr. Podobnie
specyfikator f nakazuje zamianĊ wartoĞci zmiennoprzecinkowej (typu float)
na znakową.
Zwyczajne znaki zawarte w ciągu formatującym są wypisywane bez modyfi-
kacji. Specyfikatory konwersji są natomiast zastĊpowane przez znakowe repre-
zentacje przekazanych wartoĞci. WeĨmy nastĊpujący przykáad:
int i, j;
float x, y;
i = 10;
j = 20;
x = 43.2892f;
y = 5527.0f;
printf( i = d, j = d, x = f, y = f
, i, j, x, y);
Takie wywoáanie funkcji printf spowoduje wypisanie na wyjĞciu:
i = 10, j = 20, x = 43.289200, y = 5527.000000
Zwyczajne znaki w ciągu formatującym zostaáy po prostu skopiowane na wyjĞcie.
Cztery specyfikatory konwersji zostaáy zaĞ zastąpione przez odpowiednio repre-
zentowane wartoĞci zmiennych i, j, x i y (w tej kolejnoĞci).
Specyfikatory konwersji
Specyfikatory konwersji pozwalają programistom zachowaü duĪą dozĊ kontroli
nad wyglądem (formatem) wypisywanych ciągów i wartoĞci. Z drugiej strony
bywają skomplikowane i trudne do ogarniĊcia. Istotnie, szczegóáowe opisywanie
specyfikatorów konwersji byáoby na tym wstĊpnym etapie omówienia przed-
wczesne. Zapoznamy siĊ wiĊc tylko z najwaĪniejszymi cechami i moĪliwoĞciami
dawanymi przez specyfikatory.
W rozdziale 2. zauwaĪyliĞmy, Īe specyfikator konwersji moĪe zawieraü infor-
macje sterujące formatowaniem wartoĞci. W szczególnoĞci zastosowaliĞmy spe-
cyfikator .1f, aby ograniczyü liczbĊ wypisywanych cyfr po przecinku w war-
toĞci typu float. Ogólniej rzecz biorąc, specyfikator konwersji moĪe przyjąü
postaü m.pX albo -m.pX, gdzie m i p to staáe caákowite, a X to litera. WartoĞci
m i p są opcjonalne. W przypadku nieobecnoĞci p nie stosuje siĊ równieĪ kropki
oddzielającej m od p. W specyfikatorze konwersji 10.2f m wynosi 10, p wy-
nosi 2, a X to f. W specyfikatorze 10f m wynosi 10, p (wraz z kropką) zostaáo
pominiĊte, a X to f. Za to w .2f m zostaáo pominiĊte, a p wynosi 2.
Minimalna szerokoĞü pola m okreĞla minimalną liczbĊ znaków, jaka zostanie
wypisana na wyjĞciu przy wypisywaniu wartoĞci. JeĞli wypisywana wartoĞü jest
w reprezentacji znakowej krótsza niĪ m znaków, zostanie wyrównana do minimal-
nej szerokoĞci pola i do prawej strony pola (innymi sáowy, przed wáaĞciwą war-
toĞü wstawiona bĊdzie odpowiednia liczba spacji). Na przykáad specyfikator 4d
3.1. Funkcja printf
71
Standard nie wymaga od kompilatorów jĊzyka C sprawdzania, czy liczba specy-
fikatorów konwersji okreĞlona w ciągu formatującym odpowiada liczbie przeka-
zanych wartoĞci. PoniĪsze wywoáanie funkcji printf posiada wiĊcej specyfika-
torów konwersji niĪ wartoĞci do wypisania:
printf( d d
, i); /*** ħLE ***/
Funkcja printf wypisze poprawnie wartoĞü zmiennej i, a nastĊpnie wypisze
drugą — oczekiwaną, ale nieokreĞloną — wartoĞü liczbową. Podobnie káopotliwy
jest nadmiar wartoĞci w stosunku do specyfikatorów konwersji:
printf( d
, i, j); /*** ħLE ***/
W tym przypadku funkcja printf wypisze jedynie wartoĞü i, a wartoĞü j zosta-
nie pominiĊta.
Kompilatory nie są teĪ zobligowane do sprawdzania, czy specyfikatory kon-
wersji odpowiadają typom przekazywanych wartoĞci. JeĞli programista zastosuje
nieodpowiednie specyfikatory, program moĪe wypisaü na wyjĞciu kompletne
bzdury. WeĨmy dla przykáadu wywoáanie funkcji printf, w którym zmienna i
typu int i zmienna x typu float zostaną przekazane w záej kolejnoĞci:
printf( f d
, i, x); /*** ħLE ***/
PoniewaĪ funkcja printf realizuje wytyczne z ciągu formatującego, wypisze
na wyjĞciu wartoĞü float, a za nią wartoĞü int. Niestety, obie wartoĞci jako Ĩle
zinterpretowane bĊdą niepoprawne.
spowoduje wypisanie wartoĞci 123 jako ·123 (w caáym bieĪącym rozdziale
w miejsce niewidocznych spacji ilustrujących formatowanie wartoĞci bĊdą wsta-
wiane znaki ·). Z kolei kiedy wypisywana wartoĞü bĊdzie dáuĪsza niĪ m znaków,
pole zostanie automatycznie poszerzone do szerokoĞci potrzebnej do zmieszczenia
wartoĞci: specyfikator 4d dla wartoĞci 12345 spowoduje wypisanie na wyjĞciu
12345 — bez ucinania cyfr. Znak minusa przed m wymusza wyrównanie wartoĞci
w polu do lewej strony: specyfikator 4d dla wartoĞci 123 da na wyjĞciu 123·.
Znaczenie specyfikatora precyzji p jest trudniejsze do opisania, poniewaĪ jego
dziaáanie jest zaleĪne od X, czyli wáaĞciwego specyfikatora konwersji. X okreĞla
rodzaj konwersji do przeprowadzenia przed wypisaniem wartoĞci. Do najpopu-
larniejszych konwersji wartoĞci liczbowych naleĪą:
Q d — konwersja wartoĞci caákowitej do postaci dziesiĊtnej. W takim ukáadzie
p oznacza minimalną liczbĊ cyfr do wypisania (w razie potrzeby przed wypi-
sywaną liczbą dopisywane są zera). Przy braku p uznaje siĊ, Īe ma ono wartoĞü
1 (innymi sáowy, d jest tym samym co .1d).
Q e — konwersja wartoĞci zmiennoprzecinkowej do postaci wykáadnikowej
(w tzw. notacji naukowej). W takim ukáadzie p okreĞla liczbĊ cyfr do wypi-
sania po przecinku dziesiĊtnym (wartoĞü domyĞlna to 6). Dla p równego 0
czĊĞü po przecinku nie jest wyĞwietlana w ogóle.
Q f — konwersja wartoĞci zmiennoprzecinkowej do postaci dziesiĊtnej, bez
wykáadnika. W tym ukáadzie p ma takie samo znaczenie jak przy konwersji e.
72
Rozdziaá 3. Formatowanie wejĞcia-wyjĞcia
Q g — konwersja wartoĞci zmiennoprzecinkowej do postaci wykáadnikowej albo
dziesiĊtnej, zaleĪnie od rozmiaru liczby. W tym ukáadzie p oznacza maksy-
malną liczbĊ cyfr znaczących (nie cyfr po przecinku) do wypisania. Inaczej niĪ
przy konwersji f, konwersja g nie bĊdzie wypisywaáa zer po prawej stronie
wartoĞci. Co wiĊcej, jeĞli konwertowana wartoĞü nie ma cyfr po przecinku,
konwersja g nie wypisze takĪe symbolu przecinka.
Specyfikator konwersji g jest przydatny zwáaszcza do wypisywania wartoĞci, dla
których rozmiar reprezentacji nie da siĊ ustaliü na etapie pisania programu, oraz
wartoĞci z bardzo szerokich dziedzin. Konwersja g dla niezbyt wielkich i niezbyt
maáych wartoĞci bĊdzie owocowaáa zapisem dziesiĊtnym. Dla wartoĞci bardzo
maáych i bardzo duĪych zastosowany bĊdzie zapis wykáadnikowy, wymagający
mniejszej liczby znaków.
d, e, f i g to bynajmniej nie wszystkie specyfikatory konwersji. Pozo-
staáe bĊdą stopniowo wprowadzane przy okazji omawiania kolejnych zagadnieĔ.
Peána lista specyfikatorów wraz z objaĞnieniem ich znaczenia i dziaáania znajduje
siĊ w podrozdziale 22.3.
specyfikatory
dla wartoĞci caákowitych ¥ 7.1
specyfikatory dla wartoĞci
zmiennoprzecinkowych ¥ 7.2
dla wartoĞci znakowych ¥ 7.3
specyfikatory
specyfikatory
dla ciągów znaków ¥ 13.3
PROGRAM
tprintf.c
Wykorzystanie printf do formatowania liczb
PoniĪszy program ilustruje sposób wykorzystania funkcji printf do wypisy-
wania wartoĞci caákowitych i zmiennoprzecinkowych w rozmaitych formatach:
/* Wypisuje wartoĞci int i float w róĪnych formatach */
#include stdio.h
int main(void)
{
int i;
float x;
i = 40;
x = 839.21f;
printf( | d| 5d| -5d| 5.3d|
, i, i, i, i);
printf( | 10.3f| 10.3e| -10g|
, x, x, x);
return 0;
}
Znaki | w ciągach formatujących dla funkcji printf sáuĪą jedynie do roz-
dzielenia wypisywanych wartoĞci i zilustrowania szerokoĞci pól, w których są
wypisywane. W przeciwieĔstwie do znaków i znak | nie ma specjalnego zna-
czenia dla funkcji printf. Program wypisuje na wyjĞciu coĞ takiego:
|40| 40|40 | 040|
| 839.210| 8.392e+02|839.21 |
Spróbujmy przeanalizowaü znaczenie i dziaáanie specyfikatorów konwersji
wykorzystanych w tym programie:
3.1. Funkcja printf
73
Q d — wypisanie i w zapisie dziesiĊtnym przy jak najmniejszej liczbie znaków.
Q 5d — wypisanie wartoĞci i w zapisie dziesiĊtnym w polu o szerokoĞci co
najmniej 5 znaków. PoniewaĪ wáaĞciwa wartoĞü i ma zaledwie dwa znaki, pole
jest wypeániane trzema spacjami od lewej strony.
Q -5d — wypisanie wartoĞci i w zapisie dziesiĊtnym w polu o szerokoĞci co
najmniej 5 znaków. PoniewaĪ wáaĞciwa wartoĞü i ma zaledwie dwa znaki,
pole jest wypeániane trzema spacjami po prawej stronie wartoĞci (wartoĞü i jest
wiĊc wyrównana w piĊcioznakowym polu do lewej strony).
Q 5.3d — wypisanie wartoĞci i w zapisie dziesiĊtnym w polu o szerokoĞci
co najmniej 5 znaków i przy reprezentowaniu wartoĞci co najmniej trzema
cyframi. PoniewaĪ i ma tylko dwie cyfry, przed wáaĞciwą wartoĞcią wstawiana
jest pojedyncza cyfra zero. Wynikowa trzyznakowa wartoĞü jest wypisywana
w polu o szerokoĞci 5 znaków, a wiĊc jest poprzedzona dwoma spacjami (war-
toĞü i jest wyrównana do prawej strony pola).
Q 10.3f — wypisanie wartoĞci x w zapisie dziesiĊtnym z przecinkiem w polu
o szerokoĞci co najmniej 10 znaków, z trzema cyframi po przecinku. PoniewaĪ
wartoĞü x zajmuje jedynie 7 znaków (trzy przed przecinkiem i trzy po prze-
cinku oraz sam przecinek), jest uzupeániana trzema spacjami z lewej strony.
Q 10.3e — wypisanie wartoĞci x w zapisie wykáadnikowym w polu o sze-
rokoĞci co najmniej 10 znaków, z trzema cyframi po przecinku. Tak zapisana
wartoĞü x zajmuje 9 znaków, wiĊc jest uzupeániona spacją z lewej strony.
Q -10g — wypisanie wartoĞci x w zapisie wykáadnikowym albo dziesiĊtnym
z przecinkiem w polu o szerokoĞci co najmniej 10 znaków, z trzema cyframi
po przecinku. W naszym przypadku wartoĞü x zostaáa zamieniona na dzie-
siĊtną z przecinkiem. ObecnoĞü znaku - w specyfikatorze konwersji wymusza
wyrównanie wartoĞci do lewej strony pola czterema spacjami za wáaĞciwą
wartoĞcią.
Znaki sterujące
Symbol
, wykorzystywany juĪ w poprzednich ciągach formatujących, to przy-
káad tak zwanego znaku sterującego (ang. escape sequence). Znaki sterujące
pozwalają na osadzanie w ciągach znaków, które zapisane inaczej byáyby káopo-
tliwe dla kompilatora. Dotyczy to przede wszystkim znaków niedrukowalnych
terminali znakowych oraz znaków posiadających specjalne znaczenie dla samego
kompilatora (jak ). Kompletną listĊ znaków sterujących zamieĞcimy póĨniej, na
razie wystarczy wykaz najwaĪniejszych:
a
sygnaá dzwonka,
kasowanie poprzedniego znaku (ang. backspace),
nowy wiersz,
tabulator poziomy.
Takie symbole w ciągu formatującym reprezentują czynnoĞci do wykonania w cza-
sie wypisywania ciągu na wyjĞciu programu. OtóĪ wypisanie a spowoduje na
wiĊkszoĞci maszyn wygenerowanie dĨwiĊku brzĊczyka terminala; wypisanie
znaki sterujące ¥ 7.3
74
Rozdziaá 3. Formatowanie wejĞcia-wyjĞcia
cofnie kursor o jedną pozycjĊ; wypisanie
przesunie kursor do nowego wiersza;
wypisanie przesunie kursor do nastĊpnej pozycji tabulatora.
Ciąg formatujący moĪe zawieraü dowolną liczbĊ znaków sterujących. Spójrzmy
na kolejny przykáad wywoáania printf z ciągiem formatującym zawierającym
áącznie szeĞü znaków sterujących:
printf( Towar Cena Data
jed. zakupu );
Wykonanie tej instrukcji spowoduje wypisanie na wyjĞciu dwóch wierszy:
Towar Cena Data
jed. zakupu
Innym popularnym znakiem sterującym jest , który reprezentuje w ciągu
znak podwójnego cudzysáowu . PoniewaĪ sam znak oznacza początek albo
koniec literaáu napisowego, nie moĪe w takiej postaci pojawiü siĊ wewnątrz lite-
raáu — musi zostaü oznaczony jako znak sterujący znakiem ukoĞnika. Oto przykáad:
printf( Ahoj! );
Taka instrukcja spowoduje wypisanie na wyjĞciu komunikatu:
Ahoj!
Podobna sytuacja dotyczy znaku lewego ukoĞnika. JeĞli zechcemy umieĞciü
taki znak w wypisywanym ciągu, nie moĪemy go wstawiü wprost do literaáu napi-
sowego, bo kompilator zakáada, Īe znak ukoĞnika jest zapowiedzią znaku steru-
jącego. Aby wypisaü znak , trzeba go równieĪ poprzedziü znakiem , a wiĊc
wstawiü do ciągu parĊ \:
printf( \ ); /* wypisuje na wyjĞciu pojedynczy znak */
3.2. Funkcja scanf
Tak jak funkcja printf sáuĪy do formatowania wyjĞcia programu, tak funkcja
scanf obsáuguje formatowane wejĞcie. Ciąg formatujący dla funkcji scanf rów-
nieĪ moĪe zawieraü zwyczajne znaki i specyfikatory konwersji. Konwersje obsáu-
giwane przez funkcjĊ scanf pokrywają siĊ z grubsza z konwersjami funkcji
printf.
W wielu przypadkach ciąg formatujący funkcji scanf zawiera wyáącznie
specyfikatory konwersji, jak w poniĪszym przykáadzie:
int i, j;
float x, y;
scanf( d d f f , i, j, x, y);
ZaáóĪmy, Īe uĪytkownik wprowadza na wejĞcie programu nastĊpujący wiersz:
1 -20 .3 -4.0e3
3.2. Funkcja scanf
75
Funkcja scanf wczyta taki wiersz i rozpocznie stosowanie specyfikatorów kon-
wersji i podstawianie uzyskanych wartoĞci pod zmienne przekazane w wywoáaniu:
1 pod i, -20 pod j, 0.3 pod x i -4000.0 pod y. Takie „upakowane” ciągi
sterujące są dla funkcji scanf typowe. W przypadku funkcji printf czĊĞciej
stosuje siĊ rozmaite „dekoracje” i napisy objaĞniające, otaczające wyprowadzane
wartoĞci.
Funkcja scanf (tak jak printf zresztą) zastawia na nieĞwiadomych i nie-
ostroĪnych uĪytkowników kilka wnyków. Programista stosujący funkcjĊ scanf
musi starannie sprawdzaü, czy liczba specyfikatorów konwersji odpowiada liczbie
zmiennych przekazanych w wywoáaniu i czy poszczególne konwersje odpowiadają
typom przekazanych zmiennych — podobnie jak w przypadku printf, kom-
pilator nie ma obowiązku przeprowadzania takiej kontroli i wykrywania ewentu-
alnych niezgodnoĞci. Kolejna puáapka czai siĊ w znaku , który zazwyczaj poprze-
dza kaĪdą zmienną przekazywaną do scanf. Znak jest zazwyczaj (choü nie
zawsze) konieczny i to programista ma obowiązek pamiĊtaü o jego stosowaniu.
PominiĊcie symbolu przy zmiennej przekazywanej do funkcji scanf prowadzi
do nieprzewidywalnych wyników dziaáania programu. Potencjalnie są to efekty
katastrofalne. NajczĊĞciej taki báąd prowadzi do wyáoĪenia siĊ programu. W naj-
lepszym przypadku podstawienie wartoĞci pod zmienną bĊdzie nieskuteczne —
zmienna zachowa swoją poprzednią wartoĞü (co nie oznacza, Īe bĊdzie miaáa jaką-
kolwiek okreĞloną wartoĞü, jeĞli np. nie zostaáa zainicjalizowana!). PominiĊcie
znaku jest niestety czĊstym báĊdem. Niektóre kompilatory wykrywają taki báąd
i generują komunikat z ostrzeĪeniem w rodzaju „argument nie jest wskaĨnikiem”
(o wskaĨnikach powiemy sobie w rozdziale 11.; to wáaĞnie znak tworzy wskaĨ-
nik do zmiennej). OstrzeĪenia związane z wywoáaniami funkcji scanf trzeba trak-
towaü bardzo powaĪnie.
Wywoáania funkcji scanf są efektywnym, ale potencjalnie niebezpiecznym
sposobem wczytywania danych do programów. Wielu zawodowych programi-
stów C unika funkcji scanf. Wolą oni wczytaü do programu caáoĞü danych
wejĞciowych w postaci znakowej i dopiero póĨniej zamieniü ją na oczekiwane
wartoĞci liczbowe. My natomiast bĊdziemy korzystaü ze scanf caákiem sporo,
zwáaszcza w początkowych rozdziaáach ksiąĪki — jest to zwyczajnie najprostszy
sposób wczytywania wartoĞci liczbowych do programu. Trzeba tylko mieü Ğwia-
domoĞü, Īe wiele programów zachowa siĊ niepoprawnie, kiedy uĪytkownik wpro-
wadzi do nich nieodpowiednie dane wejĞciowe. Wkrótce siĊ przekonamy, Īe moĪna
zresztą skutecznie sprawdzaü, czy funkcji scanf udaáo siĊ wczytaü z wejĞcia
oczekiwane dane (a jeĞli nie, odpowiednio zareagowaü, zamiast brnąü dalej w pro-
gram z niepoprawnymi danymi). Takie sprawdziany są jednak maáo zasadne
w zakresie początkowych przykáadów prezentowanych w ksiąĪce — nadmiernie
rozbudowaáyby program, który ma przecieĪ przede wszystkim ilustrowaü bieĪące
zagadnienie.
wykrywanie báĊdów
w scanf ¥ 22.3
76
Rozdziaá 3. Formatowanie wejĞcia-wyjĞcia
Dziaáanie funkcji scanf
Funkcja scanf robi w istocie znacznie wiĊcej, niĪ dotychczas powiedziano. Jest to
w zasadzie mechanizm dopasowywania wzorców w ciągach znaków, który pró-
buje pogrupowaü znaki wejĞciowe i dopasowaü je do specyfikatorów konwersji.
Dziaáaniem funkcji scanf sterujemy za pomocą ciągu formatującego. Funkcja
scanf analizuje zawartoĞü tego ciągu, od lewej do prawej strony. Dla kaĪdego
napotkanego w ciągu specyfikatora konwersji próbuje w ciągu wejĞciowym pro-
gramu zlokalizowaü wartoĞü odpowiedniego typu. W czasie tego wyszukiwania
automatycznie pomija znaki odstĊpów. Znaleziony podciąg pasujący do specyfi-
katora konwersji jest wczytywany aĪ do miejsca, w którym wystąpi znak niepasu-
jący do wymagaĔ konwersji. JeĞli udaáo siĊ wczytaü taki podciąg, funkcja scanf
dokonuje konwersji i przechodzi do analizy reszty ciągu formatującego. Pierwsze
nieudane dopasowanie specyfikatora konwersji do danych wczytywanych z wej-
Ğcia koĔczy dziaáanie caáej funkcji, bez rozpatrywania reszty ciągu formatującego
(i bez uwzglĊdniania reszty danych wejĞciowych).
W toku poszukiwania pierwszego znaku liczby funkcja scanf ignoruje
wszystkie znaki odstĊpów (spacje, znaki tabulacji poziomej i pionowej, znaki
wysuwu formularza i znaki nowego wiersza). DziĊki temu na wejĞciu dane moĪna
podawaü w jednym wierszu albo rozproszyü je pomiĊdzy róĪnymi wierszami. Przy
danym wywoáaniu funkcji scanf:
scanf( d d f f , i, j, x, y);
uĪytkownik moĪe wprowadziü na wejĞcie np. trzy wiersze danych:
1
-20 .3
-4.0e3
dla funkcji scanf wejĞcie jest widoczne jako ciągáy strumieĔ znaków:
··1¤-20···.3¤···-4.0e3¤
(w celu uwidocznienia znaków odstĊpów zastosowaliĞmy znak · dla spacji i znak
¤ dla nowego wiersza). PoniewaĪ funkcja scanf pomija znaki odstĊpów i szuka
przede wszystkim początku liczby i podciągu znaków nadających siĊ do konwersji,
takie dane wejĞciowe mogą byü za jednym zamachem wczytane przez funkcjĊ
scanf. PoniĪszy schemat ilustruje dziaáanie funkcji scanf. Znak p oznacza tu
pomijanie bieĪącego znaku wejĞcia, znak w oznacza wczytywanie znaków do bie-
Īącej konwersji:
··1¤-20···.3¤···-4.0e3¤
ppwpwwwpppwwppppwwwwww
Ostatni znak strumienia wejĞciowego, czyli pierwszy znak za ostatnią skonwerto-
waną grupą znaków, jest przez funkcjĊ scanf „podglądany”, ale nie jest wczy-
tywany. Zostanie on wczytany i pominiĊty bądĨ skonwertowany przy nastĊpnym
wywoáaniu scanf.
Wedáug jakich reguá scanf rozpoznaje liczbĊ caákowitą albo zmiennoprze-
cinkową w ciągu danych wejĞciowych? OtóĪ kiedy scanf ma wczytaü liczbĊ
caákowitą, szuka w ciągu wejĞciowym znaku cyfry, ewentualnie znaku + albo -.
3.2. Funkcja scanf
77
Po znalezieniu takiego znaku wczytuje wszystkie kolejne znaki aĪ do napotkania
znaku niebĊdącego cyfrą. Natomiast w przypadku liczby zmiennoprzecinkowej
scanf szuka:
znaku + albo - (opcjonalnie), a za nim
ciągu cyfr (zawierającego ewentualnie znak przecinka dziesiĊtnego), a za nim
ciągu wykáadnika (opcjonalnie); ciąg wykáadnika skáada siĊ z litery e (albo E),
opcjonalnego znaku (+ albo -) i co najmniej jednej cyfry.
W przypadku funkcji scanf konwersje e, f i g moĪna stosowaü zamiennie —
wszystkie trzy reprezentują te same reguáy dopasowania wartoĞci zmiennoprze-
cinkowej.
Kiedy scanf napotyka znak niezgodny z reguáą dopasowania dla bieĪącej kon-
wersji, znak ten jest „odkáadany” z powrotem do strumienia wejĞciowego, aby byá
dostĊpny przy obsáudze nastĊpnych specyfikatorów konwersji albo dla kolejnych
wywoáaĔ scanf wczytujących kolejne wartoĞci. WeĨmy na przykáad nastĊpujące
(niewątpliwie patologiczne) rozmieszczenie naszych czterech liczb wejĞciowych:
1-20.3-4.0e3¤
Zastosujemy takie same wywoáanie scanf jak poprzednio:
scanf( d d f f , i, j, x, y);
Funkcja scanf bĊdzie przetwarzaü taki ciąg wejĞciowy nastĊpująco:
Q BieĪąca konwersja: d. Pierwszy niepusty znak wejĞcia to 1. PoniewaĪ liczba
caákowita moĪe zaczynaü siĊ od cyfry, znak jest akceptowany jako pierwszy
znak podciągu do dopasowania. Funkcja wczytuje nastĊpny znak: -. Taki znak
nie moĪe siĊ pojawiü wewnątrz zapisu wartoĞci caákowitej, wiĊc scanf
odkáada znak z powrotem do strumienia i podstawia pod pierwszą zmienną
(i) wartoĞü 1.
Q BieĪąca konwersja: d. Pierwszy niepusty znak wejĞcia to - (dozwolony);
kolejne znaki to 2, 0 i . (kropka). Liczba caákowita nie moĪe zawieraü kropki,
wiĊc znak jest odkáadany z powrotem do strumienia wejĞciowego, a funkcja
podstawia pod kolejną zmienną (j) wartoĞü –20.
Q BieĪąca konwersja: f. Pierwszy niepusty znak wejĞcia to . (dozwolony);
kolejne znaki to 3 i - (minus). Liczba zmiennoprzecinkowa nie zawiera znaku
- po znaku cyfry, wiĊc znak - jest odkáadany z powrotem do strumienia wej-
Ğciowego, a funkcja podstawia pod kolejną zmienną (x) wartoĞü 0.3.
Q BieĪąca konwersja: f. Pierwszy niepusty znak wejĞcia to - (dozwolony);
kolejne znaki to 4, ., 0, e, 3 i ¤ (nowy wiersz). Liczba zmiennoprzecinkowa
nie moĪe zawieraü znaku nowego wiersza, wiĊc znak jest odkáadany z powro-
tem do strumienia wejĞciowego, a funkcja podstawia pod kolejną zmienną
(y) wartoĞü –4.0×103.
W tym przykáadzie funkcja scanf mogáa skutecznie dopasowaü wszystkie kolejne
specyfikatory konwersji do ciągu wejĞciowego. PoniewaĪ znak nowego wiersza
nie zostaá „zuĪyty”, bĊdzie pierwszym znakiem wczytywanym przy nastĊpnym
wywoáaniu scanf.
78
Rozdziaá 3. Formatowanie wejĞcia-wyjĞcia
Zwykáe znaki w ciągu formatującym funkcji scanf
ZasadĊ dopasowywania wzorców do podciągów strumienia wejĞciowego moĪna
rozszerzyü, zapisując ciąg formatujący zawierający poza specyfikatorami konwer-
sji równieĪ zwykáe napisy. W takim przypadku pomiĊdzy specyfikatorami kon-
wersji funkcja scanf bĊdzie porównywaáa kolejne znaki wejĞcia ze znakami
ciągu formatującego. Porównanie takie odbywa siĊ róĪnie, zaleĪnie od tego, czy
ciąg formatujący zawiera znaki odstĊpów:
Q Znaki odstĊpów w ciągu formatującym. Kiedy w ciągu formatującym znaj-
dują siĊ znaki odstĊpu, funkcja scanf bĊdzie w strumieniu wejĞciowym wczy-
tywaáa kolejne znaki tak dáugo, aĪ napotka pierwszy znak niebĊdący znakiem
odstĊpu (ten znak zostanie „odáoĪony” z powrotem do strumienia wejĞciowego).
Liczba znaków odstĊpu w ciągu formatującym nie musi dokáadnie odpowiadaü
liczbie takich znaków w ciągu wejĞciowym. Pojedynczy znak odstĊpu w ciągu
formatującym zostanie dopasowany do dowolnie dáugiego podciągu takich
znaków w ciągu wejĞciowym (co wiĊcej, obecnoĞü znaku odstĊpu w ciągu
formatującym nie wymusza obecnoĞci takiego znaku w ciągu wejĞciowym —
znak odstĊpu w ciągu formatującym odpowiada dowolnie dáugiemu podciągowi
takich znaków w ciągu wejĞciowym, a wiĊc równieĪ podciągowi zerowemu).
Q Pozostaáe znaki. Kiedy w ciągu formatującym znajduje siĊ znak nienaleĪący
do specyfikatorów konwersji i niebĊdący znakiem odstĊpu, funkcja scanf
porównuje go wprost z nastĊpnym znakiem wejĞcia. JeĞli znaki są zgodne,
funkcja przechodzi do przetwarzania nastĊpnego znaku ciągu wejĞciowego.
Przy braku zgodnoĞci funkcja odkáada niepasujący znak z powrotem do ciągu
wejĞciowego i przerywa dalsze przetwarzanie ciągu formatującego.
Dla przykáadu niech funkcja scanf otrzyma ciąg formatujący w postaci
d/ d . JeĞli na wejĞciu programu pojawi siĊ ciąg:
·5/·96
funkcja scanf pominie pierwszy znak odstĊpu, szukając liczby caákowitej, nastĊp-
nie dopasuje do d podciąg 5, dopasuje bezpoĞrednio znak /, pominie spacjĊ
w poszukiwaniu kolejnej liczby caákowitej, a póĨniej dopasuje do d podciąg 96.
Ale jeĞli na wejĞciu pojawi siĊ:
·5·/·96
to funkcja scanf pominie pierwszy znak odstĊpu, szukając liczby caákowitej,
nastĊpnie dopasuje do d podciąg 5, a póĨniej spróbuje dopasowaü do wejĞcia
znak /. PoniewaĪ w bieĪącym miejscu wejĞcia zamiast tego znaku znajduje siĊ
inny (tu: znak odstĊpu), funkcja przerwie przetwarzanie wejĞcia, odkáadając spacjĊ
z powrotem do ciągu wejĞciowego. Na wejĞciu pozostanie ciąg ·/·96 czekający
na ewentualne kolejne wywoáanie scanf. Aby umoĪliwiü dopasowanie wejĞcia
ze spacją (spacjami) po pierwszej liczbie caákowitej, ciąg formatujący powinien
mieü postaü d / d .
3.2. Funkcja scanf
79
Skutki mylenia printf ze scanf
Wywoáania funkcji printf i scanf bywają bardzo podobne, ale w ich dziaáa-
niu zachodzą daleko idące róĪnice. Zignorowanie tych róĪnic moĪe byü bardzo nie-
bezpieczne dla dziaáania programu.
Jedną z czĊstych pomyáek jest umieszczenie przed zmienną w wywoáaniu
funkcji printf:
printf( d d
, i, j); /*** ħLE ***/
Na szczĊĞcie taka omyáka jest stosunkowo prosta do wytropienia — w toku
dziaáania programu funkcja printf wyĞwietli „Ğmieci” zamiast oczekiwanych
wartoĞci i i j.
PoniewaĪ funkcja scanf normalnie pomija znaki odstĊpów przy poszuki-
waniu podciągu do dopasowania do wartoĞci liczbowej, rzadko kiedy pojawia siĊ
potrzeba umieszczania w ciągu formatującym scanf czegokolwiek poza specy-
fikatorami konwersji. Nieuprawnione zaáoĪenie, Īe ciąg formatujący scanf
powinien ĞciĞle odpowiadaü analogicznemu ciągowi formatującemu printf —
to kolejny czĊsty báąd — moĪe doprowadziü do niepoprawnego dziaáania funkcji
scanf. Zobaczmy, co siĊ stanie, jeĞli w programie znajdzie siĊ nastĊpująca in-
strukcja:
scanf( d, d , i, j);
Funkcja scanf bĊdzie najpierw szukaü podciągu wartoĞci typu int i wpisze tĊ
wartoĞü pod zmienną i. Potem bĊdzie próbowaáa dopasowaü w ciągu wejĞciowym
znak przecinka. JeĞli w ciągu wejĞciowym zamiast przecinka pojawi siĊ spacja,
dziaáanie funkcji zostanie przerwane i zmienna j nie otrzyma oczekiwanej wartoĞci.
Ciągi formatujące dla funkcji printf czĊsto koĔczą siĊ znakiem sterującym
,
wymuszającym wstawienie do wyjĞcia nowego wiersza. Taki sam znak na koĔcu
ciągu formatującego scanf to zazwyczaj záy pomysá. Dla scanf znak nowego
wiersza w ciągu formatującym jest równowaĪny ze znakiem spacji; pomija go,
szukając nastĊpnego znaku niebĊdącego znakiem odstĊpu. JeĞli na przykáad ciąg
formatujący ma postaü d
, scanf pominie ewentualne początkowe znaki
odstĊpu, wczyta wartoĞü caákowitą, a nastĊpnie bĊdzie w ciągu wejĞciowym szukaü
nastĊpnego znaku innego niĪ odstĊp. W przypadku programu interaktywnego moĪe
to doprowadziü do „zawieszenia” programu do czasu, kiedy uĪytkownik wprowa-
dzi na wejĞcie znak inny niĪ odstĊp.
Dodawanie uáamków
Aby zilustrowaü zdolnoĞü funkcji scanf do dopasowywania wzorców w ciągach
znaków, weĨmiemy na warsztat problem wczytania uáamka wprowadzanego przez
uĪytkownika. Uáamki są zwyczajowo reprezentowane przez zapis licznik/mianownik.
Zamiast zmuszaü uĪytkownika do nieintuicyjnego wprowadzania uáamka jako
dwóch osobnych liczb caákowitych, dziĊki funkcji scanf pozwolimy mu wpro-
wadziü uáamek w klasycznej postaci. Oto program ilustrujący tĊ technikĊ przy
dodawaniu dwóch uáamków:
PROGRAM
80
Rozdziaá 3. Formatowanie wejĞcia-wyjĞcia
addfrac.c
/* Dodawanie dwóch uáamków zwykáych */
#include stdio.h
int main(void)
{
int num1, denom1, num2, denom2, result_num, result_denom;
printf( Podaj pierwszy uïamek: );
scanf( d/ d , num1, denom1);
printf( Podaj drugi uïamek: );
scanf( d/ d , num2, denom2);
result_num = num1 * denom2 + num2 * denom1;
result_denom = denom1 * denom2;
printf( Suma uïamków wynosi d/ d
,
result_num, result_denom);
return 0;
}
Przykáadowa sesja z takim programem wyglądaáa tak:
Podaj pierwszy uïamek: 5/6
Podaj drugi uïamek: 3/4
Suma uïamków wynosi 38/24
ZauwaĪmy, Īe program nie przewiduje znormalizowania wynikowego uáamka.
Pytania i odpowiedzi
*P: Widywaáem specyfikatory w postaci i, przeznaczone do wczytywania i wy-
pisywania liczb caákowitych. Czym róĪnią siĊ od d (s. 71)?
liczby ósemkowe ¥ 7.1
liczby szesnastkowe ¥ 7.1
P:
O: W ciągu formatującym funkcji printf nie ma pomiĊdzy nimi Īadnej róĪnicy.
Za to w funkcji scanf d dopasuje wyáącznie liczbĊ caákowitą zapisaną w postaci
dziesiĊtnej, natomiast i moĪe dopasowaü takĪe liczby caákowite zapisane
w innych systemach liczbowych (przy innych podstawach), na przykáad liczby
ósemkowe czy szesnastkowe. OtóĪ jeĞli ciąg wejĞciowy zawiera przedrostek
0 (jak w 056), przy konwersji i taki ciąg zostanie potraktowany jako ósemkowy.
Przedrostek 0x albo 0X (jak w 0x56) przy konwersji i spowoduje konwersjĊ
liczby jako wartoĞci szesnastkowej. Zastosowanie i zamiast d do wczytywania
liczb moĪe daü zaskakujące wyniki, jeĞli uĪytkownik omyákowo wprowadzi 0 przed
wáaĞciwą liczbą; z tego powodu zaleca siĊ trzymanie siĊ konwersji d.
Skoro printf traktuje znak jako początek specyfikatora konwersji, jak
moĪna wypisaü na wyjĞciu programu znak procenta?
Funkcja printf wypisze na wyjĞciu znak tam, gdzie w ciągu formatującym
pojawi siĊ para przylegających znaków procenta ( ). Na przykáad instrukcja:
O:
Pytania i odpowiedzi
81
printf( Zysk netto: d
, profit);
moĪe spowodowaü wypisanie:
Zysk netto: 10
P: Znak sterujący ma wymusiü na printf przesuniĊcie kursora do nastĊp-
nej pozycji tabulacji. Skąd wiadomo, jaka jest szerokoĞü tabulatora (s. 74)?
O: Nie wiadomo. Efekt wypisania na wyjĞciu znaku nie jest ĞciĞle zdefiniowany
w standardzie jĊzyka C. Jest on zaleĪny od reakcji systemu operacyjnego na Īąda-
nie wypisania znaku tabulacji. Zazwyczaj szerokoĞü tabulatora to osiem znaków,
ale C sam w sobie nie daje takiej gwarancji.
P: Co zrobi funkcja scanf, jeĞli bĊdzie miaáa wczytaü liczbĊ, a uĪytkownik
wprowadzi ciąg nieliczbowy?
O: WyjaĞnimy to na przykáadzie:
printf( Podaj liczbÚ: );
scanf( d , i);
ZaáóĪmy, Īe uĪytkownik wprowadzi poprawną wartoĞü liczbową, za którą umieĞci
znaki inne niĪ cyfry:
Podaj liczbÚ: 23bla
W takim przypadku funkcja scanf wczyta znaki 2 oraz 3 i w zmiennej i umieĞci
wartoĞü 23. Reszta znaków (bla) bĊdzie w strumieniu wejĞciowym czekaáa na
kolejne wywoáanie scanf (albo innej funkcji obsáugującej wejĞcie). JeĞli natomiast
uĪytkownik wprowadzi ciąg niepoprawny od pierwszego znaku:
Podaj liczbÚ: bla
zmienna i nie otrzyma wartoĞci wczytywanej z wejĞcia programu, a w strumieniu
wejĞciowym ciąg bla poczeka na kolejne wywoáania funkcji wejĞcia.
Co moĪna zrobiü w takich smutnych przypadkach? PóĨniej dowiesz siĊ, jak
sprawdziü skutecznoĞü wywoáania funkcji scanf. JeĞli wywoáanie bĊdzie nie-
skuteczne, moĪemy zakoĔczyü program albo spróbowaü naprawiü sytuacjĊ, na przy-
káad odrzucając niepoprawne wejĞcie i ponownie prosząc uĪytkownika o wpro-
wadzenie danych (sposoby odrzucania danych wejĞciowych bĊdą omawiane
w sekcji pytaĔ i odpowiedzi rozdziaáu 22.).
wykrywanie báĊdów
w scanf ¥ 22.3
P: Nie rozumiem, w jaki sposób funkcja scanf „odkáada” znak z powrotem
do ciągu wejĞciowego i potem ponownie wczytuje go z wejĞcia (s. 77)?
O: Okazuje siĊ, Īe program nie wczytuje danych wejĞciowych bezpoĞrednio przy ich
wprowadzaniu. Ciąg wejĞciowy programu jest przechowywany w ukrytym buforze,
do którego odwoáuje siĊ funkcja scanf. W takim ukáadzie funkcja scanf moĪe
„odáoĪyü” znak z powrotem do bufora. Buforowanie wejĞcia bĊdzie omawiane
w rozdziale 22.
Jak zadziaáa funkcja scanf, kiedy uĪytkownik umieĞci pomiĊdzy liczbami
znaki przestankowe (np. przecinki)?
P:
O: Zobaczmy to na prostym przykáadzie. ZaáóĪmy, Īe zamierzamy wczytaü funkcją
scanf parĊ liczb:
82
Rozdziaá 3. Formatowanie wejĞcia-wyjĞcia
printf( Podaj dwie liczby: );
scanf( d d , i, j);
JeĞli uĪytkownik wprowadzi:
4,28
funkcja scanf wczyta znak 4 i podstawi wartoĞü 4 do zmiennej i. W poszuki-
waniu nastĊpnego podciągu reprezentującego liczbĊ caákowitą znajdzie przecinek.
PoniewaĪ przecinek nie moĪe rozpoczynaü zapisu liczby, funkcja przerwie dzia-
áanie. Sam przecinek i druga wprowadzona liczba zostaną do dyspozycji nastĊp-
nych wywoáaĔ scanf.
OczywiĞcie moĪna temu áatwo zaradziü, instruując uĪytkownika co do ocze-
kiwanego formatu danych wejĞciowych, np. nakazując mu zawsze oddzielanie liczb
przecinkiem:
printf( Podaj dwie liczby, oddzielone przecinkiem: );
scanf( d, d , i, j);
ûwiczenia
Podrozdziaá 3.1
1. Co pojawi siĊ na wyjĞciu po wykonaniu poniĪszych wywoáaĔ printf?
(a) printf( 6d, d4 , 86, 1040);
(b) printf( 12.5e , 86, 30.253);
(c) printf( .4f , 83.162);
(d) printf( -6.2g , .0000009979);
2. Napisz wywoáanie funkcji printf wyĞwietlającej wartoĞü zmiennej typu float w nastĊ-
pujących formatach:
(a) w zapisie wykáadnikowym, wyrównaną do lewej w polu o szerokoĞci 8, z jedną cyfrą
(b) w zapisie wykáadnikowym, wyrównaną do prawej w polu o szerokoĞci 10, z szeĞcioma
(c) w zapisie dziesiĊtnym z przecinkiem, wyrównaną do lewej w polu o szerokoĞci 8, z trzema
po przecinku;
cyframi po przecinku;
cyframi po przecinku;
(d) w zapisie dziesiĊtnym z przecinkiem, wyrównaną do prawej w polu o szerokoĞci 6,
bez cyfr po przecinku.
Podrozdziaá 3.2
3. Dla kaĪdej z poniĪszych par ciągów formatujących scanf wskaĪ, czy oba ciągi pary są sobie
równowaĪne, czy nie. JeĞli nie są, wskaĪ róĪnicĊ w ich dziaáaniu.
(a) d
(b) d- d- d d - d - d
(c) f
(d) f, f
f
f, f
d
*
4. WeĨmy nastĊpujące wywoáanie funkcji scanf:
ûwiczenia z gwiazdką są podchwytliwe — poprawna odpowiedĨ zazwyczaj jest róĪna
od odpowiedzi narzucającej siĊ na pierwszy rzut oka. Przeczytaj pytanie uwaĪnie, dokáadnie
przeĞledĨ kod, w razie potrzeby powtórz lekturĊ odpowiedniego podrozdziaáu. Powodze-
nia! — przyp. autora.
Zadania programistyczne
83
scanf( d f d , i, x, j);
Jakie bĊdą wartoĞci zmiennych i, x i j po wykonaniu wywoáania (zakáadamy, Īe zmienne
i i j są zmiennymi typu int, a x jest zmienną typu float), jeĞli uĪytkownik wprowadzi:
10.3 5 6
*
5. WeĨmy nastĊpujące wywoáanie funkcji scanf:
scanf( f d f , x, i, y);
Jakie bĊdą wartoĞci zmiennych x, i i y po wykonaniu wywoáania (zakáadamy, Īe zmienne
x i y są zmiennymi typu float, a i jest zmienną typu int), jeĞli uĪytkownik wprowadzi:
12.3 45.6 789
6.
PokaĪ, jak moĪna przerobiü program addfrac.c z podrozdziaáu 3.2, aby uĪytkownik mógá
wprowadzaü uáamki ze spacjami wokóá znaku dzielenia /.
Zadania programistyczne
1. Napisz program, który przyjmuje na wejĞcie datĊ w postaci dd/mm/rrrr, a nastĊpnie
wypisuje ją w formacie rrrrmmdd:
Podaj datÚ (dd/mm/rrrr): 17/2/2011
PodaïeĂ datÚ 20110217
2. Napisz program formatujący informacje o produkcie wprowadzone przez uĪytkownika. Sesja
z programem powinna wyglądaü tak:
Podaj numer towaru: 583
Podaj cenÚ jednostkowÈ: 13.5
Podaj datÚ zakupu (dd/mm/rrrr): 24/10/2010
Towar Cena Data
jed. zakupu
583 $ 13.50 24/10/2010
Numer towaru i data powinny byü wyrównane do lewej. Cena jednostkowa powinna byü
wyrównana do prawej. Program powinien dopuszczaü kwoty do 9999,99. PodpowiedĨ: Do
wyrównania kolumn zastosuj tabulatory.
3. KsiąĪki są oznaczane miĊdzynarodowym numerem ISBN (International Standard Book
Number). Numery ISBN nadawane po 1 stycznia 2007 roku skáadają siĊ z 13 cyfr, podzie-
lonych na piĊü grup, np. 978-0-393-97950-3 (starsze numery ISBN miaáy 10 cyfr). Pierwsza
grupa (przedrostek GSI) to obecnie albo 978 albo 979. Identyfikator grupy okreĞla jĊzyk
kraju wydania (np. w krajach anglojĊzycznych stosuje siĊ kody 0 i 1). Kod wydawcy
identyfikuje wydawcĊ (393 to kod wydawnictwa W.W. Norton). Numer publikacji to numer
nadawany przez wydawcĊ konkretnej ksiąĪce (tutaj 97950). Numer ISBN koĔczy siĊ sumą
kontrolną umoĪliwiającą weryfikacjĊ poprawnoĞci numeru ISBN. Napisz program, który
podzieli na grupy numer ISBN wprowadzony przez uĪytkownika:
Podaj numer ISBN: 978-0-393-97950-3
Przedrostek GSI: 978
Identyfikator grupy: 0
84
Rozdziaá 3. Formatowanie wejĞcia-wyjĞcia
Kod wydawcy: 393
Numer publikacji: 97950
Suma kontrolna: 3
Uwaga: Liczba cyfr w kaĪdej z grup moĪe byü róĪna. Nie moĪna zaáoĪyü, Īe grupy mają
akurat takie rozmiary jak w tym przykáadzie. Przetestuj program na innych, prawdziwych
numerach ISBN (znajdziesz je na okáadkach ksiąĪek i na stronach z informacjami o wydaniu).
4. Napisz program, który zapyta uĪytkownika o numer telefoniczny w formacie (xx)
xxx-xxxx, a potem wyĞwietli ten numer w zapisie 0-xx xxx-xx-xx:
Podaj numer telefonu [(xx) xxx-xxxx]: (61) 817-6900
Podany numer: 0-61 817-69-00
5. Napisz program, który bĊdzie monitowaá, aby uĪytkownik wprowadziá liczby od 1 do 16
(w dowolnej kolejnoĞci), potem wyĞwietli te liczby czwórkami (w postaci macierzy 4×4),
a nastĊpnie wypisze sumy w wierszach, kolumnach i po przekątnych:
Podaj liczby od 1 do 16 (w dowolnej kolejnoĂci):
16 3 2 13 5 10 11 8 9 6 7 12 4 15 14 1
16 3 2 13
5 10 11 8
9 6 7 12
4 15 14 1
Sumy w wierszach: 34 34 34 34
Sumy w kolumnach: 34 34 34 34
Sumy po przekÈtnych: 34 34
JeĞli sumy w wierszach, kolumnach i po przekątnych są identyczne (jak w przykáadzie),
to takie liczby stanowią tak zwany magiczny kwadrat. Ten magiczny kwadrat pojawiá
siĊ w 1514 roku na rycinie artysty i matematyka Albrechta Dürera (zauwaĪ, Īe Ğrodkowe
liczby w ostatnim wierszu skáadają siĊ na datĊ ryciny).
6.
Przerób program addfrac.c z podrozdziaáu 3.2 tak, aby uĪytkownik za jednym zamachem
wprowadzaá oba uáamki oddzielone znakiem +:
Podaj dwa uïamki oddzielone znakiem plusa: 5/6+3/4
Suma uïamków wynosi 38/24
4 WyraĪenia
UĪywanie kalkulatorka to jeszcze nie programowanie,
a juĪ nie matematyka.
Jedną z waĪniejszych cech jĊzyka C jest nacisk, jaki jest w nim káadziony na wyra-
Īenia — inaczej „wzory”, które mówią o sposobie obliczania wartoĞci. WyraĪenia
są tu waĪniejsze niĪ instrukcje. Najprostsze wyraĪenia to zmienne i staáe programu.
Zmienna reprezentuje wartoĞü, która jest obliczana w czasie dziaáania programu
poprzez pobranie wartoĞci z pamiĊci skojarzonej ze zmienną. Staáa reprezentuje
wartoĞü znaną juĪ w czasie kompilacji. Bardziej rozbudowane wyraĪenia obejmują
operandy i operatory (przy czym operatory same w sobie są równieĪ wyraĪeniami).
W wyraĪeniu a + (b * c) widzimy zastosowanie operatora + do operandów
a oraz (b + c), natomiast obie strony operatora + (oba operandy) są peánopraw-
nymi wyraĪeniami.
Operatory są podstawowymi narzĊdziami budowania wyraĪeĔ, a jĊzyk C
posiada bardzo bogaty zbiór operatorów. Przede wszystkim C obsáuguje podsta-
wowe operatory obecne w wiĊkszoĞci innych jĊzyków programowania:
Q Operatory arytmetyczne, w tym dodawanie, odejmowanie, mnoĪenie i dzielenie.
Q Operatory relacji do obliczania wartoĞci wyraĪeĔ logicznych, takich jak „i jest
wiĊksze od 0”.
Q Operatory logiczne do budowania warunków logicznych, jak „i jest wiĊksze
od 0 i jest mniejsze niĪ 10”.
Na tym jednak nie koniec. W jĊzyku C mamy do dyspozycji dziesiątki innych
operatorów. Jest ich tak wiele, Īe bĊdziemy zmuszeni do ich stopniowego wpro-
wadzania na przestrzeni aĪ dwudziestu rozdziaáów tej ksiąĪki. Opanowanie takiej
liczby operatorów wydaje siĊ zadanie
Pobierz darmowy fragment (pdf)