Priorytety operatorów Łączność operatorów Mówią o tym, jaka jest kolejność aplikowania operatorów w wyrażeniu/przypisaniu Mówią o tym, jaka jest wiemy np. z matematyki, że mnożenie jest silniejsze (ma wyższy priorytet) od dodawania: 1+2*3 = 7 a nie 9 ANSI C stosuje operatory arytmetyczne zgodnie z intuicją: najpierw operatory unarne, potem binarne wpierw multiplikatywne, a następnie addytywne najniższy priorytet mają operatory przypisania (pomijając operator przecinka, ale o nim potem) kolejność możemy wymuszać nawiasowaniem Mówi o porządku,, w jakim stosowane są operatory o takim samym priorytecie, sąsiadujące ze sobą w wyrażeniu/przypisaniu Od prawej do lewej operatory unarne (jednoargumentowe) operator wyrażenia warunkowego...?... :... przypisanie oraz jego warianty operatorowe i = j = k i = (j = k) Od lewej do prawej wszystkie pozostałe i + j + k (i + j) + k Szczegóły: Kerninghan i Ritchie Język ANSI C 115 116 Operatory - podsumowanie Operator modulo modulo % zwraca resztę z dzielenia całkowitego Równość w ANSI C oznaczamy przez == W kontekście wyrażeń logicznych wartość 0 reprezentuje fałsz fałsz, a dowolna inna - prawdę prawdę Na sposób obliczania wartości wyrażeń mają wpływ priorytety operatorów Na sposób obliczania wartości wyrażeń mają wpływ Operatory unarne, przypisania i warynkowy łączą się od prawej do lewej; wszystkie pozostałe od lewej do prawej Operatory unarne, przypisania i warynkowy Uwaga na priorytety operatorów bitowych najlepiej stosować nawiasowanie! Uwaga na priorytety operatorów bitowych Sterowanie wykonaniem programu Wprowadzenie: programowanie strukturalne podejmowanie decyzji pętle rozgałęzienia instrukcja goto 117 118
Programowanie strukturalne Programy składane z klocków Już w latach 60-tych XX wieku pokazano, że dowolny algorytm da się zaimplementować stosując jedynie trzy proste konstrukcje: Już w latach 60-tych XX wieku pokazano, że złożenie sekwencyjne wykonanie ciągu akcji podejmowanie decyzji wybór akcji (bądź jej zaniechania) w zależności od spełnienia określonego warunku wybór akcji (bądź jej zaniechania) w zależności od pętle powtarzanie akcji w zależności od spełnienia określonego warunku powtarzanie akcji w zależności od spełnienia przedstawiona w postaci schematu blokowego ciąg akcji 119 120 Programy składane z klocków Programy składane z klocków przedstawiona w postaci schematu blokowego przedstawiona w postaci schematu blokowego warunek warunek spełniony niespełniony spełniony niespełniony ciąg akcji podejmowanie decyzji pętla typu while-do 121 122
Programy składane z klocków Podstawowe elementy schematów przedstawiona w postaci schematu blokowego Terminator. Wskazuje punkt startu oraz punkty zakończenia działania algorytmu. Terminator ma zawsze tylko jedną krawędź, która łączy go z resztą diagramu. ciąg akcji Operacja wej.-wyj. - np. wprowadzanie danych lub drukowanie wyników. Przetwarzanie. Operacja bądź ciąg operacji wykonywanych przez komputer, takich, jak przypisania, operacje arytmetyczne itp. niespełniony warunek spełniony Decyzja. Oznacza punkt podejmowania decyzji. Diament ma zawsze dwie krawędzie wychodzące jedna odpowiada sytuacji, gdy warunek jest spełniony, a druga gdy nie jest spełniony. Akcja predefiniowana. Jedno polecenie oznaczające grupę wcześniej zdefiniowanych instrukcji. Na przykład, Oblicz n! oznacza, że komputer ma obliczyć wartość funkcji silnia dla argumentu n. pętla typu do-while Krawędź przepływu. Łączy elementy schematu blokowego i obrazuje następstwo w ciągu operacji wykonywanych przez algorytm. 123 124 Przykład 1: obliczanie silni Przykład 2: kasa start start założenie: n 0 wczytaj n suma=0 wprowadź(cena) silnia=1 stop NIE n > 0 TAK silnia*=n n=n 1 TAK suma=suma+cena Więcej towarów? NIE vat=suma * 0.22 kwota=suma+vat Dukuj(suma, vat, total) stop 125 126
Instrukcja złożona Podejmowanie decyzji ANSI C pozwala łączyć ciągi instrukcji w całość, tworząc tzw. instrukcje złożone ANSI C pozwala łączyć ciągi instrukcji w całość, instr_1; instr_2;... instr_n; { instr_1; instr_2;... instr_n; Język ANSI C oferuje dwa rodzaje instrukcji wyboru: Język ANSI C oferuje dwa rodzaje instrukcji if else switch szczególny przypadek instrukcji if else pozwala dokonywać wyboru na podstawie wartości parametru będącego liczbą całkowitą pozwala dokonywać wyboru na podstawie wartości 127 128 Instrukcja if else Instrukcja if else przykład TAK instrukcja_1 if (wyrażenie) instrukcja_1 else instrukcja_2 wyrażenie!= 0 NIE instrukcja_2 129 int wiek; printf("twój wiek: "); scanf("%d",&wiek); if (wiek<20) puts("dziecko."); else if (wiek<40) puts("młodziak!"); else if (wiek<80) puts("w sile wieku."); else { char odp; printf("naprawdę? "); scanf("%c",&odp); if (odp=='t' odp=='t') puts("gratulacje!"); else puts("tak myślałem"); 130
Instrukcja switch Pozwala podejmować decyzje wielowariantowe wielowariantowe, w których sprawdzamy, czy wartość pewnego wyrażenia pasuje do jednej z kilku stałych całkowitych Pozwala podejmować decyzje Obsługa każdego z przypadków może być zakończona instrukcją break; w przeciwnym wypadku sterowanie przejdzie do rozważania kolejnego przypadku Opcjonalny przypadek default pozwala obsłużyć sytuację, gdy wartość wyrażenia nie pasuje do żadnej z wymienionych stałych 131 Instrukcja switch przykład int wiek; char odp; printf("twój wiek: "); scanf("%d",&wiek); switch (wiek/20) { case 0: puts("dziecko."); break; case 1: puts("młodziak!"); break; case 2: puts("w sile wieku."); break; default : printf("naprawdę? "); scanf("%c",&odp); if (odp=='t' odp=='t') puts("gratulacje!"); else puts("tak myślałem"); 132 Pętle w ANSI C Pętle w ANSI C c.d. Dostępne są trzy rodzaje pętli typu while-do: while (wyrażenie) instrukcja typu do-while do instrukcja while (wyrażenie) pętla for for (ini; war; iter) instrukcja równoważna pętli: ini; while (war) { instrukcja iter; 133 134
Pętla while przykład Pętla for przykład /* Liczymy od 1 do n */ int i=1; while (i<=n) { printf("%d ",i); i += 1; /* Liczymy od 1 do n */ int i; for (i=1; i<=n; i++) printf("%d ",i); /* Krótsza wersja */ int i=1; while (i<=n) printf("%d ",i++); 135 136 Pętla for ciekawsze przykłady int i=255; for (;;) printf("%d ",i); i=255; for (;i;printf("%d ",i=i>>1)); i=255; for (;i>>1;) printf("%d ",i); i=255; for (;printf("%d ",i=i>>1) 2;); i=255; for (;(i=i>>1);) printf("%d ",i); break Rozgałęzienia powoduje natychmiastowe opuszczenie najbardziej zagnieżdżonej pętli bądź instrukcji switch,, w której występuje continue przechodzi do następnego obrotu pętli - np. w przypadku pętli while do while do przeskakuje do testowania warunku goto pozwala na skok do miejsca oznaczonego etykietą umożliwia wyskakiwanie z wnętrza nawet zagnieżdżonych (wielopoziomowych) pętli 137 138
break i continue przykład goto przykład /* W tablicy tab szukamy nieparzystej liczby dwucyfrowej, której suma cyfr wynosi 7 */ #define SIZE 5 int i,c1,c2, tab[size]={15,37,61,12,99; /* Zał.: tab zawiera liczby dwucyfrowe */ for (i=0; i<size; i++) { if (tab[i]%2==0) continue; /* pomijamy liczby parzyste */ c1=tab[i]/10; /* pierwsza cyfra */ c2=tab[i]%10; /* druga cyfra */ if (c1+c2 == 7) { printf("znaleziona: %d ",tab[i]); break; int i,j, a[max1], b[max2]; for (i=0; i<max1; i++) for (j=0; j<max2; j++) if (a[i]==b[j]) goto jest; /* nie znaleziono */... return 1; jest: /* znaleziono a[i]==b[j] */... 139 140 goto cała prawda Instrukcje sterujące podsumowanie Każdy program wykorzystujący instrukcję goto można napisać bez niej (na( ogół kosztem pewnych dodatkowych sprawdzeń oraz dodania zmiennych pomocniczych) Każdy program wykorzystujący instrukcję goto int i,j, a[max1], b[max2], jest=0; for (i=0; i<max1 &&!jest; i++) for (j=0; j<max2 &&!jest; j++) if (a[i]==b[j]) jest=1; if (!jest) {...; return 1; else {... 141 Wszystkie algorytmy można wyrazić stosując: ciągi prostych instrukcji, instrukcje warunkowe i pętle Wszystkie algorytmy można wyrazić stosując: ciągi Najczęściej stosowanymi w praktyce pętlami są for oraz while do Instrukcje rozgałęziania continue i break pozwalają w kontrolowany sposób opuszczać pętle Instrukcja goto nie będziemy używać jest nadmiarowa jej zastosowanie może znacząco skomplikować logiczną strukturę kodu 142
Przykład wersja 1 Przykład wersja 2 /* sumuj1.c sumowanie liczb całkowitych */ long liczba; int status; printf("podaj pierwszą liczbę "); printf("(q - zakończ): "); status = scanf("%ld", &liczba); while (status==1) { suma = suma + liczba; printf("podaj kolejną liczbę "); printf("(q - zakończ): "); status = scanf("%ld", &liczba); 143 /* sumuj2.c sumowanie liczb całkowitych */ long liczba; printf("podaj pierwszą liczbę "); printf("(q - zakończ): "); while (scanf("%ld",&liczba)) { suma = suma + liczba; printf("podaj kolejną liczbę "); printf("(q - zakończ): "); 144 Przykład wersja 3 Przykład wersja 4 /* sumuj3.c sumowanie liczb całkowitych */ long n; int status; do { printf("podaj liczbę (q - zakończ): "); status = scanf("%ld",&n); suma += (status? n : 0); while (status); /* sumuj4.c sumowanie liczb całkowitych */ long n; int nxt = 1; do { printf("podaj liczbę (q - zakończ): "); suma += (scanf("%ld",&n)? n : (nxt=0)); while (nxt); 145 146
Przykład wersja 5 Operator przecinkowy /* sumuj5.c sumowanie liczb całkowitych */ long n; do { printf("podaj liczbę (q - zakończ): "); while (scanf("%ld",&n)? suma+=n : 0); błąd! 147 Wartość pary wyrażeń oddzielonych przecinkiem oblicza się od lewej do prawej wartość lewego wyrażenia jest zaniedbywana typem i wartością wyniku jest typ i wartość prawego wyrażenia /* uncje.c taryfa pocztowa */ const int F_OZ = 37; const int N_OZ = 23; int w, c; printf(" uncje cena\n"); for (w=1, c=f_oz; w <= 16; w++, c+=n_oz) printf("%5d $%4.2f\n", w, c/100.0); 148 uncje.c wynik działania Przykład wersja 6 uncje cena 1 $0.37 2 $0.60 3 $0.83 4 $1.06 5 $1.29 6 $1.52 7 $1.75 8 $1.98 9 $2.21 10 $2.44 11 $2.67 12 $2.90 13 $3.13 14 $3.36 15 $3.59 16 $3.82 149 /* sumuj6.c sumowanie liczb całkowitych */ long n; do { printf("podaj liczbę (q - zakończ): "); while (scanf("%ld",&n)? (suma+=n), 1 : 0); Operator przecinkowy nie jest dostępny w języku Java! 150
C daje wiele możliwości... :) /* HelloWorld wersja profesjonalna */ #include "stdio.h" #define e 3 #define g (e/e) #define h ((g+e)/2) #define f (e g h) #define j (e*e g) #define k (j h) #define l(x) tab2[x]/h #define m(n,a) ((n&(a))==(a)) long tab1[]={ 989L,5L,26L,0L,88319L,123L,0L,9367L ; int tab2[]={ 4,6,10,14,22,26,34,38,46,58,62,74,82,86 ; main(m1,s) char *s; { int a,b,c,d,o[k],n=(int)s; if(m1==1){ char b[2*j+f g]; main(l(h+e)+h+e,b); printf(b); else switch(m1 =h){ case f: a=(b=(c=(d=g)<<g)<<g)<<g; return(m(n,a c) m(n,b) m(n,a d) m(n,c d)); case h: for(a=f;a<j;++a)if(tab1[a]&&!(tab1[a]%((long)l(n))))return(a); case g: if(n<h)return(g); if(n<j){n =g;c='d';o[f]=h;o[g]=f; else{c='\r' '\b';n =j g;o[f]=o[g]=g; if((b=n)>=e)for(b=g<<g;b<n;++b)o[b]=o[b h]+o[b g]+c; return(o[b g]%n+k h); default: if(m1 =e) main(m1 g+e+h,s+g); else *(s+g)=f; for(*s=a=f;a<e;) *s=(*s<<e) main(h+a++,(char *)m1); return(0); 151 Złożone typy danych w ANSI C Tablice przechowują ciągi elementów danego typu łańcuchy znaków (napisy), to szczególny przypadek typu tablicowego tablica znaków Struktury pozwalają grupować wartości różnych typów taka grupa wartości stanowi jedną całość i może być np. wykorzystana w instrukcji przypisania 152 Tablice w ANSI C Przykład Jeden z podstawowych typów danych, spotykany w większości języków programowania Jeden z podstawowych typów danych, spotykany Przechowuje ciąg elementów tego samego typu Rozmiar tablicy jest stały określany w momencie deklaracji do określania rozmiaru nie można stosować stałych (zadeklarowanych z użyciem const) na ogół stosuje się stałe zdefiniowane za pomocą preprocesora (np. #define stala 20) Bezpośredni dostęp do elementów tablicy za pomocą operatora indeksowania ([]( []) Indeksowanie za pomocą liczb naturalnych od 0 do n 1,, gdzie n to zadeklarowany rozmiar tablicy 153 /* wczytuje liczby do tablicy (do napotkania 0) i drukuje je w odwrotnej kolejności */ #define SIZE 50 int i, n, liczba; int liczby[size]; for (n = 0; n < SIZE; ++n) { printf("podaj liczbę (0 - zakończ): "); scanf("%d", &liczba); if (liczba==0) break; liczby[n] = liczba; for (i = n 1; i >= 0; i) printf("%d ", liczby[i]); 154
Inicjalizacja tablicy Inicjalizacja listą wartości int a[] = {10,20,30,40,50; Deklaracja rozmiaru jest opcjonalna zadeklarowany rozmiar musi być nie mniejszy niż długość podanej listy wartości niepodane wartości są inicjalizowane zerami niepodane wartości są inicjalizowane jeśli lista wartości jest dłuższa niż rozmiar, wówczas kompilator zasygnalizuje błąd jeśli rozmiar nie został zadeklarowany, to tablica otrzymuje rozmiar równy długości podanej w inicjalizacji listy wartości jeśli lista wartości jest dłuższa niż rozmiar, wówczas 155