background image

Pozostałe instrukcje sterujące 

  

background image

Przegląd zagadnień 

 

 

W module tym poznamy pozostałe instrukcje sterujące. Zostanie omówiona 
instrukcja wielokrotnego wyboru switch oraz instrukcje skoku. 
Zaprezentowany zostanie też pewien szablon programu. 

Po skończeniu tego modułu studenci powinni umieć wykorzystywać 
następujące instrukcje: 

 

switch 

 

goto 

 

break 

 

continue 

background image

Instrukcja wyboru switch 

 

 

Przy omawianiu instrukcji wyboru if zostało wspomniane o wyborze 
wielowariantowym. Jako wybór wielowariantowy bardziej od instrukcji if, 
nadaje się instrukcja switch. Ogólna postać instrukcji switch jest 
następująca: 

switch(wyrazenie)  

//nie ma średnika 


 

case wartoscA: instrA1; 

 

 

 

   ...; 

 

 

 

   instrAn; 

 

 

 

   break; 

 

... 

 

case wartoscN: instrN1; 

 

 

 

   ...; 

 

 

 

   instrNn; 

 

 

 

   break; 

 

default :     instr1; 

 

 

 

   ...; 

 

 

 

   instrn; 

 

 

 

   break; 

Wartość wyrażenia wyrazenie musi być typu całkowitego (sbyte, 
byte, short, ushort, int, uint, long, ulong, char) lub 
dowolnego typu wyliczeniowego lub typu string lub typu, z którego istnieje 
konwersja niejawna do jednego z podanych wcześniej typów. Wartości stojące 
obok słowa case (wartoscA ... wartoscN) muszą być znane w czasie 
kompilacji, czyli mogą być to literały lub stałe nazwane .Wartości te nie mogą 

background image

się powtarzać. Typ wartości stojących obok słowa case musi być zgodny z 
typem wyrażenia wyrazenie. 

Działanie instrukcji switch można przedstawić w kilku krokach: 

1.  Obliczana jest wartość wyrażenia wyrazenie. 

2.  Jeżeli któraś wartość stojąca obok słowa case jest równa obliczonej 

wartości, to wykonywane są instrukcje danego bloku case. Po 
osiągnięciu instrukcji break następuje wyjście z bloku instrukcji 
switch. 

3.  Jeżeli żadna wartość stojąca obok słowa case, nie odpowiada 

obliczonej wartości wyrażenia wyrazenie, wykonywane są 
instrukcje bloku default. Po osiągnięciu instrukcji break następuje 
wyjście z bloku instrukcji switch. 

4.  Jeżeli żadna wartość stojąca obok słowa case, nie odpowiada 

obliczonej wartości wyrażenia wyrazenie i w bloku instrukcji 
switch nie ma instrukcji default, to następuje wyjście z bloku 
instrukcji switch. 

Blok default może wystąpić w bloku instrukcji switch najwyżej jeden 
raz. 

Jeżeli chcemy, aby dane instrukcje były wykonywane dla kilku wartości 
wyrażenia wyrazenie, należy postąpić jak w poniższym przykładzie, który 
oblicza liczbę dni w miesiącu, nie uwzględniając lat przestępnych. Zmienna 
miesiac zawiera numer miesiąca w roku. 

int liczbaDni = 0; 
switch(miesiac) 

   case 2 : liczbaDni = 28; 
            break; 
   case 4 : 
   case 6 : 
   case 9 : 
   case 11 : liczbaDni = 30; 
             break; 
   default : liczbaDni = 31; 
             break; 

Trzeba pamiętać, że jeśli w bloku case lub default występuje jakaś 
instrukcja, to przed rozpoczęciem nowego bloku case, defaut lub nawiasem 
klamrowym zamykającym blok instrukcji switch, musi wystąpić instrukcja 
skoku: break, goto, throw oraz return. Instrukcja goto zostanie 
omówiona w dalszej części tego rozdziału. Brak instrukcji skoku jest nazywany 
błędem przejścia (no fall through rule). Wyjątkiem od tej reguły jest sytuacja, 
gdy po case występuje pętla nieskończona. Reguła ta różni język C# np. od 
języków C/C++. Pozwolenie na przejście między blokami case było 
przyczyną licznych błędów logicznych w programach napisanych w C/C++. 
Poniższy kod spowoduje więc błąd kompilatora. 

switch(c) 

  case 'a': instrA1; 

//brak instrukcji skoku 

background image

  case 'A': instrukcjaA1; 
            instrukcjaA2; 
            ... 
            break; 

  case 'b': instrB1;   //brak instrukcji skoku 
  case 'B': instrukcjaB1; 
            instrukcjaB2; 
            ... 
            break; 
  default: instrukacja1;  

//brak instrukcji skoku 

 

Rozwiązanie problemu, gdy jest potrzeba uruchomienia kodu zawartego w inny 
bloku case, po kodzie w danym bloku case, jest przedstawione przy 
omawianiu instrukcji goto w tym module. 

 

background image

goto 

 

 

Instrukcja goto jest instrukcją o "złej sławie". Używanie instrukcji goto 
powoduje, że program staje się nieczytelny. Powinniśmy się, więc starać jej 
unikać. Instrukcja goto ma następującą formę: 

goto etykieta; 

Po napotkaniu takiej instrukcji wykonywanie programu przenosi się do miejsca 
gdzie jest zdefiniowana dana etykieta. Definicja etykiety składa się z jej nazwy 
i znaku dwukropka. 

etykieta : 

Etykieta może mieć następujące formy: 

 

identyfikator 

 

case wartosc 

 

default 

W przypadku dwóch ostatnich rodzajów etykiet, instrukcja goto musi się 
znajdować w bloku instrukcji switch. W przypadku pierwszym, goto może 
skoczyć do etykiety na zewnątrz bloku lub do etykiety w tym samym bloku. 
Nie może skoczyć do etykiety, która jest zdefiniowana w bloku 
zagnieżdżonym, wewnętrznym w stosunku do bloku instrukcji goto. 
Instrukcja goto nie może występować w bloku finally. 

Uwaga: 
Instrukcja goto nie może przenieść wykonania kodu z jednej metody do 
drugie - nie może "skakać" między metodami 

background image

 

Etykieta w bloku 
zewnętrznym - OK 

Etykieta w tym samym 
bloku - OK 

Etykieta w bloku 
wewnętrznym - źle 

et: 
... 

... 
   goto et; 
... 

goto et; 
... 
et: 
... 
 

goto et; 
... 

... 
   et: 
... 

 

W przypadku, gdy etykieta nie jest dostępna, podczas kompilacji zgłaszany jest 
błąd  

Mimo złej sławy są dwie sytuacje, kiedy instrukcja goto jest na pewno 
przydatna.  

1.  Natychmiastowe opuszczenie wielokrotnie zagnieżdżonych pętli. 

 
while(...){ 
   ... 
   for(...){ 
       ... 
       while(...){ 
          ... 
          goto Etykieta; 
       } 
   } 

Etykieta: 
  instrukcja1; 

2.  W celu ominięcia reguły zabraniającego przejścia między blokami 

case lub blokiem default (no fall through rule). 
 
switch(c) 

  case 'a':instrA1; 
           goto case 'A'; 
  case 'A':instrukcjaA1; 
 

     instrukcjaA2; 

 

     ... 

 

     break; 

  case 'b': instrB1; 
            goto default;     
  default: instrukacja1; 
           break; 

background image

 break 

 

 

Poznaliśmy już wcześniej działanie instrukcji break - polegało na przerwaniu 
wykonywania instrukcji switch. Oprócz tego break może również 
przerywać działanie pętli. Jeśli jest kilka pętli zagnieżdżonych jedna w drugiej, 
to instrukcja break powoduje przerwanie tylko tej pętli, w której bezpośrednio 
się znajduje - patrz slajd. 

background image

continue 

 

 

Instrukcja continue może występować wewnątrz bloku instrukcji 
iteracyjnych. W odróżnieniu od instrukcji break, instrukcja continue nie 
kończy działania pętli, ale przerywa tylko aktualny obieg pętli i zaczyna 
następny, kontynuując pracę pętli - patrz slajd. Podobnie jak break, w 
przypadku pętli zagnieżdżonych, instrukcja continue przerywa aktualny 
obieg tej pętli, w której bezpośrednio się znajduje. 

background image

Szablon programu 

 

 

Używając poznane do tej pory instrukcje, można przedstawić pewien szablon 
programu. Szablon możemy przedstawić przy pomocy następującego schematu: 

 

 

 

 

 

 

 

 

 

 

 

Przykładową implementację można obejrzeć na slajdzie. Bardziej rozbudowany 
przykład jest dostępny projekcie SzablonProjektu, który jest częścią 
rozwiązania Kurs\Demo\Modul5\Modul5.sln, gdzie Kurs jest 
katalogiem gdzie skopiowano pliki kursu. 

Wyświetlenie menu, czyli 

co program robi i jak go 

do tego zmusić. 

Oczekiwanie na polecenie 

od użytkownika i jego 

pobranie. 

Przetworzenie polecenia 

użytkownika i 

wyświetlenie wyników. 

background image

Uwaga: 
W programie wykorzystywane są metody i właściwości klasy Console, które 
do tej pory nie były omówione: 

 

Console.BufferHeight - liczba dostępnych wierszy w okienku.. 

 

Console.WindowHeight - liczba widocznych wierszy w oknie. 
Musi być ona mniejsza od właściwości 
Console.LargestWindowHeight

, która oznacza maksymalną 

ilość wierszy, wyznaczoną w oparciu o bieżącą wielkość fontu i 
rozdzielczość ekranu. 

 

Console.BufferWidth - liczba dostępnych kolumn w okienku. 
Musi być ona mniejsza od właściwości 
Console.LargestWindowWidth

, która oznacza maksymalną 

ilość kolumn, wyznaczoną w oparciu o bieżącą wielkość fontu i 
rozdzielczość ekranu. 

 

Console.WindowWidth - liczba widocznych kolumn w oknie. 

 

Console.BackgroundColor - kolor tła. 

 

Console.ForegroundColor - kolor czcionki. 

 

Console.Clear() - wyczyszczenie całego okna, zamazanie 
kolorem tła. 

 

Console.CursorLeft - numer kolumny, gdzie znajduje się 
kursor. Kolumny są numerowane od lewej do prawej strony okna. 

 

Console.CursorTop - numer wiersza, gdzie znajduje się kursor. 
Wiersze są numerowane od góry do dołu okna. 

 

Console.SetCursorPosition(kolumna, wiersz) - 
ustawienie pozycji kursora, czyli gdzie będzie rozpoczynać się 
operacja wypisania na ekranie 

 

Console.ReadKey(true).KeyChar - wartość typu char 
naciśniętego klawisza. 

Warto wspomnieć jeszcze o jednej metodzie klasy Console: 

 

Console.Beep(czestotlowosc, czas) - wydanie dźwięku o 
danej częstotliwość podanej w Hz, przez określony czas podany w ms. 

 

background image

Pytania sprawdzające 

 

 

1.  Jakie błędy popełniono w poniższym kodzie: 

 
double x; 
... 
switch(x){ 
   case 4 :  
   case 4 : instrukcjaA1; 
            break; 
   default: instrukacj2; 

 
Odp. 
W powyższym kozie popełniono następujące błędy: 
- wartość (zmienna ) typu double nie może być wartością przełączającą w 
instrukcji switch. Dopuszczalne typy to wszystkie typy całkowite, typ 
string oraz typy wyliczeniowe, 
- powtórzona wartość 4. Każda wartość obok case musi być unikalna, w 
danej instrukcji switch 
- po etykiecie default występuje instrukcja, nie ma natomiast instrukcji 
skoku break albo goto. 

2.  Jaka jest różnica między instrukcjami break i continue wewnątrz pętli? 

 
Odp. 
Instrukcja break powoduje przerwanie (zakończenie) pętli, natomiast 
instrukcja continue kończy pojedynczy obieg pętli i zaczyna następny, 
kontynuując pracę pętli. 

background image

Laboratorium 

 

 

Ćwiczenie 

Napisz program obliczający całkę oznaczoną z funkcji nieujemnej i całkowalnej  
na zadanym przedziale np. f(x) = x

4

 + x

3

 + 2. Użytkownik ma do 

wyboru: 

 

metodę (metoda prostokątów lub metoda trapezów) 

 

przedział całkowania 

 

liczbę podziałów (podprzedziałów) 

Całkę oznaczaną w przedziale <a; b> z funkcji nieujemnej całkowalnej na 
przedziale <a, b> można interpretować jako pole obszaru ograniczonego 
wykresem tej funkcji, osią OX oraz prostymi x = a i x = b. 

W przypadku metody prostokątów, pole to przybliżamy, sumą pól odpowiednio 
dobranych prostokątów. Sposób postępowania jest następujący: Przedział 

background image

całkowania <a; b> dzielimy na n równych podprzedziałów: <x

0

; x

1

>, 

<x

1

; x

2

>, ..., <x

n-2

; x

n-1

>, <x

n-1

; x

n

gdzie: 

 

 

Dla każdego punktu x

i

, gdzie i = 1...n, wyznaczamy wartość funkcji w tym 

punkcie. Będzie to długość jednego z boków prostokąta. Długość drugiego 
boku jest równa szerokości podprzedziału. Sumę pól prostokątów, a więc 
przybliżoną wartość całki, możemy zapisać wzorem: 

 

 

 

W przypadku metody trapezów, zamiast sumy pól prostokątów używamy sumę 
pól trapezów: 

Pole trapezu jest równe iloczynowi wysokości i połowy sumy podstaw trapezu. 

 

 

Dla podprzedziału <x

i-1

; x

i

> pole trapezu można zapisać: 

 

 

Wzór na przybliżoną wartość całki, jako sumę pól trapezów, można więc 
zapisać:  

 

 

 

 

Dzięki powyższemu przekształceniu podczas obliczania wartości sumy, f(x

i

będzie obliczane tylko raz zamiast dwóch razy, gdybyśmy zastosowali wzór bez 
przekształceń. 

n

i

n

b

a

i

a

x

b

x

a

x

i

n

,...,

0

,

,

0

n

i

i

b

a

n

i

i

x

f

n

a

b

n

a

b

x

f

dx

x

f

1

1

)

(

)

(

)

(

)

(

2

1

2

1

podst

podst

h

P

trapezu

)]

(

)

(

[

2

1

1

i

i

trapezu

x

f

x

f

n

b

a

P

1

1

1

1

1

1

)

(

2

)

(

)

(

)]

(

)

(

[

2

2

)

(

)

(

)

(

n

i

i

n

i

i

i

b

a

n

i

i

i

x

f

b

f

a

f

n

a

b

x

f

x

f

n

a

b

n

a

b

x

f

x

f

dx

x

f

background image

1.  Uruchom Visual Studio 

Naciśnij przycisk Start systemu Windows, wybierz Wszystkie Programy 
następnie Microsoft Visual Studio 2005/ Microsoft Visual Studio 2005

2.  Utwórz nowy projekt 

a.  Z menu File wybierz New/Project... 

b.  W oknie dialogowym New Project określ następujące właściwości: 

i.  typu projektu: Visual C#/Windows  

ii.  szablon: Console Application  

iii.  lokalizacja: Moje Dokumenty\Visual Studio 2005\Projects\ 

iv.  nazwa projektu: Calki.  

v.  nazwa rozwiązania: Lab5 

3. 

Przed metodą Main zdefiniuj nowy typ wyliczeniowy o nazwie 
MetodyCalkowania

, który ma dwa elementy Prostokatow=1 oraz  

Trapezow=2 
 
enum MetodyCalkowania { Prostokatow=1, Trapezow=2 } 

4.  Wewnątrz metody Main napisz następujący kod: 

a.  Zadeklaruj następujące zmienne i nadaj im wartości początkowe: 

i.  dwie zmienne rzeczywiste a i b, reprezentujące początek i koniec 

przedziału całkowania. a musi być mniejsze od b. 

ii.  Zmienną dodatnią n reprezentującą liczbę podziałów przedziału 

całkowania. 

iii.  Zmienną metoda typu MetodyCalkowania. 

 
double a = 0, b = 1;  
uint n = 10; 
MetodyCalkowania metoda =  
 

 

 

MetodyCalkowania.Prostokatow; 

b. 

Ustaw główną pętlę programu: 
 
char c; 
do 

... 

while(!(c =='K' || c=='k')); 

c.  W głównej pętli programu: 

i.  Wyświetl menu programu. Menu powinno zawierać informacje na 

temat: aktualnego przedziału całkowania, ilości podziałów i 
wybranej metody całkowania oraz jak zmienić przedział 
całkowania, metodę całkowania, liczbę podziałów, jak obliczyć 
całkę dla podanych parametrów i jak zakończyć program. 

Console.WriteLine("Przedział całkowania: <{0}; {1}>", 
 

 

 

 a, b); 

background image

Console.WriteLine("Liczba podziałów: {0}", n); 
Console.WriteLine("Metoda całkowania: {0}", metoda); 
Console.WriteLine("-----"); 
Console.WriteLine("A - Zmiana przedziału"); 
Console.WriteLine("B - Zmiana liczby podziałów"); 
Console.WriteLine("C - Zmiana metody całkowania"); 
Console.WriteLine("D - Policz całkę"); 
Console.WriteLine("K - Koniec"); 
 

ii.  Pobierz od użytkownika polecenie: 

 
c = Console.ReadKey(true).KeyChar; 

iii.  Ustaw blok instrukcji switch w celu przetworzenia poleceń użytkownika: 

 
switch(c) 

... 

iv. W bloku switch napisz następujący kod przetwarzający polecenia 

użytkownika: 

1. 

Obsługa zmiany przedziału całkowania: 
Pobierz wartość początku przedziału i wstaw do zmiennej a. Pobierz 
wartość końca przedziału i wstaw do zmiennej b. Dopilnuj, aby 
wartość b była większa od a: 

case 'a': 
case 'A': 
  do 
  { 
    if (a > b) 
    { 
      Console.Write("Początek musi być  
       

¬mniejszy od końca: "); 

    } 
    Console.Write("Podaj początek przedziału: "); 
    a = Convert.ToDouble(Console.ReadLine()); 
    Console.Write("Podaj koniec przedziału: "); 
    b = Convert.ToDouble(Console.ReadLine()); 
  } 
  while (a > b); 
  break; 

2.  Obsługa zmiany liczby podziałów: 

Pobierz wartość liczby podziałów i wstaw do zmiennej n. Jeżeli 
użytkownik podał zero, zgłoś wyjątek. 

case 'b': 
case 'B': 
 

Console.Write("Podaj liczbę podziałów: "); 

 

n = Convert.ToUInt32(Console.ReadLine()); 

 

if (n == 0)  

 

 

throw new Exception("Liczba podziałów musi 

 

 

 

¬ być większa od zera"); 

 

break; 

background image

3.  Obsługa zmiany metody całkowania: 

Pobierz metodę całkowania od użytkonika: 

case 'c': 
case 'C': 
  int m = 1; 
  do 
  { 
    if (m != 1) 
    { 
      Console.Write("Naciśnij 1 lub 2: "); 
    } 
    Console.WriteLine("Podaj metodę liczenia  
      ¬całki: "); 
    Console. WriteLine("\t1-Metoda prostokątów"); 
    Console. WriteLine ("\t2 - Metoda trapezów: "); 
    m = Convert.ToInt32(Console.ReadLine()); 
  } 
  while (!(m == 1 || m == 2)); 
  metoda = (MetodyCalkowania)m; 
  break; 

 

4. 

Obsługa liczenia całki 

a.  Dodaj nowy blok case: 

 
case 'd': 
case 'D': 

b.  Zadeklaruj trzy pomocnicze zmienne rzeczywiste: suma i nadaj 

jej wartość zero, dx (szerokość podprzedziału) i nadaj jej wartość 
(b-a)/n, x i nadaj jej wartość a. 
 
double suma = 0; 
double dx = (b - a) / n; 
double x = a; 

c.  W zależności od wartości zmiennej metoda, oblicz wartość całki i 

wstaw ją do zmiennej suma. Jeżeli wartość zmiennej metoda jest 
równa MetodyCalkowania.Prostokatow skorzystaj ze 
wzoru: 
 
 
 
Jeżeli wartość zmiennej metoda jest równa 
MetodyCalkowania.Trapezow skorzystaj ze wzoru: 
 
 
 
 
Uwaga: 
W celu optymalizacji obliczania wartości funkcji w punkcie, 
możemy skorzystać z następującego przekształcenia: 
f(x) = x

4

+x

3

+2 = x

3

(x+1)+2 

 
switch (metoda) 

n

i

i

b

a

x

f

n

a

b

dx

x

f

1

)

(

)

(

1

1

)

(

2

)

(

)

(

)

(

n

i

i

b

a

x

f

b

f

a

f

n

a

b

dx

x

f

background image


case MetodyCalkowania.Prostokatow: 
 

for (int i = 0; i < n; i++) 

 

 

 

x += dx; 

 

 

suma += x * x * x * (x + 1) + 2; 

 

 

suma *= dx; 

 

break; 

case MetodyCalkowania.Trapezow: 
 

for (int i = 1; i < n; i++) 

 

 

 

x += dx; 

 

 

suma += x * x * x * (x + 1) + 2; 

 

 

suma += (a * a * a * (a + 1) + 

 

 

 b * b * b * (b + 1) + 4) / 2; 

 

suma *= dx; 

 

break; 

d. 

Wypisz wartość całki (sumy) na ekranie i poczekaj na reakcję 
użytkownika, aby mógł obejrzeć wynik. 
 
Console.Write("Przybliżona wartość całki  
 

¬funkcji f(x) w przedziale <{0}; {1}> 

 

¬ wynosi: {2}",a, b, suma); 

Console.ReadKey(true); 
break; 

5.  Skompiluj i uruchom program.