Progr
Programowanie
nie
w jęz
w ję yku C
zyku C
© 2009
Grzegorz Łukawski & Maciej Lasota
Politechnika Świętokrzyska w Kielcach
Wykład nr 3:
Niejawna i jawna konwersja typów
Instrukcja warunkowa if, switch
Pętle while, do..while, for
Pętle „nieskończone”
Generowanie liczb pseudolosowych
Niejawna i jawna konwersja typów Konwersja typów następuje, gdy operacja ma zostać wykonana na zmiennych różnego typu (np. dodawanie liczb int i float). Występuje w dwóch postaciach:
● Konwersja niejawna – wykonywana automatycznie przez kompilator gdy występuje niezgodność typów danych.
● Konwersja jawna (rzutowanie) – wymuszana przez programistę w dowolnym miejscu programu.
Ponieważ procesor może wykonywać bezpośrednie operacje tylko na danych tego samego typu (z małymi wyjątkami), w przypadku niezgodności typów zawsze następuje konwersja niejawna na większy z nich.
int a, wynik;
float suma;
double
(…)
float
wynik = suma * a;
ersjiwn
long long
(int) = (float) * (int);
o k
long
(int) = (float) * (float);
ekn
short
(float) = (float) * (float);
ieru
char
K
(int)
Umiejętne stosowanie stałych zmiennoprzecinkowych pozwala „skierować”
konwersję we właściwą stronę:
1.01
// double
5.99f
// float
Np.:
int n1, n2;
// Np. n1=10, n2=1
double wynik;
(…)
wynik = n1 / 100 + n2;
// Wynik nieprawidłowy!
wynik = n1 / 100.0 + n2;
// Wynik prawidłowy
Konwersja jawna – rzutowanie Konwersja jawna może być wymuszona w dowolnym kierunku.
(nowy_typ)zmienna
int n1, n2;
double wynik;
(…)
wynik = n1 / n2;
// Wynik nieprawidłowy!
wynik = 1.0 * n1 / n2;
wynik = (double)n1 / n2;
// Wynik prawidłowy
Przy konwersji typów większych na mniejsze może dojść do utraty danych!
unsigned char m;
m = (unsigned char)(n1 / (float)n2);
Konwersja jawna – rzutowanie Rzutowanie może dotyczyć nie tylko liczb, ma zastosowanie również do typów złożonych: tablic, struktur, wskaźników, funkcji...
Częste zastosowanie konwersji jawnej – zamiana liczb ułamkowych na całkowite:
float w1 = 7.99;
int w2 = (int)w1;
// 7 – źle
int w3 = (int)(w1 + 0.5); // 8 – lepiej
if(war) instrukcja;
if(war) instrukcja1;
else instrukcja2;
Pojedyncza „instrukcja” może być zastąpiona blokiem {}.
W języku C nie istnieje typ boolean – stwierdzenie prawdziwości warunku następuje na drodze porównania z wartością 0: war <> 0
(Prawda)
war = 0
(Fałsz)
==
Równe
>
Większe
!=
Różne
>=
Większe lub równe
<
Mniejsze
<=
Mniejsze lub równe
int liczba;
scanf(„%d”, &liczba);
if(liczba < 0)
liczba = -liczba;
float wynik;
if(a == 0) wynik = b*100;
else
wynik = b*100 / a;
UWAGA!
Jednym z najczęstszych błędów programistów języka C jest zastąpienie operatora porównania == operatorem przypisania =.
Błąd taki zazwyczaj nie jest sygnalizowany przez kompilator!
||
Operator lub (or)
&&
Operator i (and)
!
Operator zaprzeczenia (not)
if(a==0 && b==0) puts(„ZERO”); if(suma>0 && (c==1 || d==1)) {
suma = suma*2;
printf(„Suma = %d\n”, suma);
}
else
puts(„Niewłaściwe wartości”);
if(!(a==1 && b==10))
puts(„ERR”);
P onieważ operatory porównania mają wyższy priorytet niż operatory logiczne, nie trzeba stosować dodatkowych nawiasów.
Operator przypisania w instrukcji if() int n;
scanf(„%d”, &n);
// Wczytanie n
if(n = 0) {
puts(„Należy podać liczbę różną od 0!”); exit(0);
}
int x, y, z;
scanf(„%d”, &x);
// Wczytanie x
scanf(„%d”, &y);
// Wczytanie y
if(z = x+y)
printf(„%d\n”, 100 / z);
else
printf(„Nie dziel przez zero!\n”);
Instrukcja warunkowa switch – decyzja wielowariantowa Instrukcja switch zastępuje serię instrukcji if, pozwala porównać wartość zmiennej do wielu wartości stałych.
switch(zmienna) {
case W1:
if(zmienna == W1)
instr1;
instr1;
break;
else if(zmienna == W2)
case W2:
instr2;
instr2;
else
break;
instr3;
default:instr3;
}
Operator przypisania warunkowego warunek ? wartość1 : wartość2
Jeśli warunek jest spełniony, zwracana jest wartość1, w przeciwnym wypadku wartość2.
int a, b;
int a, b;
(…)
(…)
int max;
int max = (a>b) ? a : b;
if(a>b)
max = a;
else
max = b;
int x, y, w;
w = (y!=0) ? (x/y) : INT_MAX;
puts((ocena >= 3.0) ? "Zaliczenie" : "Nie zaliczone");
W języku C istnieją 4 rodzaje pętli:
● while() - standardowa pętla z warunkiem na początku;
● do..while() - pętla z warunkiem na końcu;
● for() - rozszerzenie pętli while() z iteratorem.
Typowa pętla z warunkiem na początku. Zasady dotyczące warunku są identyczne jak dla instrukcji if().
while(warunek) instrukcja;
while(warunek) {
instr1;
instr2;
(…)
}
Typowa pętla while() z warunkiem na końcu: do
instrukcja
while(warunek);
do {
instr1;
instr2;
(…)
} while(warunek);
UWAGA!
Wszystkie pętle w języku C wykonują się tak długo jak warunek pętli jest spełniony! Dotyczy to także pętli typu do...while().
Rozszerzenie pętli typu while() z iteratorem, wykorzystuje zmienną licznikową:
for(start;warunek;koniec)
instrukcja;
●
start
- instrukcja wykonywana raz przed pierwszą iteracją (opcja);
●
warunek - warunek wykonywania pętli – jak dla while();
●
koniec
- instrukcja wykonywana po każdym przejściu pętli (opcja).
Typowe użycie pętli for():
int n;
for(n=0;n < 10;n=n+1)
instr;
/* n = 0..9 */
Zgodnie ze standardem C99 możliwe jest definiowanie zmiennej licznikowej wewnątrz instrukcji for():
for(int n=0;n < 10;n=n+1)
instr;
Pętla for() - przykłady Mniej typowe użycie:
for(int n=1000;n != 0;n=n/10)
instr;
/* n = 1000, 100, 10, 1 */
Fraza początkowa i końcowa może składać się z kilku instrukcji: for(m=0,n=100;m < 10;m=m+1,n=n-10)
instr;
/* Pętla z dwoma licznikami */
/* m = 0..9, n = 100,90,80..10 */
Licznikiem pętli może być dowolna zmienna, również liczba zmiennoprzecinkowa:
float kat;
for(kat=0;kat < 2*M_PI;kat = kat+M_PI/6)
/* kat w zakresie <0 , 2Pi) */
U waga! W tym wypadku należy unika ć operatorów porównania == oraz !=.
int szer=640, wys=480;
int kolor;
for(int x=0;x < szer;x++) {
for(int y=0;y < wys;y++) {
kolor = GetPixel(x, y);
kolor = kolor + 33;
if(kolor > 255) kolor = 255;
PutPixel(x, y, kolor);
}
}
Operatory inkrementacji ++ i dekrementacji --
Jednoargumentowe operatory ++ (inkrementacja) i -- (dekrementacja) działają tylko na pojedynczych zmiennych.
zmienna++; zmienna--;
int wynik, liczba = 5;
wynik = (liczba++)+3;
// Zwiększenie po użyciu
// wynik = 8, liczba = 6
int wynik, liczba = 5;
wynik = (++liczba)+3;
// Zwiększenie przed użyciem
// wynik = 9, liczba = 6
int wynik, liczba = 5;
wynik = (liczba--)+3;
// Zmniejszenie po użyciu, itd.
// wynik = 8, liczba = 4
while(1) {…}
for(;;) {…}
● Instrukcja break przerywa najciaśniej otaczającą pętlę.
● Instrukcja continue wymusza kolejną iterację pętli.
int liczba;long suma = 0;
printf(„Podawaj liczby dodatnie, zero na koniec:”); while(1) {
scanf(„%d”,&liczba);
if(liczba == 0)
break;
if(liczba < 0)
continue;
suma = suma + liczba;
}
printf(„Suma = %ld”,suma);
Generowanie liczb pseudolosowych Funkcja generująca liczby:
rand()
Zakres generowanych liczb:
0..RAND_MAX (co najmniej 32767)
Inicjalizacja generatora:
srand(seed)
Z użyciem czasu:
srand(time(NULL))
Może być konieczne dołączenie nagłówka <time.h> Generator należy zainicjować tylko raz na początku programu.
Niezainicjowany generator może generować identyczne ciągu liczb po każdym uruchomieniu programu.
Najprostszy (prymitywny) sposób na zawężenie zakresu generowanych liczb to użycie operatora modulo:
x = rand() % 10 ;
// 0..9
y = 100 + rand() % 101;
// 100..200
z = -5 + rand() % 11;
// -5..5