Wprowadzenie do programowania w języku C Część druga Instrukcje sterujące przebiegiem programu Autor Roman Simiński Kontakt siminski@us.edu.pl www.us.edu.pl/~siminski Niniejsze opracowanie zawiera skrót treści wykładu, lektura tych materiałów nie zastąpi uważnego w nim uczestnictwa. Opracowanie to jest chronione prawem autorskim. Wykorzystywanie jakiegokolwiek fragmentu w celach innych niż nauka własna jest nielegalne. Dystrybuowanie tego opracowania lub jakiejkolwiek jego części oraz wykorzystywanie zarobkowe bez zgody autora jest zabronione.
Instrukcje wyrażeniowa i złożona Instrukcja wyrażeniowa Instrukcja wyrażeniowa to każde poprawne wyrażenie w języku C (również wyrażenie puste) zakończone znakiem średnika. Wykonanie takiej instrukcji polega na wyznaczeniu wartości danego wyrażenia. x = 0; a + b; x = a + b; ; Instrukcja złożona Instrukcja złożona zwana inaczej blokiem, to lista instrukcji ujęta w nawiasy klamrowe. Blok traktowany jest jako pojedyncza instrukcja. Identyfikator zadeklarowany w obrębie bloku ma jego zakres. Bloki mogą być zagnieżdżane do dowolnej głębokości. int i = 0, j = 1, k; k = i + j; printf( "k = %d", k ); Copyright Roman Simiński Strona : 2
Instrukcje warunkowe Instrukcja warunkowa if i instrukcja alternatywy if- Instrukcja warunkowa if Instrukcja alternatywy if- if( wyrażenie ) instrukcja if( wyrażenie ) instrukcja_1 instrukcja_2 wyrażenie prawda prawda wyrażenie fałsz fałsz instrukcja instrukcja_1 instrukcja_1 Copyright Roman Simiński Strona : 3
Instrukcje warunkowe Jakiego typu jest wyrażenie warunkowe? W języku C nie ma predefiniowanego typu Boolean. Każde wyrażenie dające w wyniku wartość całkowitą różną od zera jest traktowane jako prawdziwe, a dające w wyniku wartość zerową jest traktowane jako fałszywe. W wyrażeniach relacyjnych i porównania prawda to 1, fałsz to 0 całkowite (int). W niektórych przypadkach stosowanie instrukcji warunkowej może być zbędne if( delta < 0 ) brak_rozw_rzecz = 1; brak_rozw_rzecz = 0; brak_rozw_rzecz = ( delta < 0 ); Copyright Roman Simiński Strona : 4
Instrukcje warunkowe, cd.... Gdy potrzebne są TRUE i FALSE #define TRUE 1 #define FALSE 0 #define TRUE (0==0) #define FALSE (!TRUE) Można jeszcze inaczej, wykorzystując typ wyliczeniowy. Przydatne operatory Operator Znaczenie == równe!= różne! logiczna negacja && logiczny and logiczny or Porównywanie z zerem zwykle można uprościć if( delta == 0 ) if(!delta ) if( delta!= 0 ) if( delta ) Copyright Roman Simiński Strona : 5
Instrukcje warunkowe, cd.... Uwaga na zagnieżdżone instrukcje if- if( kwota >= 0 ) /* Wydaje si ę */ if( kwota > 0 ) printf( "Dochod" ); printf( "Strata" ); if( kwota >= 0 ) /* Jest */ if( kwota > 0 ) printf( "Dochod" ); printf( "Strata" ); Trzeba: if( kwota >= 0 ) if( kwota > 0 ) printf( "Dochod" ); printf( "Strata" ); if( kwota >= 0 ) if( kwota > 0 ) printf( "Dochod" ); printf( "Zero!" ); printf( "Strata" ); Copyright Roman Simiński Strona : 6
Instrukcja przełączająca switch Postać ogólna switch( wyrażenie ) case wyrażenie_stałe : instrukcje case wyrażenie_stałe : instrukcje default : instrukcje Instrukcja switch: sprawdza czy wartość wyrażenia jest równa jednemu z kilku przypadków określonych wyrażeniem stałym, wykonuje skok do instrukcji zapisanych za owym wyrażeniem stałym. Jeżeli nie znaleziono przypadku pasującego do wartości wyrażenia, wykonywane są instrukcje zapisane po frazie default. Instrukcja służy do podejmowania decyzji wielowariantowych. Wszystkie wyrażenia są typu całkowitego. Copyright Roman Simiński Strona : 7
Instrukcja przełączająca switch, cd.... Przykład + ilustracja graficzna int przypadek; switch( przypadek ) case 0 : puts( "przypadek == 0" ); case 1 : puts( "przypadek == 1" ); default : puts( "przypadek!= 0 i przypadek!= 1" ); sterowanie: wejście do instr. switch przypadek ==? case 0: case 1: default: puts( przypadek == 0 ); puts( przypadek!= 1 ); puts( przypadek!= 0 i przypadek!= 1 ); sterowanie: wyjście z instr. switch Copyright Roman Simiński Strona : 8
Instrukcja przełączająca switch, cd.... Instrukcja switch to nie jest instrukcja wyboru jak ją zrobić w C? int przypadek; switch( przypadek ) case 0 : puts( "przypadek == 0" ); case 1 : puts( "przypadek == 1" ); default : puts( "przypadek!= 0 i przypadek!= 1" ); sterowanie: wejście do instr. switch przypadek ==? case 0: case 1: default: puts( przypadek == 0 ); puts( przypadek!= 1 ); puts( przypadek!= 0 i przypadek!= 1 ); sterowanie: wyjście z instr. switch Instrukcja break powoduje wyjście (zakończenie wykonania) instrukcji iteracyjnej lub instrukcji switch. Copyright Roman Simiński Strona : 9
Instrukcja przełączająca switch, cd.... Przykład wykorzystania Przykład rozpoznanie czy znak jest literą, cyfrą lub znakiem interpunkcyjnym. switch( znak ) case 0 : case 1 : char znak; case 2 : znak = getchar(); case 3 : case 4 : case 5 : case 7 : case 8 : case 9 : puts( Cyfra ); case, : case. : case ; : puts( Znak interpunkcyjny ); default : if( znak >= A && znak <= Z ) puts( Duża litera ); if( znak >= a && znak <= z ) puts( Mała litera ); puts( Inny znak ); Copyright Roman Simiński Strona : 10
Instrukcja przełączająca switch, cd.... Przykład wykorzystania Przykład rozpoznanie i obsługa klawiszy naciskanych przez użytkownika. switch( get_key_from_keyboard() ) case ALT_F1 : show_last_used_help(); case CTRL_F1 : show_current_context_help(); case F1 : show_general_help(); case CTR_F4 : case ESC : close_current_window(); Copyright Roman Simiński Strona : 11
Instrukcja przełączająca switch, cd.... Uwagi dodatkowe Instrukcje nie muszą stanowić bloku: switch( error_code ) case -1 : puts( Błąd! ); make_report(); case 0 : puts( Brak błędu ); do_something(); switch( error_code ) case -1 : case 0 : puts( Błąd! ); make_report(); puts( Brak błędu ); do_something(); Uwaga przypadek default nie musi być ostatnim na liście. Warto dla tego przypadku również stosować instrukcje break. Copyright Roman Simiński Strona : 12
Instrukcje iteracyjne Instrukcja iteracyjna do-while Przypadek ogólny do instrukcja while( wyrażenie ); instrukcja Z wykorzystaniem instrukcji złożonej do ciąg instrukcji while( wyrażenie ); prawda wyrażenie fałsz Instrukcja stanowiąca ciało iteracji do-while wykona się przynajmniej raz. Wyrażenie występujące w nawiasach określa warunek kontynuacji, zatem iteracja kończy się gdy wartość wyrażenia będzie zerowa. Copyright Roman Simiński Strona : 13
Instrukcje iteracyjne Przykład wykorzystania iteracji do-while Zabezpieczenie wprowadzania danych danych, do-while + if do printf( "Podaj wiek osoby:" ); gets( linia ); wiek = atoi( linia ); if( wiek <= 0 ) printf( "Wiek musi być liczb ą dodatni ą i różn ą od zera!\n" ); while( wiek <= 0 ); Copyright Roman Simiński Strona : 14
Instrukcje iteracyjne Przykład wykorzystania iteracji do-while organizacja prostego menu do puts( "\nformatowanie dysku, wybierz opcje:" ); printf( "\n1. Format\n2. Szybki format\n3. Diagnostyka\n4. Koniec\n> ); klawisz = getchar(); fflush( stdin ); switch( klawisz ) case '1' : full_disk_format(); case '2' : quick_disk_format(); case '3' : check_disk(); /* switch */ while( klawisz!= 4 ); Zamiast fflush: void czyszczenie_bufora() while( getchar()!= '\n' ) ; Copyright Roman Simiński Strona : 15
Instrukcje iteracyjne Instrukcja iteracyjna while Przypadek ogólny while( wyrażenie ) instrukcja Z wykorzystaniem instrukcji złożonej while( wyrażenie ) ciąg instrukcji prawda instrukcja wyrażenie fałsz Instrukcja stanowiąca ciało iteracji while może nie wykonać się wcale. Wyrażenie występujące w nawiasach określa warunek kontynuacji, zatem iteracja kończy się gdy wartość wyrażenia będzie zerowa. Copyright Roman Simiński Strona : 16
Instrukcje iteracyjne Przykład wykorzystania iteracji while sylwestrowe odliczanie ;-) int licznik = 10; while( licznik > 0 ) printf( "\n%d...", licznik ); licznik--; printf( \nnowy Rok!!! ); licznik- odpowiada licznik = licznik - 1 Porównywanie z zerem często zapisuje się krócej while( licznik > 0 ) printf( "\n%d...", licznik ); licznik--; while( licznik ) printf( "\n%d...", licznik ); licznik--; Uwaga wersja uproszczona może być niebezpieczna int licznik = 11; while( licznik > 0 ) printf( "\n%d...", licznik ); licznik = licznik - 2; Copyright Roman Simiński Strona : 17
Instrukcje iteracyjne Instrukcja iteracyjna for Nie ma nic wspólnego poza nazwą z instrukcją iteracyjną for z języka Pascal. Instrukcja for w języku C stanowi uogólnienie schematu iteracji while. int licznik; licznik = 10; Inicjalizacja Warunek while( licznik > 0 ) printf( "\n%d...", licznik ); licznik--; Modyfikacja printf( \nnowy Rok!!! ); Ciało iteracji int licznik; Inicjalizacja Warunek Modyfikacja for( licznik = 10 ; licznik > 0 ; licznik-- ) printf( "\n%d...", licznik ); printf( \nnowy Rok!!! ) Ciało iteracji Copyright Roman Simiński Strona : 18
Instrukcje iteracyjne Instrukcja iteracyjna for ogólny schemat inicjalizacja; while( warunek ) ciało_iteracji modyfikacja for( inicjalizacja; warunek; modyfikacja ) ciało_iteracji Uwaga poszczególne sekcje iteracji for mogą być dowolnymi legalnymi, być może złożonymi, wyrażeniami w języku C. Mogą to być wyrażenia przecinkowe. int licznik; for( licznik = 10; licznik > 0; printf( \n%d..., licznik-- ) ) ; printf( \nnowy Rok!!! ); int i, j; for( i = 0, j = 10; i!= j; i++, j-- ) printf( \ni = %d j = %d, i, j ); Copyright Roman Simiński Strona : 19
Instrukcje break i continue Instrukcje break i continue wspomaganie iteracji i instrukcji switch Instrukcja break pozwala na natychmiastowy wyskok z najbardziej zagnieżdżonej, dowolnej instrukcji iteracyjnej lub instrukcji switch. Instrukcja continue pozwala na przerwanie bieżącego przebiegu dowolnej iteracji i przejście do wykonania następnego przebiegu od jego początku. Dla iteracji while i do-while instrukcja continue powoduje przeniesienie sterowania do fazy testowania warunku kontynuacji. W przypadku iteracji for sterowanie przenoszone jest do wyrażenia modyfikującego a potem do testowania warunku. switch( klawisz ) case '1' : full_disk_format(); case '2' : quick_disk_format(); case '3' : check_disk(); klawisz = getchar(); while( klawisz!= '\n' ) if( klawisz == 'k' ) Copyright Roman Simiński Strona : 20
Instrukcje break i continue Przykład wykorzystania instrukcji break i continue for( ; ; ) /* Iteracja nieskończona czyli pętla */ puts( "\nformatowanie dysku, wybierz opcje:" ); printf( "\n1. Format\n2. Szybki format\n3. Diagnostyka\n4. Koniec\n> ); klawisz = getchar(); fflush( stdin ); if( klawisz == 4 ) /* Czy wybrano klawisz końca?*/ /* Tak, wychodzimy z iteracji */ if(!( klawisz >= 0 && klawisz <= 9 ) ) /* Czy klawisz jest cyfr ą? */ continue; /* Klawisz nie jest cyfr ą, nie ma co dalej sprawdzać */ switch( klawisz ) case '1' : full_disk_format(); case '2' : quick_disk_format(); case '3' : check_disk(); /* switch */ Stosowanie break i continue jest czasem bardzo wygodne, są to jednak instrukcje niestrukturalne i ich stosowanie może zacznie pogorszyć czytelność kodu. Copyright Roman Simiński Strona : 21
Instrukcja return Instrukcja powrotu z podprogramu Każda funkcja wraca do miejsca swojego wywołania po osiągnięciu końca jej bloku lub napotkaniu instrukcji return. Jeżeli po słowie return występuje wyrażenie, to wartość tego wyrażenia jest przekazywana do miejsca wywołania. Instrukcja return może być również stosowana dla funkcji o type rezultatu void, umożliwia to wcześniejsze zakończenie działania funkcji. float delta( float a, float b, float c ) return b * b - 4 * a * c; float pole_trojkata( float a, float h ) return 0.5 * a * h; float wczytaj_liczbe_f( char komunikat[] ) char bufor_tekstowy[ 80 ]; printf( komunikat ); fgets( bufor_tekstowy, 80, stdin ) ; return atof( bufor_tekstowy ); Copyright Roman Simiński Strona : 22
Instrukcja return Instrukcja powrotu plusy i minusy Napisać funkcję, otrzymującą jako parametr sumaryczny roczny dochód, wyświetlającą informację tekstową o zarobku, stracie bądź zerowym dochodzie. void wypisz_info( float sum_dochod ) if( sum_dochod == 0 ) printf( "Nic nie zarobiles" ); return; void wypisz_info( float sum_dochod ) if( sum_dochod == 0 ) printf( "Nic nie zarobiles" ); if( sum_dochod > 0 ) printf( "Zarobiles!" ); if( sum_dochod > 0 ) printf( "Zarobiles!" ); return; if( sum_dochod < 0 ) printf( "Straciles!" ); return; if( sum_dochod < 0 ) printf( "Straciles!" ); void wypisz_info( float sum_dochod ) if( sum_dochod == 0 ) printf( "Nic nie zarobiles" ); if( sum_dochod > 0 ) printf( "Zarobiles!" ); printf( "Straciles!" ); Copyright Roman Simiński Strona : 23