Priorytety operatorów Łączność operatorów Operatory
Transkrypt
Priorytety operatorów Łączność operatorów Operatory
Priorytety operatorów ● Łączność operatorów Mówią o tym, jaka jest kolejność aplikowania operatorów w wyrażeniu/przypisaniu – ● 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) – ● ● 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 – kolejność możemy wymuszać nawiasowaniem wszystkie pozostałe i + j + k ≡ (i + j) + k Szczegóły: Kerninghan i Ritchie „Język ANSI C” 115 116 Operatory - podsumowanie ● ● ● ● ● ● Sterowanie wykonaniem programu Operator „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”, a dowolna inna - „prawdę” Wprowadzenie: – programowanie strukturalne – podejmowanie decyzji – „pętle” – rozgałęzienia – instrukcja „goto” Na sposób obliczania wartości wyrażeń mają wpływ priorytety operatorów Operatory unarne, przypisania i warynkowy łączą się od prawej do lewej; wszystkie pozostałe – od lewej do prawej Uwaga na priorytety operatorów bitowych – najlepiej stosować nawiasowanie! 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: – wykonanie ciągu akcji podejmowanie decyzji ● – Każda z wymienionych konstrukcji może być przedstawiona w postaci „schematu blokowego” złożenie sekwencyjne ● – ● wybór akcji (bądź jej zaniechania) w zależności od spełnienia określonego warunku ciąg akcji pętle ● powtarzanie akcji w zależności od spełnienia określonego warunku 119 120 Programy składane z „klocków” ● Programy składane z „klocków” Każda z wymienionych konstrukcji może być przedstawiona w postaci „schematu blokowego” ● Każda z wymienionych konstrukcji może być przedstawiona w postaci „schematu blokowego” warunek warunek niespełniony ● spełniony spełniony niespełniony podejmowanie decyzji ● 121 ciąg akcji pętla typu „while-do” 122 Programy składane z „klocków” ● Podstawowe elementy schematów Każda z wymienionych konstrukcji może być 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. Operacja wej.-wyj. - np. wprowadzanie danych lub drukowanie wyników. ciąg akcji Przetwarzanie. Operacja bądź ciąg operacji wykonywanych przez komputer, takich, jak przypisania, operacje arytmetyczne itp. 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. spełniony niespeł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. warunek ● Krawędź przepływu. Łączy elementy schematu blokowego i obrazuje następstwo w ciągu operacji wykonywanych przez algorytm. pętla typu „do-while” 123 124 Przykład 1: obliczanie silni Przykład 2: kasa start start suma=0 założenie: n≥0 wczytaj n wprowadź(cena) silnia=1 suma=suma+cena NIE stop n > 0 vat=suma * 0.22 kwota=suma+vat TAK TAK Więcej towarów? NIE Dukuj(suma, vat, total) silnia*=n n=n1 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 ● { instr_1; instr_2; ... instr_n; } instr_1; instr_2; ... instr_n; Język ANSI C oferuje dwa rodzaje instrukcji wyboru: – ifelse – switch ● ● szczególny przypadek instrukcji ifelse pozwala dokonywać wyboru na podstawie wartości parametru będącego liczbą całkowitą 127 Instrukcja ifelse Instrukcja ifelse – przykład if (wyrażenie) instrukcja_1 else instrukcja_2 TAK instrukcja_1 wyrażenie != 0 128 NIE instrukcja_2 129 #include <stdio.h> int main() { 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"); } return 0; } 130 Instrukcja switch ● ● Pozwala podejmować decyzje „wielowariantowe”, w których sprawdzamy, czy wartość pewnego wyrażenia pasuje do jednej z kilku stałych całkowitych „Obsługa” każdego z przypadków może być zakończona instrukcją break; – ● Instrukcja switch – przykład 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 #include <stdio.h> int main() { 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"); } return 0; } 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 – pętla for for (ini; war; iter) instrukcja typu do-while – do instrukcja while (wyrażenie) 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 Rozgałęzienia int i=255; for (;;) printf("%d ",i); ● break – i=255; for (;i;printf("%d ",i=i>>1)); ● i=255; for (;i>>1;) printf("%d ",i); continue – i=255; for (;printf("%d ",i=i>>1)2;); ● i=255; for (;(i=i>>1);) printf("%d ",i); 137 powoduje natychmiastowe opuszczenie najbardziej zagnieżdżonej pętli bądź instrukcji switch, w której występuje przechodzi do następnego „obrotu pętli” - np. w przypadku pętli „whiledo” 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 138 break i continue – przykład goto – przykład /* W tablicy tab szukamy nieparzystej liczby dwucyfrowej, której suma cyfr wynosi 7 */ #include <stdio.h> #define SIZE 5 int main() { 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; } } return 0; } 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 goto – cała prawda ● 140 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) ● ● 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 Najczęściej stosowanymi w praktyce pętlami są for oraz whiledo 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 */ #include <stdio.h> /* sumuj2.c sumowanie liczb całkowitych */ #include <stdio.h> int main() { long liczba; long suma = 0L; // inicjalizacja 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); } printf("Suma wynosi %ld.\n", suma); return 0; } int main() { long liczba; long suma = 0L; // inicjalizacja printf("Podaj pierwszą liczbę "); printf("(q - zakończ): "); while (scanf("%ld",&liczba)) { suma = suma + liczba; printf("Podaj kolejną liczbę "); printf("(q - zakończ): "); } printf("Suma wynosi %ld.\n", suma); return 0; } 143 Przykład – wersja 3 144 Przykład – wersja 4 /* sumuj3.c sumowanie liczb całkowitych */ #include <stdio.h> /* sumuj4.c sumowanie liczb całkowitych */ #include <stdio.h> int main() { long n; long suma = 0L; // inicjalizacja int status; do { printf("Podaj liczbę (q - zakończ): "); status = scanf("%ld",&n); suma += (status ? n : 0); } while (status); printf("Suma wynosi %ld.\n", suma); return 0; } int main() { long n; long suma = 0L; // inicjalizacja int nxt = 1; do { printf("Podaj liczbę (q - zakończ): "); suma += (scanf("%ld",&n) ? n : (nxt=0)); } while (nxt); printf("Suma wynosi %ld.\n", suma); return 0; } 145 146 Przykład – wersja 5 Operator przecinkowy ● /* sumuj5.c sumowanie liczb całkowitych */ #include <stdio.h> Wartość pary wyrażeń oddzielonych przecinkiem – int main() { long n; long suma = 0L; // inicjalizacja do { printf("Podaj liczbę (q - zakończ): "); } while (scanf("%ld",&n) ? suma+=n : 0); printf("Suma wynosi %ld.\n", suma); return 0; } 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 */ #include <stdio.h> int main() { 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); return 0; } błąd! 147 uncje.c – wynik działania 148 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 /* sumuj6.c sumowanie liczb całkowitych */ #include <stdio.h> int main() { long n; long suma = 0L; // inicjalizacja do { printf("Podaj liczbę (q - zakończ): "); } while (scanf("%ld",&n) ? (suma+=n), 1 : 0); printf("Suma wynosi %ld.\n", suma); return 0; } Operator przecinkowy nie jest dostępny w języku Java! 149 150 C daje wiele możliwości... :) Złożone typy danych w ANSI C /* HelloWorld – wersja “profesjonalna” */ #include "stdio.h" #define e 3 #define g (e/e) #define h ((g+e)/2) #define f (egh) #define j (e*eg) #define k (jh) #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+fg]; 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=jg;o[f]=o[g]=g;} if((b=n)>=e)for(b=g<<g;b<n;++b)o[b]=o[bh]+o[bg]+c; return(o[bg]%n+kh); default: if(m1=e) main(m1g+e+h,s+g); else *(s+g)=f; for(*s=a=f;a<e;) *s=(*s<<e)|main(h+a++,(char *)m1); } return(0); } ● ● ● ● ● 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) 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 Przykład Jeden z podstawowych typów danych, spotykany w większości języków programowania – – 151 Tablice w ANSI C ● Tablice Bezpośredni dostęp do elementów tablicy za pomocą operatora indeksowania ([]) Indeksowanie za pomocą liczb naturalnych – od 0 do n1, gdzie „n” to zadeklarowany rozmiar tablicy 153 /* wczytuje liczby do tablicy (do napotkania 0) i drukuje je w odwrotnej kolejności */ #include <stdio.h> #define SIZE 50 int main() { 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 = n1; i >= 0; i) printf("%d ", liczby[i]); return 0; } 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 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 155