Podstawy programowania Podstawy C Sowa kluczowe we wszystkich
- Slides: 104
Podstawy programowania Podstawy C#
Słowa kluczowe – we wszystkich językach programowania wysokiego poziomu – zbiór słów zastrzeżonych, których nie można "przedefiniować", m. in. : • abstract, as, base, bool, break, byte, case, catch, char, class, const, continue, decimal, default, double, else, enum, event, false, float, foreach, if, int, interface, internal, long, namespace, new, null, object, operator, out, override, private, protected, public, readonly, ref, return, sbyte, short, sizeof, static, string, struct, switch, this, throw, true, try, typeof, uint, ulong, ushort, using, virtual, void, volatile, while
Słowa kluczowe – we wszystkich językach programowania wysokiego poziomu – zbiór słów zastrzeżonych, których nie można "przedefiniować", m. in. : • … • Łatwo rozpoznawalne: using System; namespace Pod. Pro. Lab 1 { class Program { Console. Read. Key(true); } }
Słowa kluczowe kontekstowe Słowa, które są lub nie są kluczowe, zależnie od kontekstu; Nie są zastrzeżone, można użyć np. do nazwania zmiennych: • add, alias, async, await, by, descending, dynamic, equals, from, get, global, group, into, join, let, nameof, on, orderby, partial, remove, select, set, value, var, when, where, yield
Nazwy Zasady formalne: • Może zawierać litery, cyfry oraz znak podkreślenia "_" (tzw. podłoga), można używać znaków diakrytycznych, • Małe i wielkie litery SĄ rozróżniane • Nie może zaczynać się od cyfry • Nie może być słowem kluczowym Int 32 gałąź_numer_3; // ok licznik, LICZNIK; // ok, 3 różne nazwy! 2 pi; // błąd! event; // błąd! Słowo kluczowe
Nazwy Zasady nieformalne: • Klasy, pola, metody, stałe – konwencja Pacal, nazwy klas i pól – rzeczowniki, metod – czasowniki: Dane. Wykresu (klasa – należy unikać nazw na "I") Kolor. Linii (pole) Zapisz. Dane (metoda) • Interfejsy – Pascal poprzedzone literą "I" ISortable • Zmienne lokalne i parametry funkcji – camel. Case: promień pole. Koła
Nazwy Zasady nieformalne: • Nazwy powinny być znaczące: p, k, pole. Koła, kolor. Linii Kod powinien być czytelny, kiedy do niego zajrzeć po kilku miesiącach albo dla innego programisty (tzw. samodokumentujący się) • Język angielski czy polski? Odpada argument z kaleczeniem języka polskiego => reguły zespołu lub indywidualne preferencje
Styl Środowisko formatuje wg reguł klasycznych: • Nawias "{" i "}" zawsze w nowej linii, "else" w nowej linii, wcięcia odpowiadające głębokości zagnieżdżenia • Automatyczne formatowanie – po zakończeniu pisania instrukcji (po wpisaniu "; " lub ostatniego "}"), o ile nie ma błędów; Nie ma re-formatowania po zmianach • Na żądanie (Edit > Advanced > Format Document) Np. dla takiego kodu… if (x>0) {for (i=0; i<3; i++) {z += t[i]; } } else {z = 0; }
Styl Środowisko formatuje wg reguł klasycznych: • Nawias "{" i "}" zawsze w nowej linii, "else" w nowej linii, wcięcia odpowiadające głębokości zagnieżdżenia: if (x > 0) { for (i = 0; i < 3; i++) { z += t[i]; } } else { z = 0; }
Styl Alternatywne reguły formatowania, np. : • Nawias "{" na końcu linii, "}" w nowej linii, "else" razem z "}" (bardziej zwarty): if (x > 0) { for (i = 0; i < 3; i++) { z += t[i]; } } else { z = 0; } - można ustawić w opcjach edytora
Styl Komentarze służą do dokumentowania kodu • Komentarz liniowy – od "//" do końca linii // Jedna linia wyjaśnienia kod… • Komentarz blokowy – od "/*" do "*/" /* Kilka linii wyjaśnienia */ kod…
Styl Komentarze służą do dokumentowania kodu • … • Sekwencja "///" powoduje wstawienie szablonu dokumentacji XML, który jest czytany przez intellisense /// <summary> /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> static Int 32 NWD(Int 32 a, Int 32 b) { }
CTS Wspólny system typów CTS (Common Type System) Obiekt Klasa Typy proste Interfejs Typy wyliczeniowe Tablica Struktury Typy referencyjne Typy wartościowe
CTS Typy wartościowe • Deklaracja deklarowany (tworzony) jest obiekt Int 32 x; x = 7; • Przypisanie obiekt jest kopiowany Int 32 a, b; a = 13; b = a; (są dwa obiekty Int 32, oba zawierają wartość 13)
CTS Typy referencyjne • Deklaracja deklarowana (tworzona) jest referencja, obiekt nie istnieje dopóki nie zostanie utworzony operatorem new Button b 1; b 1 = new Button(); • Przypisanie kopiowany jest nie obiekt, tylko referencja do niego Button b 2; b 2 = b 1; (jest jeden obiekt Button, obie referencje wskazują na niego)
Typy proste C# Typ wspólny i rzutowanie • Wszystkie mają wspólny typ bazowy "object" – zmienną każdego typu (w tym typu prostego) można przypisać do zmiennej typu object; Odwrotne przypisania wymaga rzutowania (konwersji typów): Int 32 x; object o; x = 13; o = x; x = (Int 32)o; // ok Double y; y = (Double)o; // błąd! (obiekt w "o" nie jest Double)
Typy proste C# Typy proste • Służą do przechowywania pojedynczych wartości logicznych, liczb, znaków, łańcuchów znaków • Wszystkie są strukturami BCL (Base Class Library), wspólne dla. NET; Struktury dostarczają wielu użytecznych metod i stałych, np. dla Int 32: – Int 32. Parse – metoda statyczna, konwertuje łańcuch na liczbę Int 32 – Int 32. Max. Value – stała, maksymalna wartość Int 32 – Int 32. To. String – metoda, konwertuje liczbę Int 32 na łańcuch • Mają aliasy w postaci słów kluczowych, np. – – Int 32 – int Single – float Double – double Boolean – bool (aliasy są zapożyczone z C/C++/Java)
Typy proste C# Typy proste • Wartości logiczne: – Boolean (bool) • Liczby całkowite: – – Byte (byte), SByte (sbyte) Int 16 (short), UInt 16 (ushort) Int 32 (int), UInt 32 (uint) Int 64 (long), UInt 64 (ulong) • Liczby zmiennoprzecinkowe – Single (float) – Double (double) – Decimal (decimal) • Znaki i łańcuchy znaków unicode (tzw. widestring) – Char (char) – String (string)
Typy proste C# Boolean • Wartości logiczne – true i false (są to słowa kluczowe); Do zmiennej Boolean można wstawić wyłącznie stałą (jw. ) albo rezultat operacji lub funkcji (metody), o ile jest typu Boolean niski. Indeks = indeks < 0. 25 D; Boolean sukces = Int 32. Try. Parse("100", out liczba); • Nie jest dopuszczalna konwersja z wartości liczbowych i odwrotnie (co jest typowe dla języków C/C++): Boolean test; test = (Boolean)1; // błąd! Int 32 number; number = (Int 32)true; // błąd! Obowiązuje również dla warunków, np. w instrukcji warunkowej Int 32 x = 7, y = 0; if (x) y = 2 * x; // błąd! (ale w C++ ok)
Typy proste C# Liczby całkowite: • Wyróżniamy 8 odmian; różnią się obecnością znaku oraz ilością zajmowanego w pamięci miejsca (1, 2, 4 i 8 bajtów, tj. 8, 16, 32 i 64 bity) a w konsekwencji zakresem wartości – – Byte (byte), SByte (sbyte) Int 16 (short), UInt 16 (ushort) Int 32 (int), UInt 32 (uint) Int 64 (long), UInt 64 (ulong)
Typy proste C# Liczby całkowite: • Zakres wartości wynosi od -2 n-1 do 2 n-1 -1 dla wersji ze znakiem oraz od 0 do 2 n-1 dla wersji bez znaku, np. : – – – SByte: -128. . 127, Byte 0. . 255 Int 16: -32. 768. . 32. 767, UInt 16: 0. . 65. 535 Int 32: -2. 147. 483. 648. . 2. 147. 483. 647 Uint 32: 0. . 4, 294, 967, 295 Int 64: ± 9, 223, 372, 036, 854, 775, 807 UInt 64 0. . 18, 446, 744, 073, 709, 551, 615 ± 32000, 0. . 65000 ± 2 miliardy 0. . 4 miliardy ± 9 e 18 0. . 18 e 18 Operacje arytmetyczne (np. "+") są wykonywane na Int 32 lub Int 64; po dodaniu dwóch zmiennych Int 16 trzeba dokonać jawnej konwersji wyniku – niepraktyczne, lepiej używać Int 32 Int 16 x=1, y=2; Console. Write. Line((x). Get. Type()); // x jest Int 16 Console. Write. Line((+x). Get. Type()); // +x to już Int 32 Console. Write. Line((x+y). Get. Type()); // x+y też Int 32
Typy proste C# Liczby zmiennoprzecinkowe • Single (float), 32 bity – Zakres wartości: 0, ± 1. 5 e− 45. . ± 3. 4 e 38, ±nieskończoność, nie-liczba – 7 cyfr znaczących • Double (double), 64 bity – Zakres wartości: 0, ± 5. 0 e− 324. . ± 1. 7 e 308 , ±nieskończoność, nie-liczba – 15 cyfr znaczących • Decimal (decimal), 128 bitów – Zakres wartości: 0, ± 1. 0 e-28. . ± 7. 9 e 28 – 28 cyfr znaczących Single i Double, po przekroczenia zakresu wartości podczas obliczeń, otrzymają wartość 0 lub ±∞, a ostatecznie Na. N (np. 0/0, 0*∞); Decimal bardziej tradycyjnie wygeneruje wyjątek programowy; Decimal ma mniejszy zakres wartości przy większej precyzji - do specyficznych zastosowań, np. obliczeń finansowych
Typy proste C# Znaki i łańcuchy • Do zapisu znaków używany jest Unicode (1 znak = 2 bajty, UInt 16), łańcuchy to sekwencje znaków – Char (char) – String (string) W Unicode mieszczą się znaki wszystkich "żywych" alfabetów Unicode eliminuje kłopoty ze znakami diakrytycznymi, używaniem stron kodowych itp. • Obie struktury są wyposażone w liczne metody – większość zadań związanych z przetwarzaniem znaków i łańcuchów jest gotowa • W przetwarzaniu znaków i łańcuchów są uwzględniane ustawienia regionalne (tzw. lokalizacja) – domyślnie wg ustawień systemu, ale można to zmienić
Typy proste C# Znaki i łańcuchy • … • W C# łańcuchy są traktowane w specjalny sposób – raz nadana wartość nie może być modyfikowana, zamiast tego tworzona jest nowa struktura (z nową wartością), a stara jest usuwana z pamięci przez GC, zupełnie inaczej niż pozostałe typy proste, w których po prostu zmienia się wartość istniejącej cały czas, tej samej zmiennej. Programy intensywnie przetwarzające łańcuch mogą z tego powodu działać wolniej – każda najmniejsza zmiana wartości łańcucha, choćby jednego jego znaku, powoduje utworzenie nowej struktury i pozbycie się starej. Aby tego uniknąć należy stosować obiekt String. Builder
Typy proste C# Konwersje typów prostych • Konwersja automatyczna jest możliwa, gdy nie ma ryzyka utraty wartości lub pogorszenia precyzji: Int 32 a; Int 16 b = 77; a = b; // ok, Int 32 <- Int 16 w przeciwnym razie jest błędem składniowym: b = a; Single y; y = 1. 25; // błąd: Int 16 <- Int 32 // błąd: Single <- Double • Można stosować konwersje wymuszone: b = (Int 16) a; Przy przekroczeniu zakresu wartości konwersja nie kończy się błędem, ale wynik może być niespodzianką
Typy proste C# Deklaracja zmiennych • Nazwa typu i lista nazw zmiennych, rozdzielona przecinkami: Int 32 a; Double x, y, z; • Można połączyć deklarację z nadaniem początkowej wartości (może to dotyczyć wszystkich lub tylko wybranych zmiennych): Int 32 a = 7; Double x = 13. 0, y = 0. 0, z; • Może istnieć tylko jedna zmienna o danej nazwie, ponowna deklaracja jest błędem: Int 32 n; Int 32 n = 7; // błąd – zmienna n już istnieje Double n; // też błąd
Typy proste C# Zasięg zmiennej • Zasięg zmiennej lokalnej jest ograniczony do bloku (od "{" do "}"), w którym została zadeklarowana. Tym blokiem jest zawsze funkcja, jednak może to być węższy blok: static void Main(string[] args) { Double x; // błąd – zmienna x już istnieje Int 32 n; } n = 7; // błąd – tu już nie ma zmiennej n { Double n; } } // ok. , inny blok, nowa zmienna n
Typy proste C# Stałe liczbowe (szerzej: literały) • Stałe liczbowe maja określony typ – 12 – Int 32 – 12. 0 albo 1. 2 e 1– Double – 0 x 12 – Int 32, notacja szesnastkowa (=18 dziesiętnie) • Stałe całkowite są niejawnie konwertowane na Byte i Int 16, o ile wartość na to pozwala: Byte b = 500; // błąd! • Aby jawnie określić typ należy stosować sufiksy: – – – U – uint (UInt 32) L – long (Int 64) F – float (Single) D – double (Double) M – decimal (Decimal) Single s = 1. 25; // błąd! 1. 25 F będzie ok Decimal d = 1. 25; // błąd! 1. 25 M będzie ok
Typy proste C# Stałe liczbowe (szerzej: literały) • Stałe znakowe są zapisywane w apostrofach, na kilka sposobów Char a, b, c, a = 'A'; b = 'u 0042'; c = 'x 0043'; d = (Char)68; e = 't'; d, e; // // "B", numer znaku Unicode "C", notacja szesnastkowa "D", konwersja z liczby całkowitej <tab>, tzw. sekwencja ucieczki • Stałe łańcuchowe są zapisywane w cudzysłowach: String s 1, s 2; s 1 = "Hellornworld"; s 2 = @"d: archiwumplik. zip"; Normalnie wykrywane są sekwencje ucieczki: "t" – tabulator, "r" – CR, "n" – LF, "\" – znak "" Użycie "@" wyłącza sekwencje ucieczki – przydatne, gdy w łąńcuchu występują znaki "", np. ścieżkach do plików
Typy proste C# Typy wyliczeniowe • Służą do definiowania zbioru dopuszczalnych wartości enum Color { Red, Green, Blue } Color color = Color. Red;
Typy proste C# Typy wyliczeniowe • Można by definiować stałe "luzem", ale grozi to pomyłkami. Dzięki ścisłej kontroli typów w C#, typy wyliczeniowe gwarantują używanie zawsze poprawnych wartości Np. kolory konsoli i aplikacji okienkowych są liczbami innego typu. Dzięki typom wyliczeniowym nie ma możliwości pomylenia ich: Console. Foreground. Color = Console. Color. Yellow; // ok Label 1. Fore. Color = Color. Yellow; // ok Console. Foreground. Color = Color. Yellow; // błąd // niezgodny typ, komunikat w oknie błędów głosi: // Cannot implicitly convert type 'System. Drawing. Color' // to 'System. Console. Color'
Operatory C# • Podstawowe (primary) x. y f(a) t[n] (lewe) x++ x-- new • Jednoargumentowe +x -x !x ~x (prawe) ++x --x (typ)x • Mnożenia i dodawania * + / - (lewe) % • Przesuwania bitów (lewe) << >> • Relacji i równości < <= > == != >= (lewe) is as • Bitowe i logiczne (lewe) & ^ | && || • Warunkowy (prawe) ? : • Przypisania i rozszerzone przypisania = *= /= %= += -= <<= >>= &= ^= |= (prawe)
Operatory C# • Hierarchia operatorów Określona dla danego języka programowania kolejność wykonywania operatorów w wyrażeniu Np. * jest wyżej w hierarchii niż +, więc w wyrażeniu y = a + b * c; najpierw będzie wykonane mnożenie Różne języki programowania mają różne hierarchie operatorów. O ile mnożenie jest we wszystkich językach przed dodawaniem, to operatory logiczne mogą być w hierarchii wyżej (np. Pascal) albo niżej (np. C/C++/Java/C#) niż arytmetyczne Kolejność wynikającą z hierarchii można zmieniać używając nawiasów, wyłącznie "(" i ")", które mogą być zagnieżdżone Y = ((a + b) / (c – d));
Operatory C# • Wiązanie operatorów Określona dla danego języka programowania kolejność wykonywania operatorów o tej samej hierarchii Większość operatorów ma wiązanie lewe (są wykonywane od lewej) y = a / b * c; // (a/b)*c; c w liczniku! Tylko operatory przypisania mają wiązanie prawe x = y = z = 7; Kolejność wynikającą z wiązania można zmieniać używając nawiasów, wyłącznie "(" i ")", które mogą być zagnieżdżone y = a / (b * c); // a/(b*c); c w mianowniku
Operatory C# • Operator dostępu: x. y Daje dostęp do metod, pól, właściwości; Wpisanie ". " aktywuje Intellisense – widoczność elementów jest zależna od kontekstu, środowisko pamięta też co ostatnio było używane
Operatory C# • Operatory zwiększania i zmniejszania Przyrostkowe operatory ++ oraz -- dostarczają rezultat PRZED zmianą wartości: Int 32 x = 0, y; y = x++; // y=0, x=1 • Operatory jednoargumentowe zwiększania i zmniejszania Przedrostkowe operatory ++ oraz -- dostarczają rezultat PO zmianie wartości: Int 32 x = 0, y; y = ++x; // y=1, x=1 Kolejność ++ oraz x sugeruje kolejność czynności: ++x najpierw zwiększa, potem zwraca x, x++ odwrotnie Operatory przyrostkowe i przedrostkowe mają inną hierarchię
Operatory C# • Operatory arytmetyczne (dwuargumentowe): mnożenia: * mnożenie, / dzielenie, % reszta z dzielenia dodawania: + Działają (na ogół) zgodnie z intuicyjnym rozumieniem; Działanie i wynik zależy od typów argumentów: jeżeli oba są całkowite, to działanie jest wykonywane jak dla liczb całkowitych, jeżeli chociaż jeden argument jest zmiennoprzecinkowy, to działanie też: Int 32 i = 3 / 4; // i = 0 Double d = 3. 0 / 4 D; // d = 0. 75 Double z = 3 / 4; // z = 0. 0 Dla typów całkowitych wynik jest przynajmniej Int 32, nawet jeżeli oba argumenty są Byte lub Int 16 Reszta z dzielenia działa też dla liczb zmiennoprzecinkowych (inaczej niż w C/C++) Dla typu String jest zdefiniowany operator +, oznacza konkatenację
Operatory C# • Operatory relacji i równości: relacji: <, <=, >, >= równości: == != Ich sens jest inny niż w matematyce: nie są stwierdzeniem, lecz pytaniem: Boolean czy. Większe = x > y; Boolean czy. Nierówne = x != y; Rezultat jest true (jeżeli relacja jest prawdziwa) albo false (jeżeli nie)
Operatory C# • Operatory logiczne: negacji (not): ! koniunkcja (and): && alterantywa (or): || Służą do budowania bardziej złożonych wyrażeń logicznych; Należy pamiętać o hierarchii i wiązaniu, a w razie potrzeby stosować nawiasy Boolean warunek = x > y && !(x > 13 || y < 7); Warto zwrócić uwagę na hierarchię – operatory && i || są nisko w hierarchii (za operatorami arytmetycznymi, relacji i równości), więc na ogół nie potrzeba nawiasów, za to "!" jest znacznie wyżej i nawiasy są zwykle potrzebne: W 1 = x > 0 && y > 0; // (x>0) && (y>0) W 2 = x < y + 2 || x == y; // (x<(y+2)) || (x==y) W 3 = !(x < y); // bez () jest błąd, (!x) < y
Operatory C# • Operatory logiczne: negacji (not): ! Operator negacji jest rzadko używany w wyrażeniach – zawsze można zmienić znak relacji, np. !(x>0) odpowiada x<=0, albo skorzystać z praw De Morgana, np. !(x>0 && y>0) odpowiada x<=0 || y<=0 Operatora negacji używa się w odniesieniu do wartości zwracanych przez funkcje lub właściwości obiektów – ponieważ nie można ani nie warto zmieniać ich działania, np. : while (!stream. End. Of. Stream) { x = stream. Read. Line(); // …
Operatory C# • Operatory logiczne: koniunkcja (and): &&, alterantywa (or): || Program na ogół optymalizuje obliczanie koniunkcji i alternatywy: jeżeli w wyrażeniu (a && b) czynnik a ma wartość false, to całość będzie false, niezależnie od wartości b – zatem b nie jest wyznaczane Np. poniżej jeżeli Link. Is. Open ma wartość false, to funkcja Read. Data nie zostanie wywołana: Read. OK = Link. Is. Open && Link. Read. Data(out buffer); Czasami ta właściwość jest wykorzystywana dla skrócenia kodu, ponieważ odpowiednio użyta zastępuje instrukcję if-else: if (!Link. Is. Open) Read. OK = false; else Read. OK = Link. Read. Data(out buffer);
Operatory C# • Operatory logiczne: koniunkcja (and): &&, alterantywa (or): || Podobnie jest optymalizowane wyznaczanie operatora || Przykład: if (Link. Is. Open || Link. Reconnect()) { Link. Read. Data(out buffer); } else { Console. Write. Line(" ? ? ? "); } Kiedy funkcja Reconnect zostanie wykonana, a kiedy nie? Jaki komunikat powinien się pojawić w miejsce "? ? ? " ?
Operatory C# • Operatory przypisania: zwykły: = rozszerzone: *=, +=, … Operator przypisania nie jest deklaratywny, jest poleceniem wykonywanym w określonym momencie Int 32 a = 7, b = 13, w; w = a + b; // w=20 a = 13; // w=20 Rozszerzone operatory przypisania są tylko skróceniem zapisu: w += 1; // dokładnie jak w = w + 1; w *= b; // dokładnie jak w = w * b; Należy pamiętać, że wiązanie jest prawe: x = y = z = 7; // x=7 x += y *= z -= 3; // z=4, y=28, x=35
Operatory C# • Operatory przypisania: Wszystkie operatory przypisania mają skutek (wstawienie wartości do zmiennej) oraz rezultat (wstawiona wartość), np. rezultatem y=3 jest wartość 3 (ważne: wartość, a nie zmienna lub referencja do niej) Dzięki temu poniższy kod jest poprawny: x = y = 3; Z uwagi na wiązanie prawe operatora = jest to równoważne temu: X = (y = 3); zatem do x jest wstawiany rezultat operacji y=3, czyli 3
Operatory C# • Operatory przypisania: Fakt, że operator = posiada rezultat, pozwala robić np. takie konstrukcje: X = 2 * (y = 3); // ok, y=3, x=6 To działa, ale kod jest mało czytelny, co może prowadzić do błędów, dlatego takie użycie operatora = nie jest zalecane. Ważne są tu nawiasy, ponieważ operator "=" jest najniżej w hierarchii, zaś bez nawiasów będzie błąd składniowy: X = 2 * y = 3; // błąd, (2*y) = 3, (2*y) nie jest zmienną Czasami dopuszcza się takie nadużycie, np. w pętli while: while ("+-*". Index. Of( key = Console. Read. Key(true). Key. Char ) < 0); Wplecenie przypisania do wywołania funkcji jest konieczne, ponieważ w warunku pętli można użyć tylko jednego wyrażenia. Przy okazji – rzadki przykład instrukcji pustej, która nie jest błędem
Operatory C# • Operatory binarne: negacja ~ (NOT), koniunkcja & (AND), alternatywa | (OR), ekskluzja ^ (XOR) Operatory te, w odróżnieniu od operatorów logicznych, są wykonywane na zmiennych całkowitych, bit po bicie, za wyjątkiem bitu znaku, który jest pomijany (o ile występuje). Np. dla koniunkcji (AND), bit wyniku jest równy 1 jeżeli bity obu argumentów na tej samej pozycji są równe 1 Int 32 a = 5, b = 3, c; c = a & b; a: 00000101 b: 00000011 c: 00000001
Operatory C# • Operatory binarne: przesuwania bitów << oraz >> Przesunięcie jest wykonywane nierekursywnie (bity wychodzące poza zmienną NIE są wstawiane na drugim jej końcu), o liczbę pozycji wskazaną drugim argumentem, ale z wyłączeniem bitu znaku: Int 32 a = -15, b; b = a >> 3; a: 100000000 b = a << 10; a: 10000000 b: 100000000 00001111 00000001 // trzy "1" wcięło 00001111 00111100 0000 Przesunięcie w lewo o 1 bit odpowiada mnożeniu przez 2, zaś przesunięcie w prawo – dzieleniu przez 2
Operatory C# • Operator warunkowy ? : W pewnym sensie specyficzna postać instrukcji warunkowej (if), króra może być użyta w wyrażeniach; jest też nazywany "inline if": warunek ? wyrażenie 1 : wyrażenie 2 Działanie: obliczana jest wartość warunku, następnie jeżeli warunek jest spełniony, to jako rezultat całego wyrażenia obliczana jest wartość wyrażenia 1, w przeciwnym wypadku wartość wyrażenia 2 Rozsądnie używany upraszcza i skraca zapis kodu, np. : if (x == 0) y = 1. 0; else y = Math. Sin(x) / x; można skrócić do: y = x == 0? 1. 0 : Math. Sin(x) / x;
Operatory C# • Operator warunkowy ? : Ograniczenia – Warunek musi dawać rezultat typu logicznego (Boolean), oba następne wyrażenie muszą być tego samego typu lub musi istnieć automatyczna konwersja między nimi – Może być użyty tylko jako część przypisania albo argument funkcji: // błędy – operator ? : użyty poza przypisaniem x > 0? Console. Write(">") : Console. Write("<="); x == 0? y = 1. 0 : y = Math. Sin(x) / x; // poprawne użycie operatora ? : Console. Write(x>0? ">" : "<="); // ? : jako argument y = x == 0? 1. 0 : Math. Sin(x) / x; // ? : w przypisaniu
Aplikacje konsolowe C# Aplikacje konsolowe • Środowisko VS umożliwia tworzenie aplikacji konsolowych - uruchamianych w klasycznym, czarnym oknie konsoli • Kreator VS tworzy projekt zawierający: - włączenie typowych bibliotek - przestrzeń nazw (można w niej umieszczać własne klasy) - klasę Program - statyczną metodę Main
Aplikacje konsolowe C# Funkcja główna programu • Każdy program musi zawierać funkcję główną (jak w C++); wykonanie programu polega na wykonaniu funkcji głównej.
Aplikacje konsolowe C# Przydatne klasy C# • Math - klasa definiująca statyczne metody matematyczne, jak pierwiastek, potęga, logarytm, sinus itd. itp Double Sqrt (Double x); Double Pow (Double b, Double e); - oraz dwie stałe: liczby Π oraz e public const Double PI = 3. 14159265358979; public const Double e = 2. 71828459045;
Aplikacje konsolowe C# Przydatne klasy C# • Convert Klasa definiująca konwersje miedzy różnymi typami prostymi: Int 16 i 16; Int 32 i 32 = 13; i 16 = Convert. To. Int 16(i 32); // zamiast i 16 = (Int 16)i 32 oraz konwersje z i na typ String ln; Int 32 i 32; ln = Console. Read. Line(); i 32 = Convert. To. Int 32(ln); // zamiast Int 32. Parse(ln); albo krócej Int 32 i 32; i 32 = Convert. To. Int 32(Console. Read. Line());
Aplikacje konsolowe C# Przydatne klasy C# • Console - klasa definiująca szereg statycznych metod do obsługi konsoli (odpowiednik strumieni cin oraz cout w C++) - najważniejsze metody: void Write. Line (String line); String Read. Line (); Console. Key. Info Read. Key (Boolean no. Echo);
Aplikacje konsolowe C# Metody klasy Console • Write. Line – wyświetla tekst i przechodzi do nowej linii - wyświetlenie łańcucha znaków Console. Write. Line("Hello"); - wyświetlenie wartości zmiennej Console. Write. Line(x. To. String()); Console. Write. Line(x); - wyświetlenie kilku informacji Console. Write. Line("Wynik = " + x); Console. Write. Line("Suma {0} i {1} to {2}", a, b, s);
Aplikacje konsolowe C# Metody klasy Console • Read. Line – wczytuje tekst wpisany z klawiatury (do naciśnięcia <Enter>) - wczytanie łańcucha znaków i konwersja na liczbę String ln; Double x; ln = Console. Read. Line (); x = Double. Parse(ln); - jw. , ale z wykrywaniem błędów Boolean ok; ok = Double. Try. Parse(ln, out x);
Aplikacje konsolowe C# Przykład aplikacji konsolowej C#
Instrukcje C# • • • Instrukcja Instrukcja Instrukcje wyrażeniowa pusta blokowa warunkowa (if oraz if-else) wyboru (switch) iteracyjne (for, while, do-while, foreach)
Instrukcje C# • Instrukcja wyrażeniowa: wyrażenie; Wyrażenie (kombinacja literałów, zmiennych, wywołań funkcji oraz operatorów) zakończone średnikiem, np. : promień++; pole = 2 * Math. PI * Math. Pow(promień, 2. 0); Console. Write. Line("Pole wynosi {0}", pole); Nie każde wyrażenie może stać się instrukcją – jedynie przypisanie, inkrementacja, dekrementacja, wywołanie funkcji oraz operator new
Instrukcje C# • Instrukcja pusta: ; Stosuje się tam, gdzie składnia języka wymaga podania instrukcji, a nic konkretnego nie ma być zrobione. Instrukcja pusta przydaje się bardzo rzadko, a jej użycie w instrukcjach warunkowych i iteracyjnych najczęściej jest błędem, np. : if (delta<0); Console. Write. Line("Brak pierwiastków"); Średnik po warunku tworzy instrukcję pustą (która jest lub nie jest wykonywana, zależnie od wyniku sprawdzenia warunku), natomiast wydruk jest wykonywany zawsze, ponieważ w tej sytuacji NIE JEST częścią instrukcji warunkowej.
Instrukcje C# • Instrukcja blokowa { //dowolna liczba instrukcji } Stosuje się wtedy, gdy składnia pozwala na użycie tylko jednej instrukcji, a trzeba użyć większej ich liczby. Przykład: for (i=1; i<=10; i++) { k = i*i; Console. Write. Line("kwadrat {0} to {1}", i, k); } Intencją programisty jest, aby każda iteracja składała się z dwóch instrukcji (obliczenia i wydruk). Składnia for pozwala na użycie tylko jednej instrukcji, zatem konieczne jest użycie instrukcji grupującej.
Instrukcje C# • Instrukcja warunkowa if if (warunek) instrukcja Program oblicza wartość wyrażenia podanego jako "warunek" (musi to być wyrażenie dające rezultat typu Boolean). Jeżeli warunek jest spełniony (wartość logiczna true), program wykonuje instrukcję, w przeciwnym wypadku instrukcja jest pomijana if (a != b) Console. Write. Line("a i b są rózne”);
Instrukcje C# • Instrukcja warunkowa if -else if (warunek) instrukcja_1 else instrukcja_2 Program oblicza wartość wyrażenia podanego jako "warunek" (musi to być wyrażenie dające rezultat typu Boolean). Jeżeli warunek jest spełniony (wartość logiczna true), wykonywana jest tylko instrukcja_1, w przeciwnym wypadku wykonywana jest tylko instrukcja_2 if (x != 0) y = sin(x)/x; else y = 1;
Instrukcje C# • Instrukcja wyboru switch-case Można ją traktować jako uogólnienie instrukcji warunkowej if-else O ile instrukcja warunkowa daje dwa warianty działania (dla dwóch możliwych wartości logicznych), to kluczem instrukcji wyboru może być dowolny typ prosty całkowity, znakowy, łańcuch znaków albo typ wyliczeniowy, więc możliwych jest wiele opcji W przeciwieństwie do C/C++, kluczem instrukcji wyboru może być także łańcuch znaków
Instrukcje C# • Instrukcja wyboru switch-case switch (klucz) { case etykieta 1: instrukcje break; case etykieta 2: instrukcje break; default: instrukcje break; } Klucz – wyrażenie dające rezultat typu całkowitego, znakowego, łańcuch znaków albo typu wyliczeniowego Etykieta – literał typu zgodnego z typem klucza
Instrukcje C# • Instrukcja wyboru switch-case Zasady i ograniczenia: – Typy etykiet muszą być zgodne z typem klucza – Etykiety muszą być wartościami (literałami lub stałymi), Wartości etykiet nie mogą się powtarzać; – Sekcja "default" jest opcjonalna, może wystąpić co najwyżej raz – Każda sekcja case MUSI być zakończona instrukcją break – Kilka etykiet może mieć wspólny blok kodu switch (n) { case 1: case 7: // kod wspólny dla 1 i 7 break; // itd. .
Instrukcje C# • Instrukcja wyboru switch-case command = Console. Read. Line(); switch (command) { case "login": User. Login(); break; case "exit": case "bye": Disconnect(); break; default: Console. Write. Line("Unknown command"); break; }
Instrukcje C# • Instrukcja iteracyjna for Instrukcja iteracyjna z licznikiem, dobrze znana już ze starszych języków programowania – powinna być stosowana przede wszystkim tam, gdzie Z GÓRY wiadomo ile dokładnie razy należy powtórzyć czynność – np. obliczenie silni z 7, wydrukowanie tablicy 100 liczb itp. W językach C/C++ instrukcja for zyskała dużą elastyczność, np. licznik pętli nie musi być całkowity (w językach Basic i Pascal musi)
Instrukcje C# • Instrukcja iteracyjna for (inicjalizacja; warunek; inkrementacja) instrukcja Program wykonuje wyrażenie inicjalizacji, następnie oblicza wartość wyrażenia podanego jako "warunek" (musi to być wyrażenie dające rezultat typu Boolean). Jeżeli warunek jest spełniony (wartość logiczna true), program wykonuje instrukcję oraz inkrementację, po czym czynności SĄ POWTARZANE, począwszy od wyznaczenia warunku; Jeżeli warunek nie jest spełniony, to następuje wyjście z pętli. We wszystkich instrukcjach iteracyjnych (for, while, do-while) "warunek" jest warunkiem pozostania w pętli, a nie wyjścia z niej.
Instrukcje C# • Instrukcja iteracyjna for (inicjalizacja; warunek; inkrementacja) instrukcja inicjalizacja false warunek true instrukcja inkrementacja
Instrukcje C# • Instrukcja iteracyjna for, przykłady // klasyczna iteracja for (i = 1; i <= 10; i++) Console. Write. Line(i); //liczenie wstecz – zmienia się też warunek (na ">")! for (i = 77; i > 0; i -= 7) Console. Write. Line(i); // licznik niecałkowity for (Double d = 0. 2; d <= 2. 8; d += 0. 15) Console. Write. Line(d); // formalnie poprawna, zawiesza program for (; ; ) ;
Instrukcje C# • Instrukcja iteracyjna while Instrukcja iteracyjna z warunkiem – powinna być stosowana przede wszystkim tam, gdzie nie wiadomo ile dokładnie razy należy powtórzyć czynność, natomiast sprawdzenie, czynność ma być powtarzana, powinna być zrobiona za każdym razem PRZED tą czynnością. Klasycznym przykładem while jest odczyt pliku tekstowego: nie wiadomo ile linii zawiera plik (więc nie for), ale przed próbą odczytu można sprawdzić, czy program osiągnął koniec pliku: while (NIE koniec pliku) { linia = plik. Czytaj. Linię(); // użycie odczytanej linii }
Instrukcje C# • Instrukcja iteracyjna while (warunek) instrukcja Program oblicza wartość wyrażenia podanego jako "warunek" (musi to być wyrażenie dające rezultat typu Boolean). Jeżeli warunek jest spełniony (wartość logiczna true), program wykonuje instrukcję, po czym czynności SĄ POWTARZANE; Jeżeli warunek nie jest spełniony, to następuje wyjście z pętli. Jeżeli warunek od początku nie jest spełniony, to instrukcja nie jest wykonana nawet raz
Instrukcje C# • Instrukcja iteracyjna while (warunek) instrukcja false warunek true instrukcja
Instrukcje C# • Instrukcja iteracyjna while, przykłady // kopiowanie pliku na ekran String line; Stream. Reader plik = new Stream. Reader(@"C: plik. txt"); while (!plik. End. Of. Stream) { line = plik. Read. Line(); Console. Write. Line(line); } // formalnie poprawna, chociaż zawiesza program while (true) ;
Instrukcje C# • Instrukcja iteracyjna do-while Instrukcja iteracyjna z warunkiem – powinna być stosowana tam, gdzie nie wiadomo ile dokładnie razy należy powtórzyć czynność, natomiast sprawdzenie czynność ma być nadal powtarzana może być zrobiona dopiero PO tej czynności. Klasycznym przykładem do-while są iteracyjne obliczenia, których powtarzanie zwiększa dokładność wyniku, zaś oceny tej dokładności można dokonać dopiero PO wykonaniu obliczeń, np. rozwiązywanie równań nieliniowych metodą Newtona: do { x = Dokładniejsze. Rozwiązanie (x); e = Szacunkowy. Błąd (x); } while (e > Dopuszczalny. Błąd);
Instrukcje C# • Instrukcja iteracyjna while do { instrukcja } while (warunek); Program wykonuje instrukcję , a następnie oblicza wartość wyrażenia podanego jako "warunek" (musi to być wyrażenie dające rezultat typu Boolean). Jeżeli warunek jest spełniony (wartość logiczna true), to czynności SĄ POWTARZANE; Jeżeli warunek nie jest spełniony, to następuje wyjście z pętli. Instrukcja zostanie wykonana przynajmniej raz
Instrukcje C# • Instrukcja iteracyjna while do { instrukcja } while (warunek); instrukcja true warunek false
Instrukcje C# • Instrukcja iteracyjna do-while, przykłady // obliczanie przybliżonej wartości pierwiastka Double x = 4. 0, px = 4. 0, e; do { px = 0. 5 * (px + x / px); e = (px * px - x) / x; } while (e > 0. 001);
Instrukcje C# • Instrukcje break i continue Służą do kontrolowania instrukcji iteracyjnych: - continue przerywa bieżącą iterację, ale pętla jest dalej wykonywana - break natychmiast kończy pętlę Są używane ZAWSZE w powiązaniu z instrukcją warunkową (inaczej to, co jest za nimi, nigdy nie będzie wykonane) // pominięcie iteracji dla y<0 for (x = 0; x <= 10. 0; x += 0. 01) { y = … // obliczenia if (y < 0) continue; z = … // obliczenia }
Instrukcje C# • Instrukcje break i continue W nietypowych sytuacjach (np. kiedy sytuacja nie pozwala na użycie pętli while lub do-while), stosuję się pętlę "nieskończoną", z której wyjście jest możliwe tylko przez instrukcję break. while (true) { // instrukcje if (warunek) break; // instrukcje }
Instrukcje C# • Instrukcje break i continue Klasyczny przykład pętli "nieskończonej" z break – NWD Euklidesa dzielna = …; dzielnik = …; while (true) { reszta = dzielna % dzielnik if (reszta == 0) break; dzielna = dzielnik; dzielnik = reszta; } NWD = dzielnik;
Instrukcje C# • Przykład łączący różne instrukcje – aplikacja konsolowa realizujące wielokrotnie działania, zależnie od wyboru użytkownika; Char key; Console. Write. Line("Naciśnij + (? ? ? ), - (? ? ? ) albo * (koniec)"); while (true) { while ("+-*". Index. Of(key = Console. Read. Key(true). Key. Char) < 0); if (key == '*') break; switch (key) { case '+': Console. Write. Line("Działania dla +"); break; case '-': Console. Write. Line("Działania dla -"); break; } }
Wyjątki programowe Wyjątek programowy to rodzaj sytuacji nadzwyczajnej, np. błędu, z którym program nie potrafi sobie poradzić, którego obsłużenie jest oddane "wyższym warstwom" programu • Przykład: jeżeli funkcja Int 32. Parse otrzyma do przetworzenia ciąg znaków, który nie jest liczbą całkowitą, to wygeneruje wyjątek; Funkcja Parse nie może naprawić błędu, nie powinna też decydować jak zareagować na błąd (to należy do "wyższej warstwy" programu) • Jeżeli wyjątek nie zostanie obsłużony, to program zostanie zatrzymany Do obsługi wyjątków służą instrukcje: • throw – rzucanie wyjątku • try-catch – obsługa wyjątku • try-finally – czyszczenie po wystąpieniu wyjątku
Tablice C# Tablica to indeksowany zbiór elementów • Tablica jest typem referencyjnym (deklaracja tworzy tylko referencję, sama tablica musi być utworzona oddzielnie, najprościej operatorem new) • Wszystkie elementy tablicy są tego samego typu • Dostęp do elementów tablicy daje operator indeksowania [] (Ważne: indeks zaczyna się zawsze od wartości 0, a nie 1) • Tablice mogą być jedno- lub wielowymiarowe • Można tworzyć tablice tablic (jest to coś innego, niż tablica wielowymiarowa)
Tablice C# • Deklaracja tablicy Można zadeklarować tablicę elementów dowolnego typu (wartościowego lub referencyjnego), dopisując "[]" po typie: Int 32[] t 1; Button[] t 2; // tablica liczb Int 32 // tablica referencji przycisków Użycie "[]" po nazwie typu deklaruje tablicę jednowymiarową, użycie "[ , ]" dwuwymiarową, "[ , , ]" trzywymiarową itd. Int 32[ , ] t 3; // tablica dwuwymiarowa
Tablice C# • Deklaracja tablicy Można połączyć deklarację tablicy z jej utworzeniem i nadaniem wartości – wówczas rozmiar tablicy wynika z inicjalizatora. Inicjalizator tablicy to lista elementów, zapisana w nawiasach klamrowych i oddzielonych przecinkami: { p 0, p 1, p 2, … pk-1 } Jeżeli tablica jest wielowymiarowa, to konstrukcja ta musi zostać zagnieżdżona, np. w tablicy trójwymiarowej każde p jest tablicą elementów q, a każde q jest tablicą elementów r: { p 0, p 1, p 2, … pk-1 } {{q 0, …ql-1}, … {q 0, …ql-1}} {{{r 0, …rm-1}, …{r 0, …rm-1}}, … {{r 0, …rm-1}, …{r 0, …rm-1}}}
Tablice C# • Deklaracja tablicy Przykłady: // tablica jednowymiarowa 4 el. Int 32[] t 1 = { 1, 2, 3, 4 }; // tablica dwuwymiarowa 2 x 3 el. Int 32[, ] t 2 = { { 1, 2, 3 }, { 4, 5, 6 } }; // tablica Int 32[, , ] { { {1, 2, { {3, 4, trójwymiarowa 2 x 3 x 4 el. t 3 = 3, 4}, {5, 6, 7, 8}, {9, 0, 1, 2} } 5, 6}, {7, 8, 9, 0}, {1, 2, 3, 4} } };
Tablice C# • Utworzenie tablicy W celu utworzenia tablicy należy użyć operatora new, podając rozmiar tablicy: Int 32[] t 1; t 1 = new Int 32[5]; // deklaracja tablicy // utworzenie tablicy Deklarację i utworzenie tablicy można połączyć: Double[] t 2 = new Double[3]; Int 32[, ] t 3 = new Int 32[3, 5]; Można też połączyć utworzenie tablicy z nadaniem wartości; Liczba elementów musi być równa rozmiarowi Int 32[] t 4 = new Int 32[3] {1, 2, 3}; Int 32[] t 5 = new Int 32[3] {1, 2}; // ok // błąd!
Tablice C# • Utworzenie tablicy Rozmiar tablicy może być stałą całkowitą, ale też zmienną lub dowolnym wyrażeniem o rezultacie całkowitym: Int 32[] t 1, t 2, t 3; Int 32 r = 7; t 1 = new Int 32[7]; t 2 = new Int 32[r]; t 3 = new Int 32[2 * r + 1]; To ważne – rozmiar nie musi być znany w czasie kompilacji, można utworzyć tablicę o rozmiarze zależnym od wykonania programu, np. podanym przez użytkownika
Tablice C# • Wartości domyślne elementów Podczas tworzenia tablicy, jej wszystkie elementy są inicjalizowane tzw. wartością domyślną: – – – 0 lub 0. 0 dla typów prostych liczbowych, false dla typu Boolean '