User Tools

Site Tools


dydaktyka:cprog:2015:loops

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
dydaktyka:cprog:2015:loops [2015/10/29 09:28]
pkleczek [Zadanie 3]
— (current)
Line 1: Line 1:
-====== ​ Pętla "​while",​ formatowanie kodu, debuggowanie ====== 
- 
- 
- 
- 
-===== Cel laboratorium ===== 
- 
-  * Omówienie priorytetów operatorów. 
-  * Zapoznanie z pętlą ''​while''​ i ''​do-while''​. 
-  * Zasady formatowania kodu. 
-  * Umiejętność posługiwania się //​debuggerem//​. 
- 
-===== Priorytet operatorów ===== 
- 
-Priorytet operatorów oznacza to samo, co kolejność działań w matematyce -- operator o wyższym priorytecie zostanie wykonany najpierw, a gdy obok siebie stoją, to operacje są wykonywane od lewej do prawej (chyba, że sam operator działa inaczej, o czym za chwilę). 
- 
-Przykładowo -- w matematyce -- wyrażenie $(2+2 \cdot 2) \cdot 2$ zostanie obliczone w następujących krokach: 
-  - Obliczenie wartości w nawiasie: 
-    - Obliczenie $2 \cdot 2 = 4$ 
-    - Obliczenie $2 + 4 = 6$ 
-  - Obliczenie $6 \cdot 2 = 12$ 
- 
-Dlaczego tak? Ponieważ -- mówiąc językiem programisty -- nawiasy mają najwyższy priorytet, a mnożenie ma wyższy priorytet od dodawania. 
- 
-Zapoznaj się z [[http://​en.cppreference.com/​w/​c/​language/​operator_precedence|tabelą priorytetów operatorów]] w języku C (**uwaga:** wielu z zawartych w niej operatorów jeszcze nie znasz, lecz część z nich wprowadzimy sukcesywnie na kolejnych zajęciach). \\ 
-Zwróć uwagę na kolumnę //​Associativity//,​ czyli "​kierunek wiązania"​. Oznacza to, która strona operatora zostanie obliczona w pierwszej kolejności (np. //​Left-to-right//​ oznacza, że najpierw obliczona zostanie lewa strona operatora) i niejako "w którą stronę działa operator"​ -- przykładowo operator przypisania ''​=''​ przypisuje wartość stojącą po jego **prawej** stronie zmiennej stojącej po **lewej** stronie, zatem jego kierunek wiązania to **Right-to-Left**. 
- 
-Tak więc, można stwierdzić,​ że //każde wyrażenie w języku C ma pewną wartość, obliczoną zgodnie z priorytetami i kierunkami wiązania operatorów//​. 
- 
-:!: Nie musisz pamiętać całej tej terminologii,​ lecz **musisz kojarzyć** o co w tym wszystkim chodzi. 
- 
----- 
- 
-**Zadanie 1** \\ 
-Napisz program sprawdzający,​ czy dla zadanej przez użytkownika liczby $x$ zachodzi $4 < x < 6$. \\ 
-Przetestuj swój program dla $x = 5$. 
-===== Pętla "​while"​ ===== 
- 
-Pętla ''​while''​ wykonuje instrukcję dopóty, dopóki spełniony jest warunek testowy (tzn. wyrażenie podane jako warunek ma wartość niezerową). 
- 
-Ogólna postać: 
-<​code>​ 
-while (wyrażenie_testowe) 
-    instrukcja 
-</​code>​ 
- 
-Pętla ''​while''​ to //pętla z warunkiem wejścia//, co oznacza że warunek sprawdzany jest **przed** każdym jej obiegiem (także pierwszym). 
- 
-Zazwyczaj zechcesz gdzieś wewnątrz pętli zmieniać wartości zmiennych tak, aby warunek wejścia stał się fałszywy :) 
- 
----- 
- 
-**Przykład** \\ 
-Obliczanie silni za pomocą pętli ''​while''​ -- porównaj z [[http://​home.agh.edu.pl/​~pkleczek/​dokuwiki/​doku.php?​id=dydaktyka:​cprog:​2015:​conditionals#​petla_for|programem]] wykonującym to samo zadanie z użyciem pętli ''​for''​. 
-<code c> 
-#include <​stdio.h>​ 
- 
-int main() 
-{ 
-    int s, n, i; 
- 
-    printf("​Podaj liczbe naturalna n: "); 
-    scanf("​%d",​ &n); 
- 
-    s = 1; 
-    i = 1; 
- 
-    while (i <= n) { 
-        s *= i; 
-        i = i + 1; 
-    } 
- 
-    printf("​%d! = %d\n", n, s); 
- 
-    return 0; 
-} 
-</​code>​ 
- 
-Która pętla Twoim zdaniem lepiej nadaje się do tego zadania? 
- 
-Dobra praktyka programistyczna mówi: \\ 
-//Stosuj pętlę ''​for''​ tylko wtedy, gdy dokonujesz zarówno inicjalizacji,​ jak i aktualizacji. We wszystkich innych przypadkach lepiej (czytelniej) użyć pętli ''​while''​.//​ 
- 
----- 
- 
-**Zadanie 1** \\ 
-Napisz program obliczający wynik $n \cdot k$ dla zadanych liczb całkowitych $n$ i $k$. Użyj pętli ''​while''​. \\ 
-//​Wskazówka:​ $n \cdot k = \underbrace{n + n + \ldots + n}_{k \text{ razy}}$// 
- 
-===== Pętla "​do-while"​ ===== 
- 
-Pętla ''​do-while'',​ podobnie jak pętla ''​while''​ wykonuje instrukcję dopóki spełniony jest warunek testowy. 
- 
-Ogólna postać: 
-<​code>​ 
-do 
-    instrukcja 
-while (wyrażenie_testowe);​ 
-</​code>​ 
-:!: Zwróć uwagę na średnik występujący po ''​%%while (...)%%''​! 
- 
-Różnica między dwoma typami pętli ''​while''​ polega na tym, że ''​do-while''​ to //pętla z warunkiem wyjścia// -- oznacza to, że warunek sprawdzany jest **po** każdym obiegu pętli (a więc petla wykona się **co najmniej raz**). 
- 
----- 
- 
-**Przykład** 
-<code c> 
-#include <​stdio.h>​ 
- 
-int main(void) 
-{ 
-    int i = 0; 
- 
-    printf("​Poczatek petli \n\n"​);​ 
- 
-    do { 
-        printf("​Wartosc zmiennej '​i'​ wynosi %d \n", i); 
-        i = i + 1; 
-    } while (i < 5); 
- 
-    printf("​\nKoniec petli"​);​ 
- 
-    return 0; 
-} 
-</​code>​ 
- 
----- 
- 
-W praktyce programiści starają się unikać stosowania ''​do-while'',​ gdyż: 
-  * umieszczanie warunku na końcu pętli zmniejsza czytelność kodu, natomiast 
-  * bez trudu można tak zmienić kod, aby zastąpić pętlę ''​do-while''​ pętlą ''​while''​. 
- 
-Uogólnienie powyższej zasady brzmi: \\ 
-//Lepiej stosować pętle z warunkiem wejścia (''​while'',​ ''​for''​),​ a nie wyjścia (''​do-while''​).//​ (nbsp) [size=10](z tych samych powodów, co podane powyżej)[/​size] 
- 
----- 
- 
-**Zadanie 1** \\ 
-Napisz program, który prosi użytkownika o podanie liczby całkowitej większej od $0$. Program powinien zakończyć działanie dopiero wtedy, gdy użytkownik podał poprawną wartość. 
- 
-**Zadanie 2** \\ 
-Napisz program losujący liczbę z przedziału $[0;100]$ tak długo aż wylosuje liczbę z przedziału $[10;15]$. \\ 
-Do losowania liczb służy funkcja [[http://​www.cplusplus.com/​reference/​cstdlib/​rand/?​kw=rand|rand()]] z biblioteki //​stdlib.h//​. 
-===== Formatowanie kodu ===== 
- 
-Jedną z zasad tworzenia czytelnego kodu jest umiejętne stosowanie wcięć (//​indent//​),​ które oznaczają "​poziom zagłębienia"​ kodu. \\ 
-Choć kompilator C pomija znaki białe (a więc m.in. wcięcia i znaki nowej linii), to jednak dla człowieka taki kod byłby ciężki do odczytania. 
- 
-Zasada brzmi: 
-  * początek nowego bloku instrukcji oznacza zwiększenie ilości wcięć o jeden poziom 
-  * koniec bloku instrukcji oznacza zmniejszenie ilości wcięć o jeden poziom 
- 
-Zazwyczaj stosuje się wcięcie szerokości jednego tabulatora bądź czterech spacji. 
- 
-Przykład: 
-<code c> 
-int main () { 
---->if (1) { 
---->​--->​printf("​Hello"​);​ 
---->​--->​printf("​World!\n"​);​ 
---->} 
-} 
-</​code>​ 
- 
-:!: Kwestia formatowania to rzecz umowna -- istnieją różne szkoły formatowania,​ a programiści toczą o to nieustanne "​święte wojny"​. Najważniejsza zasada brzmi: **Stosuj reguły __konsekwentnie__!** 
- 
-==== Autoformatowanie kodu z użyciem IDE ==== 
- 
- 
-Całą tą "​czarną robotę"​ związaną z formatowaniem może za Ciebie [[https://​en.wikipedia.org/​wiki/​Integrated_development_environment|IDE]] (tu: CodeBlocks). 
- 
-Aby automatycznie sformatować kod, kliknij prawym przyciskiem myszy na oknie edytora tekstu i wybierz z menu kontekstowego opcję //Format use AStyle//. 
- 
-Aby zmienić ustawienia autoformatowania wejdź w //Settings -> Editor...// i z listy z ikonami po lewej wybierz //Source formatter//​. \\ 
-W przykładach na zajęciach stosuję następujące opcje formatowania:​ 
-  * zakładka //Style// 
-    * Bracket style: K&R 
-  * zakładka //​Indentation//​ 
-    * (bez zmian) 
-  * zakładka //​Formatting//​ 
-    * Pad empty lines around header blocks (e.g. '​if',​ '​while'​...) -- zaznaczone 
-    * Insert space padding around operators -- zaznaczone 
-    * (pozostałe opcje odznaczone) 
- 
-===== Debuggowanie ===== 
- 
-Zdarza się, że choć program nie zawiera błędów składniowych (czyli kompiluje się bez problemów i da się go uruchomić),​ to jednak nie działa zgodnie z oczekiwaniami. W takich sytuacjach do zdiagnozowania przyczyny problemu przydaje się narzędzie o nazwie //​debugger//​. 
- 
-**Debugger** (nazwa czasem tłumaczona na polski jako "​odpluskwiacz"​ :-)) służy do krokowego wykonania programu (czyli instrukcja po instrukcji),​ z możliwością podglądu stanu programu (a więc m.in. wartości zmiennych) po każdym kroku. 
- 
-:!: Debugger nie jest częścią języka -- to narzędzie dostarczane (zazwyczaj) w ramach zintegrowanego środowiska programistycznego. 
- 
-Podczas procesu debuggowania korzysta się z **//​breakpoint//​**-ów,​ które mówią debuggerowi tyle -- "​koniecznie zatrzymaj się tutaj"​. 
- 
-[size=10](Ciekawi Cię, skąd się wzięła nazwa //bug//? -- Przeczytaj w wolnej chwili [[https://​en.wikipedia.org/​wiki/​Software_bug#​Etymology|ten]] krótki fragment.)[/​size] 
- 
- 
- 
-==== Debuggowanie w CodeBlocks ==== 
- 
-Do nauki wykorzystaj poniższy kod: 
-<code c> 
-#include <​stdio.h>​ 
-#include <​stdlib.h>​ 
- 
-int main() 
-{ 
-    int i; 
-    int n = 2; 
- 
-    printf("​Zaczynamy...\n"​);​ 
- 
-    for (i = 1; i < 5; i++) { 
-        n = n * n; 
-    } 
- 
-    printf("​Wynik = %d\n", n); 
-} 
-</​code>​ 
- 
-(W razie problemów z uruchomieniem debuggera zaglądnij do [[http://​home.agh.edu.pl/​~pkleczek/​dokuwiki/​doku.php?​id=dydaktyka:​cprog:​faq#​dlaczego_debugger_nie_zatrzymuje_sie_na_breakpointach|FAQ]].) 
- 
-Debuggowanie krok po kroku: 
-  - Aby móc przystąpić do debuggowania,​ dodaj choć jeden breakpoint. W tym celu przejdź do linijki z pierwszą instrukcją ''​printf()''​ i wybierz //Debug -> Toggle breakpoint//​ -- po lewej stronie, koło numeru wiersza, pojawi się czerwona kropka (symbol breakpoint-u). 
-  - Wybierz //Debug -> Start/​Continue//​ -- uruchomiony zostanie proces debuggowania. 
-  - Aby zobaczyć podgląd zmiennych, wybierz //Debug -> Debugging windows -> Watches// 
-  - Przejdź program krok po kroku (//Debug -> Next line//), aż do jego zakończenia,​ i obserwuj zmiany wartości zmiennych oraz zawartości okna konsoli. 
- 
-W oknie //Watches// w pierwszej kolumnie możesz podać w wolnym polu u dołu dowolne poprawne wyrażenie -- jego wartość zostanie automatycznie obliczona zgodnie z bieżącym stanem programu. \\ Dodaj wyrażenie ''​x + 8 < 20''​ i ponownie prześledź zmianę wartości tego wyrażenia podczas kolejnych obiegów pętli. 
- 
-Czasem interesuje Cię podgląd stanu programu tylko w kilku określonych miejscach -- dodaj w nich breakpointy,​ a następnie przechodź pomiędzy nimi (czyli wykonuj automatycznie wszystkie instrukcje pomiędzy obecnym, a kolejnym breakpointem) za pomocą //Debug -> Start/​Continue//​. \\ 
-Dodaj drugi breakpoint przy drugim wywołaniu ''​printf()''​. Uruchom debuggowanie,​ a następnie ponownie wybierz //Debug -> Start/​Continue//​. 
- 
-:!: Pod kątem dalszych studiów na kierunku Inżynieria Biomedyczna zapamiętaj -- **MATLAB także posiada debugger**! :-D 
- 
-===== Zadania podsumowujące ===== 
- 
-==== Zadanie 1 ==== 
- 
-([size=10]poziom trudności:​[/​size] {{stars>​4/​4}}) 
- 
-Napisz program, który wypisze na ekran taki fragment: 
-<​code>​ 
-1 2 3 
-2 3 1 
-3 1 2 
-</​code>​ 
-Użyj pętli ''​for''​. 
- 
-//​Wskazówka 1: Pętle, podobnie jak instrukcje warunkowe, można zagnieżdżać. Pętla wewnętrzna wykonuje swój pełny zakres powtórzeń w każdym cyklu pętli zewnętrznej.//​ \\ 
-//​Wskazówka 2: Przydatny może być operator "​modulo"​...//​ 
-==== Zadanie 2 ==== 
- 
-([size=10]poziom trudności:​[/​size] {{stars>​2/​4}}) 
- 
-Napisz program, który dla zadanej liczby całkowitej obliczy sumę jej cyfr. \\ 
-Przykład: dla $196$ poprawnym wynikiem jest $1 + 9 + 6 = 16$ 
- 
-//​Wskazówka:​ Wykorzystaj własność [[dydaktyka:​cprog:​2015:​data_types#​arytmetyka_liczb_w_c_-_pulapki|dzielenia i obcięcia w języku C]].// 
- 
-==== Zadanie 3 ==== 
- 
-([size=10]poziom trudności:​[/​size] {{stars>​3/​4}}) 
- 
-Napisz program obliczający pierwiastek kwadratowy zadanej liczby [[https://​pl.wikipedia.org/​wiki/​Metody_obliczania_pierwiastka_kwadratowego#​Metoda_babilo.C5.84ska|metodą babilońską]] (krok 1-3). Przerwij obliczenia, gdy różnica między kolejnymi przybliżeniami jest mniejsza niż $10^{-4}$. 
- 
-//​Wskazówka:​ Jako pierwsze oszacowanie możesz przyjąć $\sqrt{S} \approx S$ ;-) // 
- 
-[size=10]Być może zastanawiasz się: //Po co ręcznie obliczać pierwiastek?​ Przecież można skorzystać z wbudowanej funkcji [[http://​www.cplusplus.com/​reference/​cmath/​sqrt/​|sqrt()]]! // \\ 
-Owszem, lecz jeśli nie potrzebujesz mega-dużej dokładności,​ to metodą babilońską uzyskasz wystarczająco dobry wynik o wiele, wiele szybciej.[/​size] 
  
dydaktyka/cprog/2015/loops.1446107324.txt.gz · Last modified: 2020/03/25 11:46 (external edit)