Dr inż. Grażyna KRUPIŃSKA Grazyna.Krupinska@fis.agh.edu.pl D-10 pokój 227 WYKŁAD 8 WSTĘP DO INFORMATYKI
Kolejność obliczeń 2 Język C nie określa kolejności obliczania podwyrażeń obliczanego wyrażenia. x = f()+ g(); Nie ma gwarancji, że f()zostanie obliczone przed g(). x = 2*6 + 6*9; Wykonują się przed dodawaniem, ale, który jako pierwszy zależy od kompilatora
3 Zachowania nieokreślone i niezdefiniowane a[i]=i++;// Nie wiemy czy zostanie zmodyfikowana komórka a[i] czy a[i+1]. int i=7; printf( %d\n, i * i++); //Wypisuje 56, a wydaje się, że powinno być 49 int i=3; i = i++;//doświadczenie pokazuje, że i może mieć wartość 3, 4 albo 7. Zachowanie kodu, który zawiera wiele niejednoznacznych efektów ubocznych, zawsze jest niezdefiniowane. Pojedyncze wyrażenie nie powinno modyfikować dwa razy tego samego obiektu, ani jednocześnie modyfikować i pobierać wartości.
Punkty sekwencyjne 4 Skutek uboczny to każda modyfikacja obiektu danych lub pliku Punkt sekwencyjny to miejsce, w którym wszystkie efekty uboczne danego wyrażenia zostały zrealizowane : na końcu wyrażenia będącego samodzielną instrukcją wewnątrz operatorów:, &&,?:, przecinek przy wywołaniu funkcji (po obliczeniu argumentów, tuż przed skokiem do funkcji).
Punkty sekwencyjne 5 1. Pomiędzy poprzednim a następnym punktem sekwencyjnym wartość, przechowywana przez dany obiekt może zostać zmodyfikowana najwyżej raz! 2. Poprzednia wartość obiektu może zostać użyta jedynie do określenia nowej wartości. z = i++ * i++; //1 i = i++; //1 z = i++ && i++; //Jednoznaczne a[i]=i++; //2 i=i++; //2 modyfikujemy zmienną i oraz używamy jej wartości
Instrukcje 6 Instrukcja to podstawowy element składowy programu. Program to skończony ciąg instrukcji. Instrukcja określa akcję, działanie. Instrukcja to każde poprawne wyrażenie języka C zakończone średnikiem. Z każdym wyrażeniem w języku C związana jest wartość. Najprostszą instrukcją jest instrukcja pusta. ; x = 13 + ( y = 5) ; podwyrażenie jest kompletnym polecenie, jest jednak tylko częścią pełnej instrukcji.
Instrukcja printf() 7 Operacje wejścia/wyjścia w języku C nie wchodzą w skład języka. Programista może realizować operacje wejścia/wyjścia za pomocą odpowiednich funkcji i makrodefinicji zawartych w plikach bibliotecznych. #include <stdio.h> Jest ona używana do zapisu ciągu znaków a także wartości zmiennych, odpowiednio sformatowanych, do standardowego pliku wyjściowego stdout. printf (const char *łańcuch_formatujący, lista_danych)
Instrukcja printf() 8 printf("\npole kwadratu o boku a %d wynosi %d", a,a*a); łańcuch formatujący dane Istotnym elementem łańcucha formatującego jest znak %. brak informuje kompilator, że żaden argument nie jest oczekiwany, pojawienie się znaku %jest sygnałem dla kompilatora, że wystąpi specyfikator formatowania i należy oczekiwać listy danych.
Instrukcja printf() 9 Specyfikator formatowania jest pojedynczym znakiem wyznaczającym typ drukowanej zmiennej. Każdy element z listy danych musi mieć specyfikator formatowania. Ogólna postać specyfikatora formatu jest następująca: %[znacznik][szerokość][precyzja][tryb_adresowania][rozmiar][typ] wymagany jest symbol % oraz [typ], inne elementy (pola) są opcjonalne.
Instrukcje 10 Instrukcje w języku C dzielimy na następujące kategorie: wyboru (warunkowe): if, switch, iteracyjne: while, for, do-while, skoku: break, continue, goto, return, etykietowane: case, default, wyrażeniowe, blokowe: {}.
Instrukcje wyboru - if 11 Ogólna postać instrukcji if: if (wyrażenie) instrukcja 1; else instrukcja 2; pojedyncza instrukcja, blok instrukcji lub instrukcja pusta. Część else jest opcjonalna Wyrażenie warunkowe musi generować wynik skalarny: liczba całkowita, znak, wskaźnik, liczba zmiennoprzecinkowa (rzadko wydłuża czas wykonania).
Instrukcje wyboru 12 if (test) { instrukcja_1; instrukcja_2; } if (test) { instrukcja_1; instrukcja_2; } else { instrukcja_3; instrukcja_4; }
Instrukcje wyboru - if 13 Zagnieżdżanie instrukcji if polega na umieszczeniu instrukcji if w bloku instrukcji if lub else. W zagnieżdżonej instrukcji if instrukcja else odpowiada najbliższej instrukcji if, znajdującej się w tym samym bloku co instrukcja else i nie mającej przypisanej już innej instrukcji else. Maksymalne dopuszczalne zagnieżdżenie: 15 poziomów (C89), 127 (C99).
Instrukcje wyboru - if-else-if 14 if( wyrazenie_1 ) instrukcja_1 ; else if ( wyrazenie_2 ) instrukcja_2 ; else if ( wyrazenie_3 ) instrukcja_3 ;... else instrukcja_e ; Warunki obliczane są od góry do dołu. Wykonywana jest instrukcja, dla której spełniony jest warunek, reszta pomijana.
Instrukcje wyboru 15 if (i ==10) printf (" 10\ n"); if (10== i) printf (" 10\ n"); if ((10 -i) ==0) printf (" 10\ n"); if (!(10 - i)) printf (" 10\ n");
Instrukcje wyboru 16 int x=10; if (x>0) printf ("zwiekaszamy x:\n"); x++; printf ("x = %d \n", x);
Instrukcje wyboru 17 int x=20, y=10; if ( (x++ > 10) (y!= 20)) printf ("x = %d, y = %d\n", x, y);
18 Styl akapitowy w C (C indent style, C bracing style) Styl akapitowy określa zasady agregacji kodu w postaci bloków w celu budowy prostej i czytelnej struktury programu. Wyodrębnia się kilka rodzajów stylu akapitowego: Styl BSD/Allman a Styl Kernel a/k&r Styl Whitesmiths a Styl GNU
Styl BSD/Allman a 19 W stylu tym nawiasów klamrowych używa się po segmentach inicjujących. if(x == y) { } something(); somethingelse(); Główną zaletą tego stylu jest wyraźne rozdzielenie zawartości bloku od segmentów inicjujących.
Styl Kernel a/k&r 20 W tym stylu nawias klamrowy otwierający umieszczony jest na tym samym poziomie co segment inicjujący, natomiast nawias klamrowy zamknięty umieszczony jest pod ostatnią instrukcją bloku. if(x == y) { } something(); somethingelse(); Główną zaletą tego stylu jest podkreślenie tego, że blok jest logicznie związany z segmentem inicjującym. Wadą tego stylu w porównaniu ze stylem BSD jest trudność w lokalizacji początku bloku.
Styl Whitesmiths a 21 Styl ten jest podobny do BSD: if(x == y) { something(); somethingelse(); } W stylu tym sposób umieszczenia nawiasów klamrowych umożliwia łatwe, wizualnie wydzielenie blok.
Styl GNU 22 Jest to styl pośredni między stylami BSD i Whitesmiths a if(x == y) { } something(); somethingelse(); Nawiasy klamrowe umieszczane są w jednej kolumnie zajmującej pozycję środkową między lewym skrajnym położeniem, a kolumną, w której pisane są kolejne instrukcje bloku. Styl ten zachowuje zalety stylu BSD i satysfakcjonuje zwolenników stylu Whitesmiths a.
Instrukcje wyboru - switch 23 switch ( wyrazenie ) int lub char. { case a : sekwencja_instrukcji_1 ; break ; case b : sekwencja_instrukcji_2 ; break ;... default : sekwencja_instrukcji_3 ; }
Instrukcje wyboru - switch 24 Wykonywana jest sekwencja instrukcji, następująca po instrukcji case, dla której wartość stałej jest równa wartości wyrażenia. Wykonanie sekwencji instrukcji kończy się w momencie napotkania instrukcji break. Instrukcje związane etykietą default (opcjonalna) zostaną wykonane, jeżeli wartość wyrażenia nie odpowiada żadnemu przypadkowi case.
Instrukcje wyboru - switch 25 Standard C89 (C99) określa, że w instrukcji switch może wystąpić co najmniej 257 (1023) instrukcji case. Gdy w instrukcji switch napotkana zostanie instrukcja break, sterowanie zostanie przekazane do pierwszego wiersza kodu znajdującego się za instrukcją switch Standard C89 (C99) określa, że w instrukcji switch może wystąpić co najmniej 257 (1023) instrukcji case. Gdy w instrukcji switch napotkana zostanie instrukcja break, sterowanie zostanie przekazane do pierwszego wiersza kodu znajdującego się za instrukcją switch
Instrukcje wyboru - switch 26 Instrukcja switch może jedynie sprawdzać równość, inaczej niż instrukcja if, która może sprawdzać dowolny typ wyrażenia logicznego bądź relacyjnego. (liczba > 2 && liczba < 1000) Realizacja przy pomocy switch wymaga etykiet dla każdej liczby od 3 do 999. W instrukcji switch nie może wystąpić dwa razy ta sama wartość. Stałe znakowe automatycznie przekształcane są do wartości typu całkowitego. Instrukcje break nie muszą występować wewnątrz instrukcji switch. Instrukcje switch można zagnieżdżać.
Instrukcje wyboru - switch 27 switch(x) { case 1: printf("1"); case 2: printf("2"); }
28 Instrukcje wyboru - switch
29 Instrukcje wyboru - switch
Instrukcje iteracyjne 30 Instrukcje iteracyjne umożliwiają wielokrotne wykonywanie tego samego zestawu instrukcji do momentu spełnienia określonego warunku.
Instrukcje iteracyjne - for 31 Ogólna postać pętli for: for ( init_lcznk ; wrnk_zknczn ; zmn_lcznk ) instrukcja ; Wykona się zawsze JEDEN raz int i; for (i = 0; i < 10; i++) printf( %d * %d = %d,i,i,i*i);
int licznik; for (licznik = 1; licznik < liczba; licznik++) { instrukcja1; instrukcja2; } 32 kolejne_instrukcje;
Instrukcje iteracyjne - for 33 int i, j; for(i=0, j=10; i + j > 0; i+=2, j-=3) printf ("i = %d, j = %d\n", i,j); for(i=0;i<3 && strcmp(str,"letmein");i++){ printf ("Podaj hasło: \b\b\b\b\b"); scanf("%s",&str); } for (;;) { char ch = getchar (); if (ch == a ) break ; }
Instrukcje iteracyjne - for 34 char * str = " tekst "; for (; *str == ; str ++); int j; for (int i=0; i<10; i++) printf (" i = %d\n ", i);
Instrukcje iteracyjne - for 35 int j; for (int i=0; i<10; i++) j = i * i; printf (" i = %d\n ", i); int i, j; for (i=0; i<10; i++) j = i * i; printf (" i = %d\n ", i);
Instrukcje iteracyjne - for 36 int x; for (printf("podaj liczbe\n") ; x!= 0; ) scanf("%d",&x); int i; int j = 55; for ( int i = 1; j < 75; j =(++i * 5)+ 50)
Instrukcje iteracyjne - while 37 Pętla while jest instrukcją wykorzystującą warunek wejścia. while (warunek) instrukcja; warunek to dowolne wyrażenie. instrukcja to instrukcja pusta, pojedyncza instrukcja lub blok instrukcji.
Instrukcje iteracyjne - while 38 while (test) { instrukcja_1; instrukcja_2; } instrukcja_3;
Instrukcje iteracyjne - while 39 Pętle while oraz for sprawdzają warunek zakończenia na początku. Ciało pętli może nigdy nie być wykonane, jeśli na wstępie warunek wejścia nie jest spełniony. int index=10; while (index++ < 5 ) printf( %d,index); Pętla while jest instrukcją wykorzystującą warunek wejścia char ch='\0'; while (ch!= 'A') ch=getchar();
Instrukcje iteracyjne - while 40 int n = 5; while (n < 7) { printf ("A. n = %d\n", n); n++; printf ("B. n = %d\n", n); } printf (" End n = %d\n", n); n = 5; while (n++ < 7) { printf ("C. n = %d\n", n); } printf (" End n = %d\n", n);
Instrukcje iteracyjne - while 41 int n = 5; while (n < 7) { printf ("A. n = %d\n", n); n++; printf ("B. n = %d\n", n); } printf (" End n = %d\n", n); A. n = 5 B. n = 6 A. n = 6 B. n = 7 End n = 7 n = 5; while (n++ < 7) { printf ("C. n = %d\n", n); } printf (" End n = %d\n", n); C. n = 6 C. n = 7 End n = 8
Instrukcje iteracyjne 42 Pętli for w postaci: for ( l_init ; l_cond ; l_expr ) statement odpowiada pętla while l_init ; while ( l_cond ) { statement l_expr ; }
Instrukcje iteracyjne do while 43 Pętla do-while sprawdza warunek zakończenia na końcu, co oznacza że ciało pętli zadziała co najmniej raz. Często stosowana do obsługi menu. do { instrukcja ; } while ( warunek ); Pętla do while działa do chwili, gdy warunek stanie się fałszywy. do{//petla konczy dzialanie gdy num<=100 scanf("%d", &num); } while (num>100);
Instrukcje iteracyjne do while 44 do { instrukcja_1; instrukcja_2; } while ( warunek ); instrukcja_3;
45 Instrukcja break Instrukcja break ma dwa zastosowania: zakończenie bloku case w instrukcji switch natychmiastowe przerwanie działania pętli, omijając zwykły warunek zakończenia pętli, sterowanie przekazywane jest do pierwszej instrukcji występującej za pętlą. for(t=0; t <100; t++){ printf ("A. %d", t); if (t == 5) break ; } printf ("B. %d", t); A. 0 A. 1 A. 2 A. 3 A. 4 B. 5
Instrukcja break 46 int i, j; for (i = 1; i<=4; i++) { for (j=1; j<=10; j++) if (j == 3) break; // wyskok z najbardziej zagnieżdżonej pętli } printf("i=%d j=%d ", i, j);
Instrukcja continue 47 Instrukcja continue wymusza przejście do kolejnej iteracji pętli, pomijając pozostałą część kodu pętli. W pętli for instrukcja continue powoduje przejście do części iterujacej i a potem do sprawdzenia warunku wejścia. W pętlach while, do-while sterowanie przekazane jest do warunku zakończenia pętli.
Instrukcja skoku return 48 Ogólna postać instrukcji return to: return wyrażenie; wyrażenie występuje tylko wtedy, gdy z deklaracji funkcji wynika, że ma zostać zwrócona wartość. Instrukcja return z określoną wartością może wystąpić jedynie w funkcji, która nie jest typu void. Instrukcji return używa się aby powrócić z funkcji. Instrukcja powoduje przekazanie sterowania do punktu, w którym miało miejsce wywołanie funkcji.
Instrukcja skoku return 49 W C99 (C++) instrukcja return w funkcji niebędącej typu void musi zwrócić wartość. W C89 jeśli funkcja z definicji zwraca wartość, to w dobrym stylu jest zadbanie, aby jakaś wartość została zwrócona. Jeśli nie określi się wartości funkcja przypadkowe wartości.
Instrukcja skoku goto 50 Ogólna postać instrukcji goto to: goto etykieta;... etykieta: Zastosowanie instrukcji skoku goto powoduje zmniejszenie czytelności kodu - spaghetti code. Instrukcje break oraz continue - skoki w przód. Instrukcja goto - skoki w przód i w tył. Wyjście z głęboko zagnieżdżonych pętli, instrukcja goto rozsądnie zastosowana, może okazać się przydatna.
Instrukcja skoku goto 51 if (r >12) // symulacja bloku danych goto a; goto b; a:c *=1.05; f=2; b:rch=c*f; if (r >12) { c *=1.05; f=2; } rch =c*f;
Instrukcja skoku goto 52 while (...) { switch (...) { // instrukcje ; goto loop_done ; // break won t work here // instrukcje ; } // instrukcje ; } loop_done : // instrukcje ;
Instrukcja skoku goto 53 while (f >0){ for (i=1;i <=100; i++){ for (j=1;j <=50; j++){ // instrukcje ; if ( klopoty ) goto pomoc ; // instrukcje ; } // instrukcje ; } // instrukcje ; } pomoc : // instrukcje ;
Instrukcja continue 54 for(t=0; t <7; t++){ printf ("A. %d", t); if (t < 5) continue ; printf ( B. %d", t); } printf ( C. %d", t); A. 0 A. 1 A. 2 A. 3 A. 4 A. 5 B. 5 A. 6 B. 6 C. 7
Funkcja exit() 55 Funkcja exit() powoduje natychmiastowe zakończenie całego programu i powrót do systemu operacyjnego. Prototyp funkcji exit() zdefiniowanej w stdlib.h: void exit (int kod powrotu); wartość kod powrotu przekazywana jest do procesu wywołującego. Na ogół 0 oznacza normalne zakończenie programu. Inne argumenty oznaczają błędy. Dostępne są makra: EXIT SUCCESS oraz EXIT FAILURE.
Style programowania 56 Styl programowania to sposób pisania kodu, który będzie czytelny zarówno dla jego twórcy, jak i innych programistów. Dobry styl jest podstawą dobrego programowania. Dobrego stylu programowania można nauczyć się wyłącznie poprzez zdobycie praktyki. Nie ma uniwersalnej reguły gwarantującej pisanie dobrych programów. Istnieje kilka prostych i przydatnych zasad.
Style programowania 57 Należy używać nazw opisowych dla definicji globalnych, krótkich zaś dla lokalnych. Należy programować w sposób jednolity. Używać nazw czynności dla funkcji. Dbać o precyzję. Stosować wcięcia, aby uwidocznić strukturę. Używać naturalnej postaci wyrażeń. Używać nawiasów, aby rozwiać niejasności. Dzielić wyrażenia złożone. Należy uważać na efekty uboczne.
Style programowania 58 Stosować jednolity sposób rozmieszczania wcięć i nawiasów klamrowych. Programując konstrukcje wielokrotnego wyboru, używać instrukcji else-if. Należy wystrzegać się makroinstrukcji grających rolę funkcji. Treść i argumenty makroinstrukcji ujmować w nawiasy. Nadawać nazwy liczbom magicznym. Definiować liczby jako stałe. Używać stałych znakowych zamiast liczb całkowitych. Do obliczania rozmiarów instancji (zmiennych, typów) używać operatorów języka.
Style programowania 59 Komentować funkcje i dane globalne. Nie komentować złego kodu, lecz go poprawiać. Komentarz nie może być sprzeczny z kodem. Wyjaśniać, nie gmatwać! To samo rób wszędzie tak samo. Zwalniaj zasoby w tej samej warstwie, w której były przydzielone. Trzymaj się standardu.