1 ELEMENTARZ
Ćwiczenie 1.8. Napisz program zliczający znaki odstępu, tabulacji i nowego wiersza.
Ćwiczenie 1.9. Napisz program, który - przepisując wejście na wyjście - będzie zastępować jednym znakiem odstępu każdy ciąg złożony z jednego lub kilku takich znaków.
Ćwiczenie 1.10. Napisz program, który podczas kopiowania wejścia na wyjście zastępuje każdy znak tabulacji przez sekwencję znaków \t, każdy znak cofania przez sekwencję \b oraz każdy znak \ przez dwa takie znaki.
Czwarty program z naszej serii pożytecznych programów zlicza wiersze, słowa i znaki. Przyjęliśmy tu swobodną definicję słowa jako ciągu znaków nie zawierającego odstępów, znaków tabulacji i znaków nowego wiersza. Nasz program jest ubogą wersją usługowego programu wc w systemie Unix.
#include <stdio.h>
#define IN 1 /* wewnątrz słowa */
#define OUT 0 /* poza słowem */
I* zlicz wejściowe wiersze, słowa i znaki */ main()
int c, ni, nw, nc, State;
State = OUT; nl = nw = nc = 0; while ((c = getchar()) != EOF) { ++nc;
if (c == ’\n’)
++nl;
if (c == * ’ ||c==’\n’||c==,\f)
State = OUT; else if (State == OUT) { stałe = IN;
++nw;
printf(”%d %d %d\n”, nl, nw, nc);
}
1.5 WEJŚCIE I WYJŚCIE ZNAKOWE
Za każdym razem po rozpoznaniu pierwszego znaku słowa program zwięks słów nw. Zmienna State (stan) wskazuje, czy program jest właśnie wewnątrz słowa, czy nie; początkowo jej wartością jest stan „poza słowem”, czemu przypisano wartość OUT. Zalecamy stosowanie stałych symbolicznych typu IN (w) i OUT (poza) dla tak prozaicznych wartości, jak 1 i 0; program staje się wówczas bardziej czytelny. W tak małym programie, jak nasz, nie jest to bardzo istotne, ale w większych programach wzrost czytelności naprawdę jest wart tego dodatkowego wysiłku - pisania w ten sposób od początku. Zauważysz później, że łatwiej jest wprowadzać rozległe zmiany w programach, w których magiczne liczby pojawiają się jedynie jako stałe symboliczne.
W wierszu
nl = nw = nc = 0;
wszystkim trzem zmiennym nadaje się wartość zero. Nie jest to przypadek specjalny, tylko naturalna konsekwencja faktu, że operacja przypisania jest wyrażeniem, a więc ma wartość, oraz że operatory przypisania są prawostronnie łączne. Znaczy to tyle, co
nl = (nw = (nc = 0));
Operator logiczny 11 oznacza „lub” (ang. O/?), zatem w wierszu if (c ==1 ’ II c == ’\n* || c == ’\t’)
mówimy „jeśli c jest odstępem lub c jest znakiem nowego wiersza, lub c jest znakiem tabulacji, to”. (Przypominamy, że sekwencja specjalna \t jest wizualną reprezentacją znaku tabulacji). W języku C występuje również operator logiczny && oznaczający „i” (ang. AND); jego priorytet jest wyższy niż priorytet operatora 11. Wyrażenia połączone operatorami 11 i && są obliczane od lewej strony do prawej i gwarantuje się, że obliczanie skończy się w chwili, w której jest już znana wartość całego wyrażenia: „prawda” lub „fałsz”. W przypadku gdy zmienna c zawiera odstęp, nie potrzeba dalej sprawdzać, czy zawiera znak nowego wiersza czy tabulacji, a więc te możliwości nie będą sprawdzane. Nie jest to takie ważne w naszej sytuacji, lecz jest bardzo ważne w bardziej skomplikowanych warunkach, co wkrótce pokażemy.
W przykładzie występuje także słowo else, wprowadzające alternatywną akcję podejmowaną w chwili, gdy wartość warunku instrukcji if jest fałszywa. Ogólna postać instrukcji if jest następująca:
if (wyrażenie) instrukcja 1 else
instrukcja2
Wykonuje się jedną i tylko jedną z dwóch instrukcji związanych z if-else. Jeśli wyrażenie ma wartość „prawda”, to zostanie wykonana instrukcjal, jeśli „fałsz” - instrukcja2. Każda instrukcja może być pojedynczą instrukcją lub kilkoma instrukcjami uję-
43