Programowanie
w języku C
Programowanie
w ję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.
Konwersja niejawna
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.
double
float
long long
long
short
char
K
ie
ru
n
ek
k
o
n
w
er
sj
i
int a, wynik;
float suma;
(…)
wynik = suma * a;
(int) = (float) * (int);
(int) = (float) * (float);
(float) = (float) * (float);
(int)
int n1, n2;
// Np. n1=10, n2=1
double wynik;
(…)
wynik = n1 / 100 + n2;
// Wynik nieprawidłowy!
Konwersja niejawna
Umiejętne stosowanie stałych zmiennoprzecinkowych pozwala „skierować”
konwersję we właściwą stronę:
1.01
// double
5.99f
// float
wynik = n1 / 100.0 + n2;
// Wynik prawidłowy
Np.:
Konwersja jawna – rzutowanie
Konwersja jawna może być wymuszona w dowolnym kierunku.
int n1, n2;
double wynik;
(…)
wynik = n1 / n2;
// Wynik nieprawidłowy!
wynik = 1.0 * n1 / n2;
wynik = (double)n1 / n2;
// Wynik prawidłowy
unsigned char m;
m = (unsigned char)(n1 / (float)n2);
(nowy_typ)zmienna
Przy konwersji typów większych na mniejsze może dojść do utraty danych!
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
Instrukcja warunkowa if
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)
Operatory porównania
==
Równe
!=
Różne
int liczba;
scanf(„%d”, &liczba);
if(liczba < 0)
liczba = -liczba;
float wynik;
if(a == 0) wynik = b*100;
else
wynik = b*100 / a;
>
Większe
>=
Większe lub równe
<
Mniejsze
<=
Mniejsze lub równe
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!
Łączenie warunków
||
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”);
Ponieważ operatory porównania mają wyższy priorytet niż operatory logiczne,
nie trzeba stosować dodatkowych nawiasów.
if(!(a==1 && b==10))
puts(„ERR”);
Operator przypisania w instrukcji if()
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”);
int n;
scanf(„%d”, &n);
// Wczytanie n
if(
n = 0
) {
puts(„Należy podać liczbę różną od 0!”);
exit(0);
}
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:
instr1;
break;
case W2:
instr2;
break;
default:
instr3;
}
if(zmienna == W1)
instr1;
else if(zmienna == W2)
instr2;
else
instr3;
Operator przypisania warunkowego
Jeśli warunek jest spełniony, zwracana jest wartość1, w przeciwnym
wypadku wartość2.
warunek ? wartość1 : wartość2
int a, b;
(…)
int max = (a>b) ? a : b;
int x, y, w;
w = (y!=0) ? (x/y) : INT_MAX;
int a, b;
(…)
int max;
if(a>b)
max = a;
else
max = b;
puts((ocena >= 3.0) ? "Zaliczenie" : "Nie zaliczone");
Instrukcje pętli w języku C
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.
Pętla while()
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;
(…)
}
Pętla do...while()
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().
Typowe użycie pętli for():
int n;
for(n=0;n < 10;n=n+1)
instr;
/* n = 0..9 */
Pętla for()
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).
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) */
Uwaga! W tym wypadku należy unikać operatorów porównania == oraz !=.
Pętle zagnieżdżone
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.
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
zmienna++; zmienna--;
Pętle „nieskończone”
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);
suma = suma + liczba;
}
printf(„Suma = %ld”,suma);
if(liczba == 0)
break;
if(liczba < 0)
continue;
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