1
Programowanie strukturalne – j
ę
zyk C
Struktura programu
Przykład programu:
# include <stdio.h>
main()
{
printf(”Program w j
ę
zyku C \n”);
return 0;
}
Komentarze
W j
ę
zykach programowania wyst
ę
puj
ą
specjalne znaczniki
powoduj
ą
ce i
ż
umieszczony tekst nie jest cz
ęś
ci
ą
programu, a
jedynie dodatkow
ą
informacj
ą
o tre
ś
ci i zadaniach programu.
/* - znak otwarcia komentarza
*/ - znak zamkni
ę
cia komentarza
/* komentarz */
/*
komentarz
*/
// komentarz
Dyrektywa #include
# include - dyrektywa preprocesora - polecenia dla
preprocesora aby w tym miejscu doł
ą
czy
ć
do programu zawarto
ść
wskazanego pliku
2
preprocesor – specjalny program wykonuj
ą
cy czynno
ś
ci
przygotowawcze do kompilacji (przed kompilacj
ą
)
Pliki nagłówkowe
Po dyrektywie #include wyst
ę
puj
ą
pliki nagłówkowe, s
ą
to pliki
dodawane do programów za pomoc
ą
tej dyrektywy, nazwa ich
wywodzi si
ę
st
ą
d ,
ż
e s
ą
zawsze doł
ą
czane na pocz
ą
tku programu
(w jego nagłówku)
stdio.h - plik nagłówkowy standardowego wej
ś
cia – wyj
ś
cia
stdlib.h – standardowa biblioteka funkcji
string.h – operacje na ła
ń
cuchach tekstowych
math.h – funkcje matematyczne
conio.h – funkcje obsługi konsoli
<stdio.h> i ”stdio.h”
< ... > - plik nagłówkowy b
ę
dzie poszukiwany w katalogu innym
ni
ż
bie
żą
cy; wskazanym w opcjach kompilatora – jest to
najcz
ęś
ciej katalog /..../INCLUDE
” ... ” - plik nagłówkowy b
ę
dzie poszukiwany w katalogu
bie
żą
cym
Funkcja main()
Funkcja specjalna w j
ę
zyku C, w ka
ż
dym programie musi ona
wyst
ą
pi
ć
i jest tylko jedna.
Mo
ż
na j
ą
wstawi
ć
w dowolne miejsce w programie , jednak
program zacznie zawsze wykonywa
ć
si
ę
od funkcji main() i
zako
ń
czy swoje działanie w tej funkcji. Je
ż
eli wszystkie
instrukcje zawarte w funkcji main() zostały wykonane i
zako
ń
czone program ko
ń
czy swoje działanie.
W zamieszczonym powy
ż
ej przykładzie funkcja main() zawiera
funkcje biblioteczn
ą
printf() , której argumentami jest tekst
3
wyprowadzany na urz
ą
dzenie wej
ś
ciowe , oraz specjalny znak
steruj
ą
cy :
\n - znak steruj
ą
cy przej
ś
cia do nast
ę
pnego wiersza.
zasad
ą
tego j
ę
zyka programowania jest to,
ż
e ka
ż
da funkcja w
tym main() zwraca wynik; domy
ś
lnie wynikiem jest liczba typu
całkowitego (integer)
wykorzystywana jest do tego celu instrukcja :
return 0;
Zwrócenie przez funkcj
ę
warto
ś
ci 0 - oznacza i
ż
zako
ń
czyła si
ę
ona poprawnie, ka
ż
da inna warto
ść
całkowita wi
ę
ksza od zera
oznacza zako
ń
czenie działania funkcji z bł
ę
dem.
funkcja biblioteczna (stdlib.h) exit() - mo
ż
e by
ć
równie
ż
u
ż
yta do zako
ń
czenia działania programu.
Funkcja exit() nie zwraca
ż
adnego wyniku, ale argument
przekazany do funkcji wskazuje czy program zako
ń
czył si
ę
normalnie czy z bł
ę
dem.
exit(0) – zako
ń
czenie poprawne
exit(n) – zako
ń
czenie z bł
ę
dem n<>0
#include <stdio.h>
#include <stdlib.h>
void main()
{
printf(”Program w j
ę
zyku C\n”);
exit(0);
}
typ danych: void
void - pusty, nijaki
4
słowo to pojawiaj
ą
ce si
ę
przed nazw
ą
funkcji oznacza,
ż
e nie
b
ę
dzie ona zwraca
ć
ż
adnej warto
ś
ci
main() à zwraca domy
ś
lnie warto
ść
typu integer
void main() à funkcja main() nie zwraca
ż
adnej warto
ś
ci
linia instrukcji w j
ę
zyku C zako
ń
czona jest
ś
rednikiem
j
ę
zyk ten rozró
ż
nia małe i du
ż
e litery
Podstawowe elementy programu
Stałe i zmienne
stała – nigdy nie zmienia swojej warto
ś
ci
zmienna – mo
ż
e by
ć
u
ż
ywana do reprezentowania ró
ż
nych warto
ś
ci
Stałe i zmienne mog
ą
wystepowa
ć
razem w wyra
ż
eniach.
i = 1;
- jest stał
ą
;
i = 10;
- jest stał
ą
;
i - mo
ż
e przyjmowa
ć
ró
ż
ne warto
ś
ci (1,10, lub inne) zatem jest
zmienn
ą
.
Wyra
ż
enie
Wyra
ż
enie to kombinacja stałych, zmiennych i operatorów
( 3 + 6 ) * 20
4/2
20 * ( 2 + 1 )
Operatory arytmetyczne
+ - dodawanie
- odejmowanie
* - mno
ż
enie
5
/ - dzielenie
% - reszta z dzielenia (dzielenie modulo)
8 % 5 à 3
* / % - operatory o wy
ż
szym priorytecie
+ - - operatory o ni
ż
szym priorytecie
Priorytet okre
ś
la kolejno
ść
wykonywanych działa
ń
, chyba,
ż
e
wystepuj
ą
nawiasy, wtedy w pierwszej kolejno
ś
ci wykonywane s
ą
wyra
ż
enia w nawiasach.
Instrukcje
W j
ę
zyku C instrukcja to polecenie zako
ń
czone
ś
rednikiem.
i = 5;
j = (12+4 ) * 2;
k = i + j;
return 0;
exit(0);
printf(”To jest program w C”);
Bloki instrukcji
Grupa instrukcji tworzy blok instrukcji, który jest traktowany
przez kompilator jako pojedyncza instrukcja.
{
i = 5;
j = 8;
k = i + j;
}
6
Blok instrukcji to sposób poł
ą
czenia kilku instrukcji
prostych, tak aby zawsze były wykonywane razem – tak jak jedna
instrrukcja.
Struktura funkcji
Funkcje w j
ę
zyku c mog
ą
by
ć
albo funkcjami bibliotecznymi,
albo stworzonymi przez programist
ę
, albo przez innych
programistów.
Funkcja składa si
ę
z:
typu funkcji
nazwy funkcji
argumentów funkcji
nawiasu otwieraj
ą
cego
ciała funkcji
nawiasu zamykaj
ą
cego
int nazwa_funkcji(int x, int y)
{
int rezult;
rezult = x + y;
return rezult;
}
typ funkcji :
to rodzaj warto
ś
ci wyniku, który funkcja zamierza zwróci
ć
po
jej wykonaniu.
nazwa funkcji :
nazwa funkcji musi by
ć
zwi
ą
zana z zadaniem wykonywanym przez
funkcje
nazwa funkcji nie mo
ż
e rozpoczyna
ć
si
ę
do cyfry
nazwa funkcji nie mo
ż
e rozpoczyna
ć
si
ę
od znaku *
nazwa funkcji nie mo
ż
e rozpoczyna
ć
si
ę
od znaku operatora
arytmetycznego
nazwa funkcji nie mo
ż
e rozpoczyna
ć
si
ę
od znaku .
nazwa funkcji nie mo
ż
e zawiera
ć
(wewn
ą
trz) znaku -
7
nazwa funkcji nie mo
ż
e zawiera
ć
(wewn
ą
trz) znaku ‘
argumenty przekazywane do funkcji
dla prawidłowego wykonania pewne funkcje potrzebuj
ą
przekazania im pewnych informacji , przekazywanych w postaci
tzw. argumentów
argumenty umieszczane s
ą
w nawiasach okr
ą
głych tu
ż
po nazwie
funkcji
je
ż
eli do prawidłowego działania funkcji niezb
ę
dne jest
podanie wi
ę
cej ni
ż
jednego argumentu, wtedy tworzymy tzw.
list
ę
argumentów, w które argumenty oddzielone s
ą
od siebie
przecinkami
je
ż
eli funkcja nie wymaga
ż
adnych argumentów to lista
argumentów jest pusta
pocz
ą
tek i koniec funkcji :
{ } znaki słu
żą
ce do zaznaczenia pocz
ą
tku i ko
ń
ca funkcji;
pomi
ę
dzy nimi zawarte jest ciało funkcji;
ciało funkcji :
zawiera :
deklaracje zmiennych
instrukcje j
ę
zyka C
wykonanie funkcji à wykonanie instrukcji stanowi
ą
cych jej
ciało
wywołanie funkcji polega na podaniu jej nazwy i okre
ś
leniu
argumentów wywołania;
// p_0
# include <stdio.h>int dodaj(int x, int y)
{
int wynik;
wynik=x+y;
return wynik;
}
int main()
8
{
int suma;
suma=dodaj(2,3);
printf("Wynik dodawania 2 + 3 = %d\n",suma);
return 0;
}
// p_01
# include <stdio.h># include <conio.h>
int dodaj(int x, int y)
{
int wynik;
wynik=x+y;
return wynik;
}
int main()
{
int suma;
suma=dodaj(2,3);
clrscr();
printf("Wynik dodawania 2 + 3 = %d\n",suma);
return 0;
}
// p_02
# include <stdio.h>
# include <conio.h>
int dodaj(int ax,int ay);
9
int main()
{
int suma;
suma=dodaj(2,3);
clrscr();
printf("Wynik dodawania 2 + 3 = %d\n",suma);
return 0;
}
int dodaj(int x, int y)
{
int wynik;
wynik=x+y;
return wynik;
}
Słowa kluczowe j
ę
zyka C
auto break case char const continue
default do double else enum extern
float for goto if int long
register return short signed sizeof static
struct switch typedef union unsigned void
volatile while
słowa kluczowe j
ę
zyka C pisane s
ą
małymi literami
10
Typy danych
Typ danych - char
obiekty typu charakter to znaki : a, b, z, A,B,7,,0,2,W,w
ka
ż
dy z tych znaków przechowywany jest w pami
ę
ci w postaci
numerycznego kodu liczbowego
tablica kodów ASCII 27 =128
rozszerzona tablica kodów ASCII 28 =256
obiekt typu char zajmuje 1 bajt (8 bitów)
zmienne znakowe - mog
ą
reprezentowa
ć
ró
ż
ne znaki
deklaracja zmiennej znakowe jest sposobem przyporz
ą
dkowania
tej zmiennej okre
ś
lonego miejsca w pami
ę
ci o rozmiarze
odpowiadaj
ą
cym typowi tej zmiennej
char lista nazw zmiennych /oddzielone przecinkami/;
char c1,c2,c_znak;
Stałe znakowe
znak uj
ę
ty w apostrofy (‘) jest nazywany stał
ą
znakow
ą
‘a’ , ‘A’ , ‘b’
stałe znakowe (pojedyncze znaki ASCII) s
ą
ujmowane w apostrofy
(‘) ;
ła
ń
cuchy znakowe (teksty) s
ą
ujmowane w znaki (”);
poszczególnym znakom przyporz
ą
dkowane s
ą
ich kody ASCII;
‘A’ à 65
‘a’ à 97
‘B’ à 66
‘b’ à 98
dlatego dla zmiennej x
char x;
11
x=’A’; i x=65 to równowa
ż
ne zapisy
znak specjalny : \
tworzy wraz z innymi znakami znaki steruj
ą
ce:
np.:
\n - przej
ś
cie do nast
ę
pnej linii
\b - cofni
ę
cie kursora o jeden znak w lewo
\f - przej
ś
cie do nast
ę
pnej strony
\r - powrót na pocz
ą
tek bie
żą
cego wiersza
\t - tabulacja
drukowanie znaków :
do wyprowadzania znaków na ekran mo
ż
na stosowa
ć
funkcj
ę
printf();
W funkcji tej do wyprowadzenia pojedynczego znaku słu
ż
y format
: %c
# include <stdio.h># include <conio.h>void main(void){char
c1,c2; c1='a'; clrscr(); printf("Oto c1 %c \n",c1); c2='A';
c1='B'; printf("Oto c1 %c \n",c1);
printf("Oto c2 %c \n",c2);
getch();
}
# include <stdio.h># include <conio.h>int main(){char c1,c2;
c1=97; c2=65; clrscr(); printf("Oto c1 %c \n",c1); printf("Oto
c2 %c \n",c2);}
12
Specyfikator formatu %c, u
ż
yty w funkcji printf(), okre
ś
la
sposób wy
ś
wietlenia zmiennej - w tym przypadku jest to sposób
wy
ś
wietlenia w postaci znaku;
Typ danych int /integer/
typ danych int wykorzystywany jest dla danych numerycznych –
całkowitych;
liczby całkowite nie zawieraj
ą
ani cz
ęś
ci ułamkowej, ani
przecinka dziesi
ę
tnego;
wynik dzielenie liczb całkowitych ulega obci
ę
ciu o cz
ęść
ułamkow
ą
;
w najprostszym przypadku obiekty typu int zajmuj
ą
2 bajty / w
innych systemach mo
ż
e to by
ć
4 bajty/
zakres warto
ś
ci 16 bitowych liczb całkowitych (2bajty)
32 767 (215 – 1) do -32 768 dla liczb ze znakiem
lub
do 216 dla liczb bez znaku
deklarowanie zmiennych dla obiektów typu int
int lista zmiennych;
int x, zm_1,i;
drukowanie numerycznych kodów znaków
%d - jest specyfikatorem formatu, który zawarto
ść
komórek
pami
ę
ci interpretuje jako warto
ść
typu integer
// p_1
# include <stdio.h># include <conio.h>void main(void){char
c1,c2; c1='a'; clrscr(); printf("Oto c1 %c %d \n",c1,c1);
c2='A'; c1='B'; printf("Oto c1 %c %d \n",c1,c1);
printf("Oto c2 %c %d \n",c2,c2);
getch();
}
13
//p_2
# include <stdio.h># include <conio.h>int main(){char c1,c2;
c1=97; c2=65; clrscr(); printf("Oto c1 %c %d \n",c1,c1);
printf("Oto c2 %c %d \n",c2,c2);
}
zmienne znakowe mog
ą
by
ć
wyprowadzane na ekran albo w postaci
znaków, albo w postaci ich kodów numerycznych ; zale
ż
y to od
specyfikatora formatu.
typ danych - float
zmienne przecinkowe (z pływaj
ą
cym przecinkiem) – float
- stałe 6,56f lub 6,56F oznaczaj
ą
stałe typu float
6,56 domy
ś
lnie jest traktowane jako typ double
typ float zajmuje 4 bajty pami
ę
ci
co najmniej 6 miejsc znacz
ą
cych po przecinku
deklaracja:
float lista zmiennych;
float y, zm_1, x;
%f jest zmiennoprzecinkowym specyfikatorem formatu
//p_3
# include <stdio.h># include <conio.h>int main(){int i1,i2,d;
i1=3; i2=2; d=i1/i2; clrscr(); printf("Oto wynik 3/2 = %d
\n",d); getch();}
//p_4
# include <stdio.h># include <conio.h>void main(void){int
int_1,int_2,int_3,int_4;
float flt_1,flt_2,flt_3,flt_4;
clrscr();
14
int_1=32/10;
flt_1=32/10;
int_2=32.0/10;
flt_2=32.0/10;
int_3=32/10.0;
flt_3=32/10.0;
int_4=32.0/10.0;
flt_4=32.0/10.0;
printf("Dzielenie całkowite 32/10 %d\n",int_1);
printf("Dzielenie zmiennoprzecinkowe 32/10 %f\n",flt_1);
printf("Dzielenie całkowite 32.0/10 %d\n",int_2);
printf("Dzielenie zmiennoprzecinowe 32.0/10 %f\n",flt_2);
printf("Dzielenie całkowite 32/10.0 %d\n",int_3);
printf("Dzielenie zmiennoprzecinkowe 32/10.0 %f\n",flt_3);
printf("Dzielenie całkowite 32.0/10.0 %d\n",int_4);
printf("Dzielenie zmiennoprzecinkowe 32.0/10.0 %f\n",flt_4);
getch();
}
typ danych - double
w przeciwie
ń
stwie do typu float, typ zmiennopozycyjny double
zajmuje dwa razy wi
ę
cej miejsca w pami
ę
ci (8 bajtów)
co najmniej 10 miejsc znacz
ą
cych po przecinku
zapis wykładniczy liczb
w formacie wykładniczym liczba przedstawiona jest w postaci
mantysy i wykładnika; cecha i mantysa rozdzielone s
ą
litera E
(e)
mantysa E (e) wykładnik
15
= 5e3
-300 = -3e2
przy wyprowadzaniu liczb w takim formacie na ekran, funkcja
printf() u
ż
ywa specyfikatora:
%e lub %E
Identyfikatory
s
ą
to nazwy zmiennych i funkcji j
ę
zyka C
Znaki, które mo
ż
na stosowa
ć
przy nadawaniu nazw zmiennych:
litery du
ż
e A,...,Z i małe a,...,z;
cyfry 0,...,9 /cyfra nie mo
ż
e by
ć
pierwszym znakiem nazwy/;
znak podkre
ś
lenia (_);
Znaki zabronione przy nadawaniu nazw zmiennych:
nazwa zmiennej nie mo
ż
e zawiera
ć
znaku jakiejkolwiek operacji
arytmetycznej;
nazwa zmiennej nie mo
ż
e zawiera
ć
kropki (.);
nazwa zmiennej nie mo
ż
e zawiera
ć
apostrofu (‘);
nazwa zmiennej nie mo
ż
e zawiera
ć
ż
adnego spo
ś
ród pozostałych
symboli specjalnych : *,@,#,?, itp.
nie mo
ż
na stosowa
ć
słów kluczowych j
ę
zyka C, nazw funkcji
bibliotecznych jako nazw zmiennych w programach pisanych w
j
ę
zyku C;
Obsługa standardowego wej
ś
cia/wyj
ś
cia
Miejscem przechowywania informacji s
ą
pliki. Poniewa
ż
informacje s
ą
reprezentowane jako ci
ą
gi bitów pogrupowane po 8
w bajty, j
ę
zyk C traktuje plik jako ci
ą
g bajtów.
Ci
ą
g bajtów mo
ż
e by
ć
nazwany plikiem b
ą
d
ź
strumieniem. W
j
ę
zyku C wszystkie strumienie danych i wszystkie pliki
traktowane s
ą
tak samo.
W j
ę
zyku C mamy do czynienia z 3 strumieniami plikowymi:
stdin - standardowe wej
ś
cie do odczytu
stdout - standardowe wyj
ś
cie do zapisu
stderr - standardowe wyj
ś
cie diagnostyczne dla komunikatów o
bł
ę
dach
16
zazwyczaj stdin à klawiatura
stdout , stderr à ekran monitora
Wprowadzanie danych
Funkcja getc() - wczytuje pojedynczy znak ze strumienia
(pliku) wej
ś
ciowego , zwracaj
ą
c kod wczytanego znaku w postaci
liczby całkowitej (int).
int getc(FILE *stream);
int getc(stdin);
//P_5
# include <stdio.h># include <conio.h>void main(void){ int c;
clrscr(); printf("Naci
ś
nij klawisz : \n"); c=getc(stdin);
printf("Nacisn
ą
łe
ś
klawisz < %c > ,którego kod ASCII wynosi %d
\n",c,c); getch();}
Funkcja getchar() - jest równowa
ż
na funkcji getc(stdin);
int getchar(void);
//p_6
# include <stdio.h># include <conio.h>void main(void){ int c;
clrscr(); printf("Naci
ś
nij klawisz : \n"); c=getchar();
printf("Nacisn
ą
łe
ś
klawisz < %c > ,którego kod ASCII wynosi %d
\n",c,c);
getch();
}
Wyprowadzanie danych
Funkcja putc() - wysyła znak do wskazanego jej jako argument
strumienia /pliku.
int putc(int c, FILE *stream);
int c - pierwszy argument funkcji to nazwa zmiennej
numerycznej przechowuj
ą
cej kod znaku do przesłania;
17
drugi argumnet to wska
ź
nik do pliku wyj
ś
ciowego
je
ż
eli operacja si
ę
powiodła funkcja zwraca numer kodu
przesłanego znaku; w przeciwnym przypadku (bł
ą
d) funkcja
zwraca EOF (-1)
//P_7
# include <stdio.h># include <conio.h>void main(void)
{
int c;
clrscr();
c=70;
printf("Znak o kodzie ASCII 70 to \n");
putc(c,stdout);
getch();
}
Funkcja putchar() - funkcja ta w przeciwie
ń
stwie do putc()
potrzebuje tylko jednego argumentu tj. znaku przeznaczonego do
wyprowadzenia;
drugiego argumentu nie trzeba wprowadza
ć
poniewa
ż
jest on
domy
ś
lny tj. stdout
// p_8
18
# include <stdio.h># include <conio.h>void main(void){ int c;
clrscr(); c=70; printf("Znak o kodzie ASCII 70 to \n");
putchar(c); getch();}
//p_9
# include <stdio.h>
# include <conio.h>
void main(void)
{
clrscr();
putchar(65);
putchar(10);
putchar(66);
putchar(10);
putchar(67);
putchar(10);
getch();
}
Funkcja printf()
int printf(const char *format_string, ...);
const – stała
char - typ znakowy
* - wska
ź
nik (wskazanie)
format_string - ła
ń
cuch formatuj
ą
cy
... - nastepne elementy
pierwszy element format_string to ła
ń
cuch znaków zawieraj
ą
cy
równie
ż
specyfikatory formatu (%c, %d, %f, itp.)
19
cz
ęść
druga to ewentualna lista wyra
ż
e
ń
, które powinny by
ć
sformatowane w cz
ęś
ci pierwszej zgodnie ze specyfikatorami
formatu;
ilo
ść
tych wyra
ż
e
ń
musi by
ć
równa ilo
ś
ci specyfikatorów
formatu w cz
ęś
ci pierwszej
funkcja printf() zwraca (int) ilo
ść
poprawnie sformatowanych
wyra
ż
e
ń
, w przeciwnym przypadku zwraca warto
ść
ujemn
ą
Specyfikatory formatu, które mo
ż
na stosowa
ć
w wywołaniu
funkcji printf()
%c - znak (typ char)
%d - liczba (typ int)
%i - liczba (typ int) to samo co %d
%f - liczba zmiennoprzecinkowa (typ float)
%e - format wykładniczy z u
ż
yciem małej litery e
%E - format wykładniczy z u
ż
yciem du
ż
ej litery E
%g - zastosuj %f lub %e – wybierz format, w którym wynik
b
ę
dzie krótszy
%G - zastosuj % f lub %E – wybierz format, w którym wynik
b
ę
dzie krótszy
%o - liczba ósemkowa bez znaku
%s - ła
ń
cuch znaków (string)
%u - liczba całkowita (typu unsigned) jak int, ale bez znaku
%x - liczba szesnastkowa bez znaku (z zastosowanie przyrostka
x, małe litery)
%X - liczba szesnastkowa bez znaku (z zastosowaniem przyrostka
X, du
ż
e litery)
%p - argument odpowiadaj
ą
cy wska
ź
nikowi (pointer)
%n - rejestruj ilo
ść
znaków wyprowadzon
ą
do tego momentu
%% - wyprowad
ź
znak ‘%’
Zamiana liczb dziesi
ę
tnych na szesnastkowe - wykorzystanie
formatu %x i %X
//p_10
# include <stdio.h># include <conio.h>void
main(void){clrscr(); printf("Liczba 16 X Liczba 16 x Liczba
10\n");
printf("%X %x %d\n",0,0,0);
printf("%X %x %d\n",1,1,1);
printf("%X %x %d\n",2,2,2);
printf("%X %x %d\n",3,3,3);
printf("%X %x %d\n",4,4,4);
20
printf("%X %x %d\n",5,5,5);
printf("%X %x %d\n",6,6,6);
printf("%X %x %d\n",7,7,7);
printf("%X %x %d\n",8,8,8);
printf("%X %x %d\n",9,9,9);
printf("%X %x %d\n",10,10,10);
printf("%X %x %d\n",11,11,11);
printf("%X %x %d\n",12,12,12);
printf("%X %x %d\n",13,13,13);
printf("%X %x %d\n",14,14,14);
printf("%X %x %d\n",15,15,15);
printf("%X %x %d\n",16,16,16);
printf("%X %x %d\n",17,17,17);
printf("%X %x %d\n",18,18,18);
printf("%X %x %d\n",19,19,19);
printf("%X %x %d\n",20,20,20);
getch();
}
Minimalna szeroko
ść
pola
J
ę
zyk C umo
ż
liwia na wstawienie do specyfikatora formatu
pomi
ę
dzy znak % a liter
ę
specyfikatora liczby nazywanej
specyfikatorem minimalnej szeroko
ś
ci pola
21
np. %10f - wyprowadzenie w formacie zmiennoprzecinkowym z
u
ż
yciem minimum 10 znaków (cyfr)
//p_11
# include <stdio.h># include <conio.h>void main(void){int
n1,n2;clrscr(); n1=12; n2=12345; printf("%d\n",n1);
printf("%d\n",n2); printf("%5d\n",n1); printf("%05d\n",n1);
printf("%2d\n",n2); getch();}
%5d - ustalenie na 5 minimalnej szeroko
ś
ci pola wyj
ś
ciowego
%05d - jak wy
ż
ej z tym
ż
e puste miejsca zostana wypełnione
zerami
%2d - gdy specyfikator formatu jest za mały w stosunku do
długo
ś
ci liczby to liczba jest wyprowadzana w cało
ś
ci
Wyrównanie pola wyj
ś
ciowego
Znaki wyj
ś
ciowe s
ą
wyrównywane do prawej strony.
Aby to zmieni
ć
, i doprowadzi
ć
do wyrównywania do lewej nale
ż
y
poprzedzi
ć
specyfikator minimalnej szeroko
ś
ci pola znakiem
minus (-);
//p_12
# include <stdio.h># include <conio.h>
void main(void)
{
int n1,n2;
clrscr();
22
n1=12;
n2=12345;
printf("%-d\n",n1);
printf("%-d\n",n2);
printf("%-5d\n",n1);
printf("%-05d\n",n1);
printf("%-2d\n",n2);
getch();
}
//p_13
# include <stdio.h># include <conio.h>void main(void)
{
int n1,n2,n3,n4,n5;
clrscr();
n1=1;
n2=12;
n3=123;
n4=1234;
n5=12345;
printf("%10d %-10d\n",n1,n1);
printf("%10d %-10d\n",n2,n2);
printf("%10d %-10d\n",n3,n3);
printf("%10d %-10d\n",n4,n4);
printf("%10d %-10d\n",n5,n5);
getch();
23
}
Specyfikator precyzji
Po specyfikatorze minimalnej szeroko
ś
ci pola mo
ż
na doda
ć
kropk
ę
(.) i liczb
ę
całkowit
ą
. Poł
ą
czenie .liczba tworzy
specyfikator precyzji.
Pozwala on okre
ś
li
ć
:
ilo
ść
cyfr dziesi
ę
tnych po przecinku dla liczb
zmiennoprzecinkowych;
albo maksymalna szeroko
ść
pola wyj
ś
ciowego /przypadek ten
odnosi si
ę
do liczb całkowitych i do ła
ń
cuchów tekstowych/
np.:
%10.3f
minimalna szeroko
ść
pola wyj
ś
ciowego 10 znaków
ilo
ść
cyfr dziesi
ę
tnych po przecinku : 3 /domy
ś
lna ilo
ść
cyfr
po przecinku to 6/
%3.8d
minimalna szeroko
ść
pola wyj
ś
ciowego – 3
maksymalna szeroko
ść
pola wyj
ś
ciowego - 8
//p_14
# include <stdio.h># include <conio.h>void main(void){int
n1;double d1;clrscr(); n1=123; d1=123.456789; printf("Format
całkowity domy
ś
lny %d\n",n1);
printf("j.w. ze spec. pracyzji %2.8d\n",n1);
printf("Format zmiennoprzecinkowy domy
ś
lny %f\n",d1);
printf("j.w. ze spec. praecyzji %10.2f\n",d1);
getch();
}
//p_15
# include <stdio.h># include <conio.h>void main(void){int n1;
24
float d1;
clrscr();
n1=123;
d1=123.456789;
printf("Format całkowity domy
ś
lny %d\n",n1);
printf("j.w. ze spec. pracyzji %2.8d\n",n1);
printf("Format zmiennoprzecinkowy domy
ś
lny %f\n",d1);
printf("j.w. ze spec. precyzji %10.2f\n",d1);
getch();
}
Operatory
Operator przypisania
= operator przypisania
operand_lewostronny = operand_prawostronny
warto
ść
operandu prawostronnego zostaje przypisana operandowi
lewostronnemu; przypisanie polega na umieszczeniu w obszarze
pami
ę
ci zarezerwowanym dla operandu lewostronnego warto
ś
ci
operandu prawostronnego;
x = 10;
y = a + 5;
25
Operatory arytmetyczne i operator przypisania
z = x + y;
x = x + y; ß à x += y
Poł
ą
czenie operatorów arytmetycznych z operatorem przypisania
tworzy w j
ę
zyku C
arytmetyczne operatory przypisania
+= operator przypisania z dodawaniem
-= operator przypisania z odejmowaniem
*= operator przypisania z mni
ż
eniem
/= operator przypisania z dzieleniem
%= operator przypisania reszty z dzielenia
x += y ß à x = x + y
x -= y ß à x = x - y
x *= y ß à x = x * y
x /= y ß à x = x / y
x %= y ß à x = x % y
z = z * x + y i z *= x + y nie s
ą
równowa
ż
ne ze wzgl
ę
du na
kolejno
ść
operacji
równowa
ż
ne s
ą
:
z *= x + y i z = z * ( x + y )
//p_16
# include <stdio.h># include <conio.h>void main(void){int
x,y,z;clrscr(); x=1; y=3; z=10; printf("x= %d y= %d z=
26
%d\n",x,y,z); x=x+y; printf("\nx=x+y przypisuje zmiennej x
warto
ść
%d\n",x);
x=1;
x+=y;
printf("\nx+=y przypisuje zmiennej x warto
ść
%d\n",x);
x=1;
x=x-y;
printf("\nx=x-y przypisuje zmiennej x warto
ść
%d\n",x);
x=1;
x-=y;
printf("\nx-=y przypisuje zmiennej x warto
ść
%d\n",x);
x=1;
z=z*x+y;
printf("\nz=z*x+y przypisuje zmiennej z warto
ść
%d\n",z);
z=10;
z=z*(x+y);
printf("\nz=z*(x+y) przypisuje zmiennej z warto
ść
%d\n",z);
z=10;
z*=x+y;
printf("\nz*=x+y przypisuje zmiennej z warto
ść
%d\n",z);
getch();
}
Jednoargumentowy operator zmiany znaku
Operandem tego operatora mo
ż
e by
ć
warto
ść
numeryczna całkowita
lub zmiennoprzecinkowa – stała b
ą
d
ź
zmienna.
27
Nie mo
ż
na myli
ć
jednoargumentowego operatora (-) z
dwuargumentowym operatorem (-) odejmowania.
W wyra
ż
eniu:
x - -y à pierwszy jest operatorem dwuargumentowym odejmowania,
za
ś
drugi minus operatorem jednoargumentowym zmiany znaku.
tj. x – (-y) à x + y
Zwi
ę
kszanie i zmniejszanie o 1. à Inkrementacja i
dekrementacja.
++ x ß à x = x+1 lub x += 1
-- x ß à x = x-1 lub x -= 1
Operatory inkrementacji i dekrementacji wystepuj
ą
w j
ę
zyku C w
dwóch wersjach ka
ż
dy :
++ x - operator pre-inkrementacji
x ++ - operator post-inkrementacji
-- x - operator pre-dekrementacji
x -- - operator post-dekrementacji
W przepadku pre- najpierw nast
ę
puje dodanie lub odjecie
jedynki a pó
ź
niej wykorzystanie zmiennej z now
ą
warto
ś
ci
ą
w
programie;
W przypadku post- najpierw nast
ę
puje wykorzystanie warto
ś
ci
zmiennej w programie a dopiero pó
ź
niej jej zwi
ę
kszenie lub
zmniejszenie o 1;
y = x ++;
1/ najpierw wykonane zostanie przypisanie y = x;
2/ potem x = x + 1;
praktycznie realizuje si
ę
to w nast
ę
puj
ą
cy sposób:
28
1/ program wykonuje kopie tymczasow
ą
zmiennej x;
2/ inkrementuje zmienn
ą
x , a nie tymczasow
ą
kopi
ę
;
3/ wykorzystuje tymczasowa kopie x do przypisania y = x;
//p_17
# include <stdio.h># include <conio.h>void main(void){int
x,y,z,w,wynik;clrscr(); x=y=z=w=1; printf("x = %d y = %d z =
%d w = %d\n",x,y,z,w); wynik=++x; printf("\n++x wynosi
%d\n",wynik); wynik=y++;
printf("\ny++ wynosi %d\n",wynik);
wynik=--z;
printf("\n--z wynosi %d\n",wynik);
wynik=w--;
printf("\nw-- wynosi %d\n",wynik);
getch();
}
Operatory relacji
Mi
ę
dzy wyra
ż
eniami w j
ę
zyku C mog
ą
wyst
ę
powa
ć
nast
ę
puj
ą
ce
relacje:
== równe
!= ró
ż
ne od
> wi
ę
ksze od
< mniejsze od
>= wi
ę
ksze lub równe
<= mniejsze lub równe
Wszystkie operatory relacji maj
ą
ni
ż
szy priorytet ni
ż
operatory arytmetyczne, co oznacza
ż
e najpierw zostan
ą
wykonane operacje arytmetyczne a nast
ę
pnie zostan
ą
dokonane
porównania warto
ś
ci.
29
Uj
ę
cie operacji w nawiasy powoduje ich wykonanie w pierwszej
kolejno
ś
ci.
W grupie operatorów logicznych, operatory > , < , >= , <= maja
wy
ż
szy priorytet ni
ż
== oraz != .
Je
ż
eli relacja jest prawdziwa to zwrócona zostanie warto
ść
1,
w przeciwnym przypadku warto
ść
0.
//p_18
# include <stdio.h># include <conio.h>void main(void){int
x,y;double z;clrscr(); x=7; y=25; z=24.46;
printf("x = %d y = %d z = %.2f\n",x,y,z);
printf("operacja %d >= %d daje wynik %d\n",x,y,x>=y);
printf("operacja %d == %d daje wynik %d\n",x,y,x==y);
printf("operacja %d < %.2f daje wynik %d\n",x,z,x<z);
printf("operacja %d > %.2f daje wynik %d\n",y,z,y>z);
printf("operacja %d != %d - 18 daje wynik %d\n",x,y,x!=y-18);
printf("operacja %d + %d != %.2f daje wynik
%d\n",x,y,z,x+y!=z);
getch();
}
1 / 2 + 1 / 2 == 1 à logiczny wynik 0 1 / 2 à 0
1.0 / 3.0 + 1.0 / 3.0 + 1.0 / 3.0 == 1 à logiczne 0 1.0 / 3.0
à 0.3333333
Operator rzutowania
W j
ę
zyku C mo
ż
na zamieni
ć
jeden typ danych na inny poprzez
poprzedzenie operandu operatorem rzutowania.
(typ_danych)x
typ danych na który ma zosta
ć
zamieniona warto
ść
x
30
(float)5 à 5.0
x=1;
(float)(x+2) à 3.0
//p_19
# include <stdio.h># include <conio.h>void main(void){int
x,y;clrscr(); x=8; y=5;printf("x = %d y = %d \n",x,y);
printf("operacja %d / %d daje wynik %d\n",x,y,x/y);
printf("operacja float(%d) / %d daje wynik
%f\n",x,y,float(x)/y);
getch();
}
Operacje p
ę
tli
P
ę
tla for ( ... )
for ( wyra
ż
enie1; wyra
ż
enie2; wyra
ż
enie3 )
{
instrukcja1;
instrukcja2;
instrukcja3;
...........
...........
}
31
wyra
ż
enie1 - wyra
ż
enie inicjuj
ą
ce p
ę
tli /wykonuje si
ę
tylko
raz/
wyra
ż
enie2 - wyra
ż
enie warunkowe 1 à wykonuje si
ę
p
ę
tla
à nie wykonuje si
ę
wyra
ż
enie3 - wykonuje si
ę
po ka
ż
dym przebiegu instrukcji
p
ę
tli, przed
sprawdzeniem warto
ś
ci wyra
ż
enia2;
//p_20
# include <stdio.h>
# include <conio.h>
void main(void)
{
int i;
clrscr();
printf("Kod 16 D.L. Kod 16 m.l. Kod 10 \n");
for (i=0;i<16;i++)
printf(" %X %x %d \n",i,i,i);
getch();
}
for (i=0; i<8; i++)
{
ciało p
ę
tli
}
for (i=0; i<8; i++ )
suma+=i;
32
for (i=0; i<8; i++ ); à p
ę
tla pusta
rozbudowana p
ę
tla for
for ( i=0, j=10; i<10, j>0; i++, j-- )
{
}
//p_21
# include <stdio.h>
# include <conio.h>
void main(void)
{
int i,j;
clrscr();
for (i=0,j=8;i<8;i++,j--)
printf("%d + %d = %d\n",i,j,i+j);
getch();
}
//p_22
# include <stdio.h>
# include <conio.h>
void main(void)
{
int i,j;
clrscr();
for (i=0,j=8;i<8,j>5;i++,j--)
33
printf("%d + %d = %d\n",i,j,i+j);
getch();
}
//p_23
# include <stdio.h>
# include <conio.h>
void main(void)
{
int i,j;
clrscr();
for (i=0,j=1;i<8;i++,j++)
printf("%d - %d = %d\n",j,i,j-i);
getch();
}
P
ę
tle niesko
ń
czone
for (;;)
{
ciało p
ę
tli
}
for(;;);
for(;1;);
for (;1;)
34
{
ciało p
ę
tli
}
//p_24
# include <stdio.h>
# include <conio.h>
void main(void)
{
int c;
clrscr();
printf("Wpisz znak - jesli wpiszesz znak <x> to koniec
programu\n");
for (c=' ';c!='x';)
{
c=getc(stdin);
putchar(c);
}
printf("\nKoniec programu\n");
getch();
}
P
ę
tla while
while(wyra
ż
enie)
{
instrukcja1;
instrukcja2;
35
)
Je
ż
eli wyra
ż
enie zwraca warto
ść
niezerow
ą
wykonywane s
ą
instrukcje wewn
ą
trz p
ę
tli. Po wykonaniu instrukcji p
ę
tli
wyra
ż
enie sprawdzane jest ponownie i je
ż
eli zwróci warto
ść
niezerowa instrukcje wewn
ą
trz p
ę
tli wykonywane s
ą
ponownie, a
ż
do chwili gdy po kolejnym sprawdzeniu wyra
ż
enie przyjmie
warto
ść
0.
//p_25
# include <stdio.h># include <conio.h>
void main(void)
{
int c;
clrscr();
printf("Wpisz znak - jesli wpiszesz znak <x> to koniec
programu\n");
while (c!='x')
{
c=getc(stdin);
putchar(c);
}
printf("\nKoniec programu\n");
getch();
}
Niesko
ń
czona p
ę
tla while
while(1)
{
instrukcja1;
instrukcja2;
36
}
//p_26
# include <stdio.h># include <conio.h>void main(void){int
c;clrscr(); printf("Wpisz znak\n"); while (1) { c=getc(stdin);
putchar(c); break; } printf("\nKoniec programu\n"); getch();}
Petla do - while
W p
ę
tlach for i while wyra
ż
enia warunkowe znajduj
ą
si
ę
w
nagłówku p
ę
tli. W p
ę
tli do-while odwrotnie – wyra
ż
enie
znajduje si
ę
na ko
ń
cu p
ę
tli. Dzieki temu instrukcje znajduj
ą
ce
si
ę
wewn
ą
trz p
ę
tli b
ę
d
ą
wykonywane przynajmniej jeden raz
zanim dojdzie do sprawdzenia warunku.
do
{
instrukcja1;
instrukcja2;
} while (wyra
ż
enie);
Instrukcja do-while zako
ń
czona jest srednikiem.
//p_26_1
#include <stdio.h>main(){ int i; i = 65; do { printf("The
numeric value of %c is %d.\n", i, i);
37
i++;
} while (i<72);
return 0;
}
P
ę
tle zagnie
ż
d
ż
one
Wstawianie jednej p
ę
tli wewn
ą
trz innej p
ę
tli nazywa si
ę
zagnie
ż
d
ż
eniem p
ę
tli.
//p_27
# include <stdio.h># include <conio.h>void main(void){int i,j;
clrscr(); for(i=1;i<=3;i++)
{
printf("Poczatek iteracji %d p
ę
tli zewnetrznej \n",i);
for(j=1;j<=4;j++)
printf("Iteracja %d petli wewnetrznej \n",j);
printf("Koniec iteracji %d petli zewnetrznej \n",i);
}
getch();
}
Zanim rozpocznie si
ę
kolejna iteracja p
ę
tli zawn
ę
trznej, musi
zosta
ć
zako
ń
czone wykonywanie p
ę
tli wewn
ę
trznej. Gdy
rozpocznie si
ę
kolejne wykonanie p
ę
tli zewn
ę
trznej, p
ę
tla
wewn
ę
trzna jest ponownie wykonywana zadan
ą
ilo
ść
razy.
//p_28
# include <stdio.h># include <conio.h>void main(void)
{
38
int i,j;
clrscr();
for(i=1;i<=3;i++)
{
printf("Poczatek iteracji %d p
ę
tli zewnetrznej \n",i);
for(j=1;j<=4;j++)
printf("Iteracja %d petli wewnetrznej \n",j);
printf("Koniec iteracji %d petli zewnetrznej \n",i);
}
getch();
}
Operatory - cd
Operator sizeof
sizeof(wyra
ż
enie)
wyra
ż
enie oznacza typ danych lub zmienn
ą
, warto
ść
jest zwraca
w bajtach;
//p_29
# include <stdio.h># include <conio.h>void main(void){char c='
';int i=0;float f=0.0f;double d=0.0;clrscr();
printf("Dane typu char zajmuj
Ą
: %d - bajt\n",sizeof(char));
printf("Zmienna typu char zajmuje %d - bajt\n",sizeof c);
printf("Dane typu int zajmuj
Ą
: %d - bajty\n",sizeof(int));
printf("Zmienna typu int zajmuje %d - bajty\n",sizeof i);
39
printf("Dane typu float zajmuj
Ą
: %d - bajty\n",sizeof(float));
printf("Zmienna typu float zajmuje %d - bajty\n",sizeof f);
printf("Dane typu double zajmuj
Ą
: %d -
bajt˘w\n",sizeof(double));
printf("Zmienna typu double zajmuje %d - bajt˘w\n",sizeof d);
getch();
}
podaj
ą
c operatorowi sam typ danych np. sizeof(int) lub
identyfikator zmiennej np. sizeof int_1; poniewa
ż
identyfikator zmiennej nie jest słowem kluczowym j
ę
zyka C
zatem mo
ż
emy pomin
ąć
nawiasy.
Operatory logiczne
&& - iloczyn logiczny (AND)
| | - suma logiczna (OR)
! - negacja logiczna (NOT)
s
ą
to operatory dwu (&& , || ) lub jednoargumentowe, których
argumentami s
ą
wyra
ż
enia b
ą
d
ź
warto
ś
ci logiczne;
Operator iloczynu logiczne (AND)
wyr1 && wyr2
wyr1 wyr2 wyr1 && wyr2
1 1 1
1 0 0
0 1 0
0 0 0
//p_30
# include <stdio.h>
# include <conio.h>
40
void main(void)
{
int num=0;
clrscr();
printf("Operator && zwraca: %d\n", (num%2==0)&&(num%3==0));
num =2;
printf("Operator && zwraca: %d\n", (num%2==0)&&(num%3==0));
num=3;
printf("Operator && zwraca: %d\n", (num%2==0)&&(num%3==0));
num=6;
printf("Operator && zwraca: %d\n", (num%2==0)&&(num%3==0));
getch();
}
Operator sumy logicznej (OR)
wyr1 | | wyr2
wyr1 wyr2 wyr1 | | wyr2
1 1 1
1 0 1
0 1 1
0 0 0
//p_31
41
# include <stdio.h>
# include <conio.h>
void main(void)
{
int num;
clrscr();
printf("Wpisz jednocyfrow
ą
liczbe podzieln
ą
\n przez 2 i przez
3\n");
for (num=1; (num%2!=0)||(num%3!=0);)
num=getchar()-48;
printf("Szukana liczba to : %d\n",num);
getch();
}
Operator logicznej negacji
! wyr
wyr ! wyr
1 0
0 1
//p_32
# include <stdio.h>
# include <conio.h>
void main(void)
{
int num;
42
clrscr();
num=7;
printf("Dana jest zmienna num o warto˜ci 7 \n");
printf("!(num<7) zwraca : %d\n",!(num<7));
printf("!(num>7) zwraca : %d\n",!(num>7));
printf("!(num==7) zwraca : %d\n",!(num==7));
getch();
}
//p_33
# include <stdio.h>
# include <conio.h>
void main(void)
{
int num;
clrscr();
printf("Wpisz jednocyfrow
ą
liczb
ę
podzieln
ą
\n przez 2 i przez
3\n");
for (num=1; !((num%2==0)&&(num%3==0));)
num=getchar()-48;
printf("Szukana liczba to : %d\n",num);
getch();
}
43
Logiczne operatory bitowe
& - bitowy iloczyn logiczny AND (I)
| - bitowa suma logiczna OR (LUB)
^ - bitowa alternatywa wył
ą
czna XOR (ALBO)
~ - bitowe uzupełnienie do 2 (komplementarne)
>> - przesuni
ę
cie bitów w prawo
<< - przesuni
ę
cie bitów w lewo
HEX Binarnie Dziesi
ę
tnie
0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
A 1010 10
B 1011 11
C 1100 12
D 1101 13
E 1110 14
F 1111 15
44
x & y
Operator & porównuje ka
ż
dy bit operandu x z odpowiednim bitem
operandu y. Je
ż
eli oba bity s
ą
równe 1 operator ustawia 1 na
tej samej pozycji bitu wyniku. Je
ż
eli cho
ć
by jeden z
porównywanych bitów jest równy 0 to bit wyniku jest 0.
& 11 à 01
x | y
Operator bitowy sumy logicznej (alternatywy zwykłej) ustawia
bit wyniku na 1 je
ż
eli cho
ć
by jeden z bitów operandu (lub oba)
jest równy 1.
| 11 à 11
x ^ y
Operator alternatywy wył
ą
cznej ustawia bit wyniku na 1 ,
je
ż
elili dokładnie jeden z bitów obu operandów jest równy 1.
^ 11 à 10
~ x
Operator negacji (inwersji bitowej) – dokonuj
ą
cy operacji na
pojedynczym operandzie - odwraca warto
ść
ka
ż
dego bitu
operandu.
~ 01 à 10
//p_34
# include <stdio.h># include <conio.h>void main(void){int
x,y,z;x=4321;y=5678;clrscr(); printf("Dana jezt zmienna x = %u
, czyli 0x%04X\n",x,x); printf("oraz zmienna y = %u , czyli
0x%04X\n",y,y);
z=x&y;
printf("x&y zwraca %6u , czyli 0x%04X\n",z,z);
z=x|y;
printf("x|y zwraca %6u , czyli 0x%04X\n",z,z);
45
z=x^y;
printf("x^y zwraca %6u , czyli 0x%04X\n",z,z);
printf("~x zwraca %6u , czyli x%04X\n",~x,~x);
getch();
}
Operatory przesuni
ę
cia bitowego
>> przesuwa bity operandu w prawo
<< przesuwa bity operandu w lewo
x >> y
x << y
x – operand, którego bity b
ę
d
ą
przesuwane
y – ilo
ść
miejsc o które nale
ż
y przesun
ąć
bity operandu
8 >> 2 à 1000>>2 à 0010 à 2
5 << 1 à 0101<<1 à 1010 à 10
//p_35
# include <stdio.h># include <conio.h>void main(void){int
x,y,z;x=255;y=5;clrscr(); printf("Dana jest zmienna x = %4d ,
czyli 0x%04X\n",x,x); printf("oraz zmienna y = %4d , czyli
0x%04X\n",y,y); z=x>>y; printf("x>>y zwraca %6d , czyli
0x%04X\n",z,z);
z=x<<y;
printf("x<<y zwraca %6d , czyli 0x%04X\n",z,z);
getch();
}
y > 0
x >> y ß à x / 2y
46
x << y ß à x * 2y
Operator warunkowy – jedynym operatorem trójargumentowym.
?: - operator warunkowy
x ? y : z
operandy x , y , z
x - wyra
ż
enie logiczne – wyra
ż
enie warunkowe
y - wyra
ż
enie wynikowe , które jest wykonywane gdy x zwraca
warto
ść
niezerow
ą
(np. 1)
z - wyra
ż
enie wynikowe, które jest wykonywane gdy x zwraca
warto
ść
0.
//p_36
# include <stdio.h># include <conio.h>void main(void){int
x;x=sizeof(int);clrscr(); printf("%s\n", (x==2) ? "Typ danych
int ma 2 bajty.":"Typ int nie ma 2 bajtów");
printf("Maksymalna wartosc liczby typu int to : %d\n", (x!=2)
? ~(1<<x*8-1): ~(1<<15));
getch();
}
Typy danych - modyfikatory
Bit znaku
47
Jeden bit liczby mo
ż
e by
ć
wykorzystany po to aby wskazywał czy
liczba jest dodatnia czy ujemna. Jest to tzw, bit znaku.
Modyfikator signed
Dla liczb całkowitych pierwszy od lewej bit jest u
ż
ywany jako
bit znaku. Je
ż
eli liczby całkowite typu int maj
ą
16 bitów, i
pierwszy bit od prawej jest okre
ś
lany bitem na pozycji 0 to
bit znaku znajduje si
ę
na pozycji 15. Je
ż
eli jego warto
ść
wynosi 0 to liczba jest dodatnia, za
ś
gdy 1 to liczba jest
ujemna.
Sposób implementacji liczb ujemnych zmiennopozycyjnych typu
float i double na razie pominiemy.
modyfikator signed jest u
ż
ywany dla wskazania, i
ż
jeden bit
danych jest bitem znaku;
deklaracja int à jest domyslnie traktowana jako signed int
deklaracja char à zakres warto
ś
ci 0 – 255 (28 – 1)
deklaracja signed char à zakres warto
ś
ci
od -128 (-27 )
do +127 (27 – 1)
Aby zamieni
ć
liczb
ę
dwójkow
ą
na równ
ą
jej co do warto
ś
ci
bezwzgl
ę
dnej lecz ujemn
ą
, nale
ż
y:
liczba 12 345 à 0011 0000 0011 1001
1/ znajdujemy kod odwrotny liczby:
1100 1111 1100 0110
2/ dodajemy 1
1100 1111 1100 0111
jest to kod dwójkowy liczby - 12 345
48
Modyfikator unsigned
modyfikator unsigned stosowany jest dla okre
ś
lenia , i
ż
pierwszy bit liczby nie jest jej bitem znaku;
mo
ż
e on by
ć
stosowany jako :
unsigned int
unsigned char
unsigned int x; à x: 0 , 65 535 (216 – 1)
Standard ANSI C pozwala na stosowanie przyrostków U i u przy
stałych bez znaku:
unsigned int x,y;
x = 1234U;
y = 0xABCFu;
//p_37
# include <stdio.h># include <conio.h>// funkcja druk_bin
drukuje binarny podany dzisi
ę
tnie argument x typu intvoid
druk_bin(int x){ int n; for (n=15;n>=0;n--) ((x>>n&1) ?
putchar('1') : putchar('0'));
}
void main(void)
{
signed char ch;
int x;
unsigned int y;
ch=0xFF;
x=0xFFFF;
y=0xFFFF;
clrscr();
49
printf("\nDziesi
ę
tnie ze znakiem 0xFF to : %d",ch);
printf("\nDziesi
ę
tnie ze znakiem 0xFFFF to : %d a binarnie
:",x);
druk_bin(0xFFFF);
printf("\nDziesietnie bez znaku 0xFFFF to : %u",y);
printf("\nDziesi
ę
tnie: 12345 to Hex: 0x%X i binarnie:
",12345);
druk_bin(12345);
printf("\nDziesi
ę
tnie: -12345 to Hex: 0x%X i binarnie: ",-
12345);
druk_bin(-12345);
getch();
}
Modyfikatory rozmiaru danych
Dla zmniejszenia lub zwi
ę
kszenia pami
ę
ci zajmowanej przez dane
słu
żą
modyfikatory short i long.
Modyfikator short
Modyyfikator short umo
ż
liwia np. w systemie 32 bitowym
skrócenie danych in z 32 bitów do 16 bitów
short x; oznacza short signed int x;
unsigned short x; oznacza short unsigned int x;
Modyfikator long
50
Modyfikator long poszerza zakres warto
ś
ci iprzez to dane
zajmuja wi
ę
cej miejsca w pami
ę
ci.
Je
ż
eli zmienna typu int zajmuje domy
ś
lnie 16 bitów to
modyfikator long int powi
ę
ksza wielko
ść
tej zmiennej do 32
bitów;
long int x; à -2147483648 (-231 ) do 2147483647 (231 – 1)
Standard ANSI C pozwala na dodawanie do stałych typu long
przyrostków L i l .
long int x,y;
x=123456789L;
y=0xABCD1234l;
//p_38
# include <stdio.h># include <conio.h>void
main(void){clrscr(); printf(" Rozmiar int: %d \n
",sizeof(int)); printf("Rozmiar short int: %d \n
",sizeof(short int)); printf("Rozmiar long int: %d \n
",sizeof(long int));
printf("Rozmiar float: %d \n ",sizeof(float));
printf("Rozmiar double: %d \n ",sizeof(double));
printf("Rozmiar long double: %d \n ",sizeof(long double));
getch();
}
short int - 2 bajty - 16 bitów - liczby całkowite krótkie
long int - 4 bajty - 32 bity - liczby całkowite długie
float - 4 bajty - 32 bity - liczby zmiennoprzecinkowe krótkie
double - 8 bajtów – 64 bity - liczby zmiennoprzecinkowe o
podwójnej
precyzji
long double - 10 bajtów - 80 bitów - liczby zmiennoprzecinkowe
długie
51
Specyfikatory formatu h l L
%hd %hi
dziesietnie, liczba całkowita krótka - short int
%hu
dziesi
ę
tnie, liczba całkowita krótka bez znaku - short
unsigned int
%ld %Ld
dziesi
ę
tnie, całkowita długa - long int
%lu %Lu
dziesi
ę
tnie, całkowita długa bez znaku - long unsigned int
//P_39
# include <stdio.h># include <conio.h>void main(void)
{
short int x;
unsigned int y;
long int s;
unsigned long int t;
x=0xFFFF;
52
y=0xFFFFU;
s=0xFFFFFFFFl;
t=0xFFFFFFFFL;
clrscr();
printf("Short int 0xFFFF to: %hd\n",x);
printf("Unsigned int 0xFFFF to: %u\n",y);
printf("Long int 0xFFFFFFFF to: %ld\n",s);
printf("Unsigned long int 0xFFFFFFFF to %lu\n",t);
getch();
}
Funkcje matematyczna
Grupy funkcji matematycznych
Trygonometryczne i hiperboliczne : sin() , cos() , cosh()
,......
53
Wykładnicze i logarytmiczne : exp() , pow() , log10() , .....
Pozostałe : ceil() , fabs() , floor() , ....
Wykorzystanie funkcji sin(), cos(), tan();
argumentem funkcji jest k
ą
t x w radianach
radiany = stopnie * (3.141593 / 180.0 )
#include <math.h>
double sin(double x);
double cos(double x);
double tan(double x);
//p_40
# include <stdio.h># include <conio.h># include <math.h>void
main(void){double x;x=45.0;x*=3.141593/180.0;clrscr();
printf("Sinus 45 : %f\n",sin(x)); printf("Cosinus 45 :
%f\n",cos(x));
printf("Tangens 45 : %f\n",tan(x));
getch();
}
Wywołanie funkcji : pow() i sqrt();
#include <math.h>
double pow(double a, double b);
double sqrt(double x);
//p_41
54
# include <stdio.h># include <conio.h># include <math.h>void
main(void){double x,y,z;x=64.0;y=3.0;z=0.5;clrscr();
printf("64 x 64 x 64 : %7.0f\n",pow(x,y));
printf("Pierw. kw. z 64 : %2.0f\n",sqrt(x));
printf("64 do pot
ę
gi 1/2 : %2.0f\n",pow(x,z));
getch();
}
Sterowanie programem
Instrukcja warunkowa if
if (wyra
ż
enie)
{
blok instrukcji
}
//p_42
# include <stdio.h>
# include <conio.h>
void main(void)
{
int i;
55
clrscr();
printf("Liczby caˆkowite podzielne przez 2 i przez 3\n");
printf("\tw zakresie od 0 do 100 \n");
for (i=0;i<=100;i++)
if((i%2==0)&&(i%3==0))
printf(" %d\n",i);
getch();
}
Instrukcja warunkowa if-else
if (wyra
ż
enie)
{
blok instrukcji
}
else
{
blok instrukcji
}
//p_43
# include <stdio.h>
# include <conio.h>
void main(void)
{
int i;
clrscr();
printf("Liczby parzyste Liczby nieparzyste\n");
56
for (i=0;i<10;i++)
if(i%2==0)
printf("%d",i);
else
printf("%30d\n",i);
getch();
}
Zagnie
ż
d
ż
one instrukcje warunkowe if
//p_44
# include <stdio.h>
# include <conio.h>
void main(void)
{
int i;
clrscr();
for (i=-5;i<=5;i++)
if(i>0)
if(i%2==0)
printf("%d to liczba parzysta \n",i);
else
printf("%d to liczba nieparzysta \n",i);
else
if (i==0)
57
printf("To jest zero\n");
else
printf("Liczba ujemna %d\n",i);
getch();
}
Instrukcja switch
switch (wyra
ż
enie)
{
case wyra
ż
enie1:
instrukcja1;
case wyra
ż
enie2:
instrukcja2;
...........
default:
instrukcja-domyslna;
}
Najpierw sprawdzana jest warto
ść
wyra
ż
enia (wyra
ż
enie
sterujace)
Je
ż
eli warto
ść
wyra
ż
enia jest równa wyra
ż
enie1 to wykonywana
jest instrukcja1, je
ż
eli jest równa wyra
ż
enie2 to wykonywana
jest isntrukcja2, itd.
58
wyra
ż
enie1, wyra
ż
enie2 i pozostałe wyra
ż
enia s
ą
wyra
ż
eniami
stałowarto
ś
ciowymi;
Je
ż
eli warto
ść
zwrócona przez wyra
ż
enie steruj
ą
ce nie jest
równa warto
ś
ci któregokolwiek z wyra
ż
e
ń
stałowarto
ś
ciowych,
zostanie wykonana instrukcja domyslna.
//p_45
# include <stdio.h>
# include <conio.h>
void main(void)
{
int day;
clrscr();
printf("Wpisz numer dnia z zakresu od 1 do 3\n");
day=getchar();
switch(day)
{
case '1':
printf("Dzie
ń
1\n");
case '2':
printf("Dzie
ń
2\n");
case '3':
printf("Dzie
ń
3\n");
default:
;
}
getch();
59
}
Instrukcja break
//p_45p
# include <stdio.h>
# include <conio.h>
void main(void)
{
int day;
clrscr();
printf("Wpisz numer dnia z zakresu od 1 do 3\n");
day=getchar();
switch(day)
{
case '1':
printf("Dzie
ń
1\n");
break;
case '2':
printf("Dzien 2\n");
break;
case '3':
printf("Dzie
ń
3\n");
break;
default:
;
60
}
getch();
}
//p_46
# include <stdio.h>
# include <conio.h>
void main(void)
{
int day;
clrscr();
printf("Wpisz numer dnia tygodnia od 1 do 7\n");
day=getchar();
switch(day)
{
case '1':
printf("Dzie
ń
1 - Niedziela\n");
break;
case '2':
printf("Dzie
ń
2 - Poniedziaˆek\n");
break;
case '3':
printf("Dzie
ń
3 - Wtorek\n");
break;
case '4':
printf("Dzie
ń
4 -
Ś
roda\n");
61
break;
case '5':
printf("Dzie
ń
5 - Czwartek\n");
break;
case '6':
printf("Dzie
ń
6 - Pi
ą
tek\n");
break;
case '7':
printf("Dzie
ń
7 - Sobota\n");
break;
default:
printf("Liczba spoza zakresu 1 - 7");
break;
}
getch();
}
Przerwanie p
ę
tli niesko
ń
czonej
for(;;)
{
instr1;
instr2;
......
}
while(1)
{
62
instr1;
instr2;
......
}
//p_47
# include <stdio.h>
# include <conio.h>
void main(void)
{
int c;
clrscr();
printf("Wpisz znak:\n");
printf("x + <Enter> = Koniec programu\n");
while (1)
{
c=getc(stdin);
if(c=='x')
break;
}
printf("Program zostaˆ przerwany - Koniec \n");
getch();
}
Instrukcja continue
63
Czasem zamist przerywa
ć
p
ę
tl
ę
, trzeba tylko pomin
ąć
pewn
ą
grup
ę
instrukcji, ale p
ę
tla powinna wykonywa
ć
si
ę
dalej.
Instrukcja continue powoduje natychmiastowy skok na pocz
ą
tek
p
ę
tli i poj
ę
cie próby ponownego wykonania p
ę
tli od pocz
ą
tku.
//p_48
# include <stdio.h>
# include <conio.h>
void main(void)
{
int i,sum;
clrscr();
sum=0;
for(i=1;i<8;i++)
{
if((i==3) || (i==5))
continue;
sum+=i;
}
printf("Suma liczb 1 2 3 4 6 i 7 wynosi: %d\n",sum);
getch();
}
Instrukcja goto
etykieta:
instrukcja1;
instrukcja2;
.........
64
goto etykieta;
etykieta pokazuje w które miejsce w programie ma nastapi
ć
skok
po wykonaniu instrukcji goto;
etykieta wyst
ę
puje w dwóch miejscach:
1/ ze znakiem : w miejscu do którego nastepuje skok (etykietaJ
2/ po instrukcji goto (goto etykieta:)
Wska
ź
niki
adres w pami
ę
ci = zmienna = stała
warto
ść
lewostronna warto
ść
prawostronna
zmiennej zmiennej
deklaracja nadaje zmiennej warto
ść
lewostronn
ą
–
przyporz
ą
dkowuj
ą
c jej adres w pami
ę
ci;
int x;
podstawienie nadaje zmiennej warto
ść
prawostronn
ą
– umiesza w
zarezerwowanym dla zmiennej obszarze pami
ę
ci dane;
65
x=10;
Operator adresowy &
Operator adresowy zwraca warto
ść
lewostronn
ą
zmiennej
long int x,y;
y=&x;
przypisuje zmiennej y adres zmiennej x;
// p_49
# include <stdio.h># include <conio.h>void main(void){char
c;int x;float y;clrscr(); printf("c: adres=0x%p,
zawarto
ść
=%c\n",&c,c); printf("x: adres=0x%p,
zawarto
ś
c=%d\n",&x,x); printf("y: adres=0x%p,
zawarto
ś
c=%5.2f\n",&y,y);
c='A';
x=7;
y=123.45;
printf("c: adres=0x%p, zawarto
ść
=%c\n",&c,c);
printf("x: adres=0x%p, zawarto
ś
c=%d\n",&x,x);
printf("y: adres=0x%p, zawarto
ść
=%5.2f\n",&y,y);
getch();
66
}
specyfikator formatu %p /’pointer’/ u
ż
ywany jest dla
wyprowadzania adresów zmiennych;
Deklaracja wska
ź
ników
Wska
ź
nik to zmienna, w której przechowywany jest adres innej
zmiennej.
warto
ść
lewostronna warto
ść
prawostronna
wska
ż
nika to jego = wska
ź
nik = to adres innej zmiennej
adres
słu
ż
y do odwołania si
ę
67
do samego wska
ź
nika
deklaracja wska
ż
nika
typ danych * nazwa_wska
ź
nika
typ danych , których adres operator jednoargumentowy
przechowywał b
ę
dzie wska
ź
nik
// p_50
68
# include <stdio.h># include <conio.h>void main(void){char
c,*ptr1;int x,*ptr2;float y,*ptr3;clrscr(); c='A'; x=7;
y=123.45; printf("c: adres=0x%p, zawarto
ść
=%c\n",&c,c);
printf("x: adres=0x%p, zawarto
ść
=%d\n",&x,x);
printf("y: adres=0x%p, zawarto
ść
=%5.2f\n",&y,y);
ptr1=&c;
printf("ptr_c adres=0x%p, zawiera=0x%p\n",&ptr1,ptr1);
printf("*ptr_c => %c\n",*ptr1);
ptr2=&x;
printf("ptr_x adres=0x%p, zawiera=0x%p\n",&ptr2,ptr2);
printf("*ptr_x => %d\n",*ptr2);
ptr3=&y;
printf("ptr_y adres=0x%p, zawiera=0x%p\n",&ptr3,ptr3);
printf("*ptr_y => %5.2f\n",*ptr3);
getch();
}
69
Operator dereferencji * /operator jednoargumentowy – unarny/
Poł
ą
czenie oparatora dereferencji * oraz nazwy wska
ź
nika
powoduje odwołanie do prawostronnej warto
ś
ci zmiennej
wskazywanej.
char c; - deklaracja zmiennej
char *ptrc; - deklaracja wska
ź
nika
ptrc=&c; - zainicjowanie wska
ź
nika
odwołanie do zmiennej c:
przez nazw
ę
c - bezpo
ś
rednie
przez *ptrc - posrednie ; przez wska
ź
nik
printf(”%c”,c) to samo co printf(”%c”,*ptrc)
int x=1234, *ptrx;
ptrx=&x;
printf(”%d”,(*ptrx+1)); à 1235
Wska
ż
nik pusty - to wska
ź
nik o prawostronnej warto
ś
ci = 0;
char *ptrc;
70
int *ptrx;
ptrc=ptrx=0;
puste wska
ź
niki
Modyfikowanie zawarto
ś
ci zmiennej przez wska
ź
niki:
// p_51
# include <stdio.h># include <conio.h>void main(void){char
c,*ptr_c;clrscr(); c='A'; printf("c: adres=0x%p,
zawarto
ść
=%c\n",&c,c);
ptr_c=&c;
printf("ptr_c adres=0x%p, zawiera=0x%p\n",&ptr_c,ptr_c);
printf("*ptr_c => %c\n",*ptr_c);
*ptr_c='B';
printf("ptr_c adres=0x%p, zawiera=0x%p\n",&ptr_c,ptr_c);
printf("*ptr_c => %d\n",*ptr_c);
printf("c: adres=0x%p, zawiera=%c\n",&c,c);
getch();
}
Wskazanie tego samego adresu.
Ten sam adres w pami
ę
ci mo
ż
e by
ć
wskazywany przez wi
ę
cej ni
ż
jeden wska
ź
nik.
71
char p1,p2;
char zmienna;
p1=&zmienna;
p2=&zmienna;
//p_52
# include <stdio.h># include <conio.h>void main(void){int
x;int *ptr_1,*ptr_2,*ptr_3;clrscr(); x=1234;
printf("x: adres=0x%p, zawarto˜†=%d\n",&x,x);
ptr_1=&x;
printf("ptr_1 adres=0x%p, zawiera=0x%p\n",&ptr_1,ptr_1);
printf("*ptr_1 => %d\n",*ptr_1);
ptr_2=&x;
printf("ptr_2 adres=0x%p, zawiera=0x%p\n",&ptr_2,ptr_2);
printf("*ptr_2 => %d\n",*ptr_2);
ptr_3=ptr_1;
printf("ptr_3 adres=0x%p, zawiera=0x%p\n",&ptr_3,ptr_3);
printf("ptr_3 => %d\n",*ptr_3);
getch();
}
Tablice
Zestaw danych tego samego typu, posiadaj
ą
cych podobne
przeznaczenie nazywany jest tablic
ą
.
Ka
ż
da zmienna wchodz
ą
ca w skł
ą
d tablicy nazywa si
ę
jej
elementem. Do wszystkich elementów tablicy mo
ż
na odwoływac si
ę
poprzez t
ę
sama nazw
ę
tablicy, zajmuj
ą
one poło
ż
one koło
siebie miejsca w pami
ę
ci.
72
Deklaracja tablicy :
typ_danych nazwa_tablicy[rozmiar_tablicy];
wspólny typ identyfikator ilo
ść
elementów tablicy
np. tablica danych numerycznych 10-elementowa
int tab[10];
Indeksowanie elementów tablicy :
int tab[9];
element – 1 tab[0]
element - 2 tab[1]
..........
element - 9 tab[8]
wyra
ż
enia umieszczone w nawiasach umo
ż
liwiaj
ą
odwołanie do
elementów tablicy - s
ą
nazywane referencjami do elementów
tablicy;
Inicjowanie tablic
1/ przez referencje do elementów i operator podstawienia :
tab[6]=12;
2/ jednoczesnie :
int tab[5] = {2,4,3,66,1};
73
//p_53
# include <stdio.h># include <conio.h>void main(void){int
i;int Tab[10];clrscr(); for(i=0;i<10;i++)
{
Tab[i]=i+1;
printf("Element tablicy Tab[%d] ma warto
ść
: %d. \n",i,Tab[i]);
}
getch();
}
Rozmiar tablicy
Obszar pami
ę
ci zajmowany przez tablic
ę
– adres jej pierwszego
i ostatniego elementu.
// p_54
# include <stdio.h># include <conio.h>void main(void){int
total;int list[10];clrscr(); total=sizeof(int)*10;
printf("Element typu int zajmuje %d - bajty \n",sizeof(int));
printf("Cała tablica zajmuje %d bajt˘w \n",total);
printf("Adres pierwszego elementu tablicy: 0x%x\n",&list[0]);
printf("Adres ostatniego elementu tablicy : 0x%x\n",&list[9]);
getch();
}
- operator adresowy & zwraca adres elementu tablicy
typ_danych nazwa_tablicy[rozmiar_tablicy];
Ilo
ść
bajtów zajmowanych przez tablic
ę
to :
sizeof(typ_danych) * rozmiar_tablicy
lub
74
sizeof(nazwa_tablicy)
Wska
ź
nikowanie tablic
//p_55
# include <stdio.h># include <conio.h>void main(void){int
*ptr_int;int list_int[10];int i;clrscr(); for(i=0;i<10;i++)
list_int[i]=i+1; ptr_int=list_int; printf("Adres startowy
tablicy 0x%p\n",ptr_int);
printf("Warto
ść
pierwszego elementu tablicy %d\n",*ptr_int);
ptr_int=&list_int[0];
printf("Adres pierwszego elementu : 0x%p\n",ptr_int);
printf("Warto
ść
pierwszego elementu : %d\n",*ptr_int);
getch();
}
podstawienie pod wska
ź
nik adres pierwszego elementu tablicy
p_tab=&tab[0];
podstawienie pod wska
ź
nik nazwy tablicy;
p_tab=tab;
wykorzystanie nazwy tablicy jako adresu jej pierwszego
elementu
// p_55p
# include <stdio.h># include <conio.h>void main(void)
{
int *ptr_int;
int list_int[10];
int i;
75
clrscr();
for(i=0;i<10;i++)
list_int[i]=i+1;
ptr_int=list_int;
printf("Adres startowy tablicy 0x%p\n",ptr_int);
printf("Warto
ść
pierwszego elementu tablicy %d\n",*ptr_int);
ptr_int=&list_int[0];
printf("Adres pierwszego elementu : 0x%p\n",ptr_int);
printf("Adres drugiego elementu : 0x%p\n",ptr_int+1);
printf("Warto
ść
pierwszego elementu : %d\n",*ptr_int);
printf("Warto
ść
drugiego elementu : %d\n",*(ptr_int+1));
getch();
}
Tablice znakowe
Tablice znakowe posiadaj
ą
elementy, z których ka
ż
dy zajmuje 1
bajt; zatem rozmiar tablicy jest jednocze
ś
nie obszarem w
bajtach zajmowanym przez tablic
ę
;
W j
ę
zyku C ła
ń
cuchy znaków (teksty) s
ą
okre
ś
lane jako
jednowymiarowe tablice znakowe, w których ostatni element to
tzw. znak zerowy, oznaczany symbolicznie ‘\0’ o kodzie ASCII =
0.
//p_56
# include <stdio.h>
# include <conio.h>
void main(void)
{
char tab_ch[7]={'W','i','t','a','j','!','\0'};
76
int i;
clrscr();
for(i=0;i<7;i++)
printf("Tab_ch[%d] zawiera %c\n",i,tab_ch[i]);
// Metoda I
printf("Wszystkie elementy razem - metoda I: \n");
for(i=0;i<7;i++)
printf("%c",tab_ch[i]);
// Metoda II
printf("\nWszystkie elementy razem - metoda II: \n");
printf("%s\n",tab_ch);
getch();
}
Znak zerowy ‘\0’
Jest to pojedynczy znak specjalny okre
ś
laj
ą
cy koniec ła
ń
cucha
znakowego. Funkcja printf() przetwarzaj
ą
c ła
ń
cuch znaków w
formacie %s przetwarza znak po znaku, a
ż
do napotkania znaku
zerowego. Zank zerowy uto
ż
samiany z fałszem mo
ż
e by
ć
równie
ż
stosowany to testowania warto
ś
ci logicznej w p
ę
tlach
steruj
ą
cych.
//p_57
# include <stdio.h>
# include <conio.h>
void main(void)
{
char tab_ch[18]={'C',' ',
77
't','o',' ',
'j','
ę
','z','y','k',' ',
'p','r','o','g','r','.','\0'};
int i;
clrscr();
for(i=0;tab_ch[i]!='\0';i++)
printf("%c",tab_ch[i]);
getch();
}
Tablice wielowymiarowe
typ_danych
nazwa_tablicy[rozmiar_tab1][rozmiar_tab2]....[rozm_tabN];
N - jest całkowite i dodatnie
tablica dwuwymiarowa 2 x 3 :
int tab [2][3];
inicjowanie :
tab[0][0] = 1;
tab[0][1] = 2;
tab[0][2] = 3;
tab[1][0]= 4;
tab[1][1] = 5;
tab[1][2] = 6;
lub
int tab[2][3] = {1,2,3,4,5,6};
78
lub
int tab[2][3] = { {1,2,3},{4,5,6}};
/p_58
# include <stdio.h>
# include <conio.h>
void main(void)
{
int tab[3][5]={1,2,3,4,5,
10,20,30,40,50,
100,200,300,400,500};
int i,j;
clrscr();
for(i=0;i<3;i++)
{
printf("\n");
for(j=0;j<5;j++)
printf("%6d",tab[i][j]);
}
getch();
}
//p_59
# include <stdio.h>
# include <conio.h>
void main(void)
{
int tab[3][5]={1,2,3,4,5,10,20,30,40,50,100,200,300,400,500};
79
int i,j;
clrscr();
for(i=0;i<3;i++)
{
printf("\n");
for(j=0;j<5;j++)
printf("%6d",tab[i][j]);
}
getch();
}
//p_60
# include <stdio.h>
# include <conio.h>
void main(void)
{
int
tab[3][5]={{1,2,3,4,5},{10,20,30,40,50},{100,200,300,400,500}}
;
int i,j;
clrscr();
for(i=0;i<3;i++)
{
printf("\n");
for(j=0;j<5;j++)
printf("%6d",tab[i][j]);
}
80
getch();
}
//p_61
# include <stdio.h>
# include <conio.h>
void main(void)
{
int
tab[][5]={{1,2,3,4,5},{10,20,30,40,50},{100,200,300,400,500}};
int i,j;
clrscr();
for(i=0;i<3;i++)
{
printf("\n");
for(j=0;j<5;j++)
printf("%6d",tab[i][j]);
}
getch();
}
Tablice bezwymiarowe
Mo
ż
emy deklarowac tablic
ę
bez wpisywania jej rozmiaru w
nawiasach kwadratowych. Kompilator mo
ż
e sam obliczy
ć
rozmiar
tablicy je
ż
eli zadeklarowana zostanie jako bezwymiarowa,
int tab[] = {12,45,56,78,34,2,34,5,6,78,98};
81
w przypadku tablic wielowymiarowych bez wymiaru mo
ż
na
pozostawi
ć
tylko jeden wymiar (pierwszy z lewej);
int tab_2[ ][4] = {
‘a’,’A’,
‘b’,’B’,
‘c’,’C’,
‘d’,’D’};
//p_62
# include <stdio.h>
# include <conio.h>
void main(void)
{
char tab_ch[]={'C',' ',
't','o',' ',
'j','
ę
','z','y','k','\0'};
int
tab[][5]={{1,2,3,4,5},{10,20,30,40,50},{100,200,300,400,500}};
clrscr();
printf("Rozmiar tablicy tab_ch[] wynosi %d
bajt˘w.\n",sizeof(tab_ch));
printf("Rozmiar tablicy tab[][5] wynosi %d
bajt˘w.\n",sizeof(tab));
getch();
}
82
Ła
ń
cuchy znakowe
Ła
ń
cuch znakowy czyli string to tablica znakowa, której
ostatnim elementem jest znak ‘\0’.
Szereg znaków uj
ę
ty w cudzysłów (” ”) jest nazywany stał
ą
ła
ń
cuchow
ą
lub stał
ą
tekstow
ą
, kompilator mo
ż
e automatycznie
doda
ć
znacznik ko
ń
ca [\0].
char tab1[5] = {‘J’,’a’,’n’,’e’,’k’};
char tab2[6] = {‘J’,’a’,’n’,’e’,’k’,’\0’};
tab1 - jest traktowana jako tablica znakowa
tab2 - jest teraz tak
ż
e traktowana jako ła
ń
cuch znakowy
poniewa
ż
posiada znacznik ko
ń
ca ła
ń
cucha;
char tab3[6] = ”Janek”;
kompilator automatycznie doda znak ‘\0’;
inicjowanie tablicy przy pomocy stałej ła
ń
cuchowej oraz
inicjacja tab2 s
ą
równowa
ż
ne;
Stałe ła
ń
cuchowe i stałe znakowe
Stała ła
ń
cuchowa to szereg znaków uj
ę
tych w znak (” ”);
Stał
ą
znakowa to pojedynczy znak umieszczony w (‘ ’);
char znak = ‘x’;
char string = ”x”;
zadeklarowanie zmiennej znakowej znak powoduje zarezerwowanie
w pami
ę
ci 1 bajtu;
83
zadeklarowanie zmiennej ła
ń
cuchowej string powoduje
zarezerwowanie 2 bajtów : dla znaku ‘x’ i dla znacznika ko
ń
ca
ła
ń
cucha;
Ła
ń
cuch znakowy jest traktowany jako wska
ź
nik do zmiennej typu
char (wskazuj
ą
cy pierwszy znak ła
ń
cucha).
Dlatego identyfikator ła
ń
cucha znakowego mo
ż
na przypisa
ć
wska
ź
nikowi wprost bez stosowania operatora adresowego;
char *ptr_str;
ptr_str = ”Ła
ń
cuch znakowy”;
Za
ś
stałej znakowej nie mo
ż
na w ten sposób przypisa
ć
:
char *ptr_str;
ptr_str = ‘x’; /operator przypisania próbuje przypisa
ć
prawostronna
warto
ść
(‘x’), natomiast wska
ź
nik oczekuje warto
ś
ci
lewostronnej (adresu)/
Natomiast prawidłowe jest :
char *ptr_str;
*ptr_str = ‘x’;
wykorzystanie wska
ź
nika do przypisania mu ła
ń
cucha znaków
// p_63
# include <stdio.h># include <conio.h>void main(void){char
str1[]={'S','t','a','ł','a',' ',
'ł','a','
ń
','c','u','c','h','o','w','a','\0'};char
str2[]="Druga stała ła
ń
cuchowa";char *ptr_str;
int i;
clrscr();
// wydruk str1
for(i=0;str1[i];i++) // str1[i]=='\0' - synonim fałszu
printf("%c",str1[i]);
84
printf("\n");
// wydruk str2
for(i=0;str2[i];i++)
printf("%c",str2[i]);
printf("\n");
// przypisanie ła
ń
cucha do wska
ź
nika
ptr_str="Przypisanie ła
ń
cucha do wska
ź
nika";
for(i=0;*ptr_str;i++) à i jest zb
ę
dne
printf("%c",*ptr_str++);
getch();
}
Długo
ść
ła
ń
cucha znaków
Ile znaków zawiera ła
ń
cuch ?
Funkcja strlen()
#include <string.h>
size_t strlen(const char *s)
ilo
ś
c bajtów wska
ź
nik do ła
ń
cucha znaków
zajmowanych przez /identyfikator ła
ń
cucha/
ła
ń
cuch
85
//p_64
# include <stdio.h># include <conio.h># include <string.h>void
main(void){char str1[]={'S','t','a','ł','a',' ',
'ł','a','
ń
','c','u','c','h','o','w','a','\0'};
char str2[]="Druga stała ła
ń
cuchowa";
char *ptr_str="Przypisanie ła
ń
cucha do wska
ź
nika";
clrscr();
printf("Długo
ść
str1 wynosi: %d bajt˘w\n",strlen(str1));
printf("Długo
ść
str2 wynosi: %d bajt˘w\n",strlen(str2));
printf("Długo
ść
ła
ń
cucha przypisanego wska
ź
nikowi: %d
bajt˘w\n",strlen(ptr_str));
getch();
}
Kopiowanie ła
ń
cuchów – strcpy()
#include <string.h>
char *strcpy(char *dest, const char *src);
src à dest
kopiowanie ła
ń
cuchów bez u
ż
ycia wska
ź
ników
// p_65
# include <stdio.h># include <conio.h># include <string.h>void
main(void)
{
char str1[]="Kopiowanie ła
ń
cuchów";
char str2[25];
86
char str3[25];
int i;
clrscr();
// kopiowanie przy pomocy strcpy()
strcpy(str2,str1);
// kopiowanie bez uzycia strcpy()
for(i=0;str1[i];i++)
str3[i]=str1[i];
str3[i]='\0';
printf("Zawarto
ść
str2 : %s\n",str2);
printf("Zawarto
ść
str3 : %s\n",str3);
getch();
}
kopiowanie ła
ń
cuchów z wykorzystaniem wska
ź
ników
// p_65p
# include <stdio.h># include <conio.h># include <string.h>void
main(void){char str1[]="Kopiowanie ła
ń
cuchów";
char str2[25];
char str3[25];
int i;
clrscr();
// kopiowanie przy pomocy strcpy()
strcpy(str2,str1);
// kopiowanie bez uzycia strcpy()
for(i=0;*(str1+i);i++)
*(str3+i)=*(str1+i);
87
*(str3+i)='\0';
printf("Zawarto
ść
str2 : %s\n",str2);
printf("Zawarto
ść
str3 : %s\n",str3);
getch();
}
Odczyt i zapis ła
ń
cuchów znakowych
gets() - odczyt ła
ń
cuchów tekstowych ze standardowego
strumienia wej
ś
ciowego stdin
#include <stdio.h>
char *gets(char *s);
s – identyfikator tablicy znakowej, w której przechowywane s
ą
znaki wczytane ze standardowego wej
ś
cia;
gets() ko
ń
czy swoje działanie po wczytaniu ze standardowego
wej
ś
cia znaku przej
ś
cia do nast
ę
pnej linii (naci
ś
ni
ę
cie
Entera), albo po wczytaniu EOF – (koniec pliku) . Funkcja
dodaje do tablicy znakowej znacznik ‘\0’ i zwraca wska
ź
nik do
tablicy s, do której zapisała znaki, lub wska
ź
nik pusty je
ś
li
operacja nie powiodła si
ę
.
puts() - zapis ł
ąń
cuchów tekstowych do standardowego
strumienia wyj
ś
ciowego stdout
#include <stdio.h>
char puts(const char *s)
s – tablica (lub wska
ź
nik) odwołuj
ą
ca si
ę
do ła
ń
cucha
znakowego, który ma zosta
ć
wysłany do standardowego strumienia
(urz
ą
dzenia) wyj
ś
ciowego.
Funkcja puts() likwiduje znacznik ko
ń
ca ła
ń
cucha tekstowego,
dodaj
ą
c w jego miejsce znak przej
ś
cia do nowego wiersza.
we wprowadzonym tek
ś
cie zamiana małych liter na du
ż
e – bez
wska
ź
ników
88
//p_66
# include <stdio.h># include <conio.h># include <string.h>void
main(void){char str[80];int i;clrscr(); printf("Wprowad
ź
ła
ń
cuch do max. 80 znaków\n");
gets(str);
i=0;
while(str[i])
{
if((str[i]>=97)&&(str[i]<=122))
str[i]-=32;
i++;
}
printf("Wprowadzony tekst po zamianie małych liter na du
ż
e
\n");
puts(str);
getch();
}
we wprowadzonym tek
ś
cie zamiana małych liter na du
ż
e – ze
wska
ź
nikami
//p_66p
# include <stdio.h>
# include <conio.h>
# include <string.h>
void main(void)
{
89
char str[80];
int i;
clrscr();
printf("Wprowad
ź
ła
ń
cuch do max. 80 znak˘w\n");
gets(str);
i=0;
while(*(str+i))
{
if((*(str+i)>=97)&&(*(str+i)<=122))
*(str+i)-=32;
i++;
}
printf("Wprowadzony tekst po zamianie małych liter na du
ż
e
\n");
puts(str);
getch();
}
Specyfikator %s w funkcji printf() à wydrukowanie na ekranie
ła
ń
cucha znakowego.
Funkcja scanf()
Podobnie jak printf() funkcja scanf() słu
ż
y do wczytywania
danych ró
ż
nego typu.
# include <stdio.h>
int scanf(const char *format,[adres,......]);
90
w ła
ń
cuchu formatuj
ą
cym mog
ą
znale
źć
si
ę
wszystkie
specyfikatory formatu, w tym %s. Je
ż
eli działanie funkcji
scanf() jest poprawne funkcja zwraca liczb
ę
wczytanych
elementów (nie bajtów), ze strumienia stdin.
W przypadku bł
ę
du zwraca EOF.
U
ż
ycie specyfikatora formatu %s nakazuje funkcji scanf()
wczyta
ć
dane ze standardowego wej
ś
cia traktuj
ą
c je jako
ła
ń
cuch znaków. Wczytywanie danych przez funkcje scanf()
zostaje zako
ń
czone je
ż
eli w strumieniu znaków wej
ś
ciowych
pojawi si
ę
jeden z nastepuj
ą
cych znaków : spacja, znak nowego
wiersza, tabulator, tabulacja pionowa, FF – znak ko
ń
ca strony.
Znaki wczytywane przez funkcj
ę
s
ą
przechowywane w tablicy
znakowej, która musi zosta
ć
wskazana funkcji jako jej
argument. Tablica powinna by
ć
wystarczaj
ą
co du
ż
a aby pomie
ś
ci
ć
wszystkie wczytane znaki.
Po zako
ń
czeniu wczytania ła
ń
cucha znaków jako ostatni element
tablicy znakowej zostaje automatyczne dodany znacznik ‘\0’.
//p_67
# include <stdio.h># include <conio.h># include <string.h>void
main(void)
{
char str[80];
int i;
clrscr();
printf("Wprowad
ź
ła
ń
cuch do max. 80 znak˘w\n");
gets(str);
i=0;
while(str[i])
{
if((str[i]>=97)&&(str[i]<=122))
str[i]-=32;
i++;
91
}
printf("Wprowadzony tekst po zamianie małych liter na du
ż
e
\n");
puts(str);
printf("\n%s",str);
getch();
}
//p_68
# include <stdio.h># include <conio.h># include <string.h>
void main(void){char str[80];int i;clrscr(); printf("Wprowad
ź
ła
ń
cuch do max. 80 znak˘w\n");// gets(str);
scanf("%s",&str);
i=0;
while(str[i])
{
if((str[i]>=97)&&(str[i]<=122))
str[i]-=32;
i++;
}
printf("Wprowadzony tekst po zamianie małych liter na du
ż
e
\n");
puts(str);
printf("\n%s",str);
getch();
}
92
//p_69
# include <stdio.h># include <conio.h>
# include <string.h>
void main(void)
{
char str[80];
int x,y;
float z;
clrscr();
printf("Po wpisaniu danych dowolnego typu naci
ś
nij
<Enter>\n");
printf("Wpisz dwie liczby całkowite:\n");
scanf("%d %d",&x,&y);
printf("Wpisz liczb
ę
zmiennoprzecinkow
ą
: \n");
scanf("%f",&z);
printf("Wpisz ła
ń
cuch znaków: \n");
scanf("%s",str);
printf("Wpisałe
ś
nast
ę
puj
ą
ce dane: \n");
printf("%d %d\n%f\n%s\n",x,y,z,str);
getch();
}
Po napotkaniu spacji wczytywanie znaków funkcja scanf()
zostaje przerwane.
93
Funkcja scanf nie wczytuje znaków z wej
ś
cia dopóki nie
zostanie naci
ś
niety klawisz ENTER ( do tego czasu znaki
znajduj
ą
si
ę
w buforze wej
ś
ciowym ).
Widoczno
ść
zmiennych
W zło
ż
onym programie mog
ą
by
ć
zmienne, z których korzystaj
ą
ró
ż
ne funkcje, a z drugiej strony u
ż
ycie niektórych zmiennych
mo
ż
e ogranicza
ć
si
ę
tylko do pojedynczych funkcji. Oznacza to
ż
e widoczno
ść
i dost
ę
pno
ść
tych zmiennych mo
ż
e by
ć
ograniczona, a warto
ś
ci przypisane tym zmiennym mog
ą
by
ć
ukryte z punktu widzenia innych funkcji.
W j
ę
zyku C mo
ż
na deklaruj
ą
c zmienn
ą
okre
ś
li
ć
zakres jej
dost
ę
pno
ś
ci i widoczno
ś
ci. Zmienne dost
ę
pne tylko lokalnie s
ą
dost
ę
pne tylko wewn
ą
trz tego bloku programu , w którym zostały
zadeklarowane.
Zmienne lokalne /blokowe/
Zmienna zadeklarowana wewnatrz bloku programu ma zasi
ę
g
blokowy. Jest ona dostepna od miejsca zadeklarowania do ko
ń
ca
bloku w którym zastała zadeklarowana. Takie zmienne nazywaj
ą
si
ę
lokalnymi lub blokowymi.
//p_70
# include <stdio.h># include <conio.h># include <string.h>
void main(void)
{
int i=32;
clrscr();
printf("W bloku zewnetrznym i=%d\n",i);
{
int i,j;
printf("W bloku wewn
ę
trznym \n");
94
for (i=0,j=10;i<=10;i++,j--)
printf("i=%2d, j=%2d\n",i,j);
}
printf("Znowu w bloku zewn
ę
trznym: i=%d\n",i);
getch();
}
P
ę
tla for modyfikuje i wyprowadza warto
ś
ci zmiennych lokalnych
bloku wewn
ę
trznego, jednak
ż
e po zako
ń
czeniu i wyj
ś
ciu z tego
bloku lokalna zmienna i (wewn
ę
trzna) przestaje by
ć
dost
ę
pna.
Ponownie widoczna jest zewn
ę
trzna zmienna i, która nie uległa
zmianie. Dzi
ę
ki umiej
ę
tno
ś
ci ograniczania zakresu dost
ę
pno
ś
ci
zmiennych , nie nast
ą
piło ani nadpisanie warto
ś
ci ani
konflikt.
Zmienne widoczne w obr
ę
bie funkcji
Zmienne wewn
ę
trzne funkcji to takie zmienne, które s
ą
dost
ę
pne
i aktywne tylko pomi
ę
dzy pocz
ą
tkiem a ko
ń
cem danej funkcji.
W j
ę
zyku C tylko goto label ma taki zasi
ę
g. Je
ż
eli etykieta
przyporz
ą
dkowana instrukcji goto jako docelowy adres skoku
b
ę
dzie nazywa
ć
si
ę
start, to w obrebie funkcji main() jest
widoczna i dostepna z dowolnego punktu, czyli jej adres
widoczno
ś
ci to cała funkcja
int main()
{
int i;
....
start:
.....
goto start;
.....
return 0;
}
95
Etykieta start jest widoczna od poczatku do konca funkcji
main(), dlatego w obr
ę
bie funkcji main() nie mo
ż
e wystapi
ć
druga etykieta o nazwie start: (natomiast zmienne i mog
ą
wyst
ę
powa
ć
lokalnie wewn
ą
trz zagnie
ż
d
ż
onych bloków).
Zmienne widoczne w całym programie
Je
ż
eli zmienna została zadeklarowana przed funkcj
ą
main() to
jej zasi
ę
giem widoczno
ś
ci jest cały program. Zmienne takie
nazywaj
ą
si
ę
zmiennymi globalnymi.
int a = 0;
float b = 2.0;
int main()
{
int i;
return 0;
}
//p_71
# include <stdio.h># include <conio.h># include <string.h>//
deklaracje zmiennych globalnychint x=1234;double
y=1.234567;void fun_1(){ printf("Wewn
ą
trz funkcji \n x=%d,
y=%f\n",x,y);
}
void main(void)
{
int x=4321;
clrscr();
fun_1();
printf("Blok główny funkcji main() \n x=%d, y=%f\n",x,y);
96
{
double y=7.654321;
fun_1();
printf("Blok zagnie
ż
dzony funkcji main() \n x=%d,
y=%f\n",x,y);
}
getch();
}
Z wn
ę
trza funkcji widoczne s
ą
zmienne globalne.
Deklaracja lokalnej zmiennej x przysłania zmienn
ą
globalna w
obr
ę
bie bloku funkcji.
Specyfikatory i modyfikatory klasy pami
ę
ci
W j
ę
zyku C s
ą
cztery specyfikatory i dwa modyfikatory, które
mog
ą
by
ć
u
ż
ywane do okre
ś
lania czasu
ż
ycia zmiennej.
Specyfikator auto
Specyfikator auto okre
ś
la,
ż
e lokalizacja zmiennej w pami
ę
ci
jest tymczasowa tzn. kiedy zmienna przestanie by
ć
widoczna i
dost
ę
pna w programie, zmienna mo
ż
e zosta
ć
przemieszczona w
inne miejsce w programie albo skasowana.
Tylko zmienne o lokalnym zakresie dost
ę
pno
ś
ci mog
ą
by
ć
deklarowane jako zmienne auto. Auto jest rzadko u
ż
ywanym
słowem kluczowym, poniewa
ż
zmienne o blokowym zakresie
dostepno
ś
ci, s
ą
w sposób domy
ś
lny traktowane jako tymczasowe
(auto).
Specyfikator static
Specyfikator static (zmienna statyczna) mo
ż
e by
ć
stosowany
wobec zmiennych dost
ę
pnych w zakresie bloku lub w zakresie
programu. Je
ż
eli zmienna wewn
ą
trz funkcji zostanie
97
zadeklarowana jako statyczna istnieje ona w sposób ci
ą
gły w
czasie. Miejsce w pami
ę
ci przeznaczona dla przechowywania tej
zmiennej nie podlega likwidacji, gdy zmienna ta wyjdzie poza
zakres swojej widoczno
ś
ci (warto
ść
zmiennej jest przechowywana
dalej pod tym samym adresem, mimo
ż
e jest niewidoczna). Po
powrocie przez program do zakresu widoczno
ś
ci zmiennej nadal
znajduje si
ę
tam jej ostatnio zapisana warto
ść
.
//p_72
# include <stdio.h># include <conio.h>int sumuj(int x,int
y){static int licznik=1;printf("Wywołanie funkcji, stan
licznika : %d, \n",licznik++);
return(x+y);
}
int main(void)
{
int i,j;
clrscr();
for(i=0,j=5;i<5;i++,j--)
printf("dodawanie liczb: %d oraz %d suma: %d.
\n",i,j,sumuj(i,j));
getch();
}
//p_73
# include <stdio.h># include <conio.h>int sumuj(int x,int
y){int licznik=1;
printf("Wywołanie funkcji, stan licznika : %d, \n",licznik++);
return(x+y);
}
int main(void)
{
int i,j;
98
clrscr();
for(i=0,j=5;i<5;i++,j--)
printf("dodawanie liczb: %d oraz %d suma: %d.
\n",i,j,sumuj(i,j));
getch();
}
//p_74
# include <stdio.h>
# include <conio.h>
int sumuj(int x,int y)
{
static int licznik=1;
printf("Wywołanie funkcji, stan licznika : %d, \n",++licznik);
return(x+y);
}
int main(void)
{
int i,j;
clrscr();
for(i=0,j=5;i<5;i++,j--)
printf("dodawanie liczb: %d oraz %d suma: %d.
\n",i,j,sumuj(i,j));
getch();
}
99
Zakresy dost
ę
pno
ś
ci :
zasi
ę
g blokowy
zasi
ę
g w obr
ę
bie funkcji
zasi
ę
g w obr
ę
bie programu
zasi
ę
g w obrebie pliku
W j
ę
zyku C zmienna globalna zadeklarowana jako static jest
nazywana zmienn
ą
o zasi
ę
gu obejmuj
ą
cym cały plik. Jest ona
dost
ę
pna od punktu zadeklarowania a
ż
do ko
ń
ca pliku. Słowo
plik oznacza
ź
ródłowy plik programu, czyli plik tekstowy
zawieraj
ą
cy tekst programu. ( Wi
ę
kszo
ść
du
ż
ych programów
składa si
ę
z wielu plików
ź
ródłowych)
int x = 0;
static int y = 0;
static float z = 0.0;
int main()
{
int i;
...
...
return 0;
}
Zasi
ę
g programu --------------------à
Zasi
ę
g pliku --------------à
Zasi
ę
g funkcji --------à
Zasi
ę
g blokowy -----à
Specyfikator register
100
Ka
ż
dy komputer ma pewn
ą
ilo
ść
rejestrów do przechowywania
danych i wykonywania operacji arytmetycznych i logicznych.
Poniewa
ż
rejestry s
ą
umieszczone w pami
ę
ci procesora zatem
dost
ę
p do nich jest du
ż
o szybszy ni
ż
do pami
ę
ci RAM gdzie
znajduj
ą
si
ę
zmienne programu. Aby przy
ś
pieszy
ć
dost
ę
p do
pewnych zmiennych mo
ż
emy je umie
ś
ci
ć
bezpo
ś
rednio w pami
ę
ci
procesora, czyli w rejestrze.
Kompilator mo
ż
e zignorowa
ć
tak
ą
sugesti
ę
, je
ż
eli nie ma
dostepnego rejestru, b
ą
d
ź
inne ograniczenia uniemo
ż
liwiaj
ą
mu
takie postepowanie.
Pobranie adresu zmiennej zadeklarowanej jako rejestrowa jest
nielegalne.
int main()
{
register int i;
for (i=0;i<max;i++)
{
......
}
return 0;
}
Specyfikator extern
Zmienna globalna widoczna jest we wszystkich plikach
ź
ródłowych tworz
ą
cych program. Jak zmienna zadeklarowana jako
globalna w jednym pliku dyskowym (A) mo
ż
e by
ć
widoczna i
dost
ę
pna w innym pliku dyskowym (B). Sk
ą
d kompilator ma
wiedzie
ć
,
ż
e w pliku B chodzi o t
ę
sam
ą
zmienn
ą
, która została
zadeklarowana jako globalna w pliku A.
Aby w pliku B odwoła
ć
si
ę
do zmiennych globalnych
zadeklarowanych w A, nale
ż
y w pliku B zadeklarowa
ć
te zmienne
jako zmienne zewn
ę
trzne, u
ż
ywaj
ą
c specyfikatora extern.
plik A
101
int a,b;
int main()
{
return 0;
}
plik B
int c;
extern int a;
int main()
{
extern int b;
int i;
return 0;
}
Zasady deklarowania i odwoływania si
ę
do zmiennych
zewn
ę
trznych :
Deklaruj
ą
c zmienna globaln
ą
:
pomin
ąć
słowo extern
zainicjowa
ć
zmienn
ą
przy deklaracji
Kiedy w innym pliku odwołujemy si
ę
do tej zmiennej:
u
ż
y
ć
słowa extern
nie inicjowa
ć
zmiennej w deklaracji
Modyfikatory sposobów odwoływania si
ę
do zmiennych.
Modyfikator const
Je
ż
eli zmienna zostanie zadeklarowana z u
ż
yciem modyfikatora
const, po jednorazowym zainicjowaniu jej warto
ść
nie mo
ż
e
zosta
ć
zmieniona.
102
const double pi = 3.141593;
const char str[ ] = ”Tablica znakowa”;
str[0] = ‘x’; à bł
ą
d
Modyfikator volatile - dane ulotne
Zmienn
ą
której warto
ść
mo
ż
e by
ć
zmieniana w trakcie programu
bez stosowania operacji przypisania nale
ż
y zadeklarowa
ć
jako
ulotn
ą
– volatile.
Mo
ż
na np. zadeklarowa
ć
zmienn
ą
globalna do zapami
ę
tania znaku
wprowadzanego przez uzytkownika z klawiatury. W procesie
optymalizacji kodu kompilator mo
ż
e t
ą
zmienna potraktowa
ć
tak
jak inne zmienne , których warto
ś
ci ustalane s
ą
operacjami
podstawienia. Zadeklarowanie jej jako ulotn
ą
zabezpieczy j
ą
przed tym procesem i jej zmiana warto
ś
ci b
ę
dzie mo
ż
liwa
jedenie poprzez wprowadzenie nowego znaku z klawiatury.
void read_keyboard()
{
volatile char keyboard_ch;
.......
}
Funkcje
Deklaracja a definicja funkcji
Deklaracja zmiennej lub funkcji okre
ś
la interpretacj
ę
i
atrybuty zestawu identyfikatorów;
Definicja wymaga od kompilatora zarezerwowania pami
ę
ci dla
zmiennej lub funkcji okre
ś
lonej danym identyfikatorem;
Deklaracja zmiennej jest jej definicj
ą
.
Deklaracja funkcji nie stanowi jej definicji. Deklaracja
funkcji odwołuje si
ę
do jej definicji (znajduj
ą
cej si
ę
w innym
103
miejscu), okre
ś
la natomiast jakiego typu warto
ść
zostanie
zwrócona przez funkcj
ę
.
Definicja funkcji okre
ś
la co ta funkcja robi, podaj
ą
c
jednocze
ś
nie liczb
ę
i typy argumentów przekazywanych do
funkcji.
Zadeklarowanie funkcji nie jest równoznaczne z jej definicj
ą
.
Je
ż
eli definicja funkcji jest umieszczona przed miejscem
pierwszego wywołania funkcji, to nie musimy funkcji wcze
ś
niej
deklarowa
ć
. W przeciwnym razie musimy przed pierwszym
wywołaniem funkcji umie
ś
ci
ć
jej deklaracj
ę
.
Typ warto
ś
ci zwracanej przez funkcj
ę
.
Funkcja mo
ż
e by
ć
zadeklarowana i zwraca
ć
dane dowolnego typu
(za wyj
ą
tkiem tablicy i funkcji). Instrukcja return z
definicji funkcji zwraca jedn
ą
warto
ść
, którejm typ powinien
by
ć
zgodny z typem zadeklarowanym przed nazw
ą
funkcji.
Domy
ś
lnym typem jest typ int.
specyfikator_typu_danych nazwa_funkcji();
Prototyp funkcji
Deklaracja funkcji zawiera tak
ż
e liczb
ę
i typy argumentów
przekazywanych do funkcji.
Liczba i typ argumentów funkcji nazywa si
ę
prototypem funkcji.
Ogólna forma deklaracji:
spec_typu_danych nazwa_funkcji ( spec_typ_danych argument1,
spec_typ_danych argument2,
spec_typ_danych argument3,
..................................................);
nazwy : argument1, argument2 itd. s
ą
opcjonalne
104
Wywołanie funkcji
Po wywołaniu funkcji wykonanie programu przenosi si
ę
do kodu
funkcji, a
ż
do zako
ń
czenia jego wykonania. Po powrocie z
funkcji i ewentualnym zwrocie warto
ś
ci , wykonanie programu
jest podejmowane pocz
ą
wszy od nastepnej intrukcji nastepuj
ą
cej
po wywołaniu funkcji.
Wywołanie funkcji to wyra
ż
enie, które mo
ż
e by
ć
u
ż
ywane jako
samodzielna instrukcja, lub jako element wewn
ą
trz innych
wyra
ż
e
ń
.
//p_75
# include <stdio.h># include <conio.h>int funkcja1(int x,int
y);double funkcja2(double x,double y){printf("Jeste
ś
my w
funkcji2\n");return (x-y);}void main(void){int x1=80;int
y1=10;double x2=100.123456;
double y2=10.123456;
clrscr();
printf("Wywołanie funkcja1(%d,%d).\n",x1,y1);
printf("Funkcja1 zwraca : %d. \n",funkcja1(x1,y1));
printf("Wywołanie funkcja2(%f,%f).\n",x2,y2);
printf("Funkcja2 zwraca : %f.\n",funkcja2(x2,y2));
getch();
}
int funkcja1(int x,int y)
{
printf("Jeste
ś
my w funkcji1.\n");
return(x+y);
}
105
Prototypy funkcji :
1/ Funkcja przy wywołaniu nie pobiera
ż
adnych argumentów –
bezargumantowa;
2/ Funkcja pobiera stał
ą
okre
ś
lon
ą
liczb
ę
argumentów;
3/ Funkcja pobiera zmienn
ą
liczb
ę
argumentów;
Funkcje bezargumentowe
int c;
c = getchar();
deklaracja: int getchar(void);
Dla wszystkich funkcji bezargumentowych w ich deklaracji
(prototypie) stosowany jest typ danych void.
//p_76
#include <stdio.h>#include <conio.h>#include <time.h>void
data_czas(void);main(){ printf("Przed wywołaniem \n");
data_czas(); printf("Po wywołaniu \n"); return 0;}void
data_czas(void){time_t t; printf("Wewn
ą
trz funkcji data_czas()
\n");
time(&t);
printf("Aktualna data i czas : %s",asctime(localtime(&t)));
getch();
}
Funkcja data_czas() wykorzystuje zmienna t typu time_t i
posługuje si
ę
funkcjami bibliotecznymi zadeklarowanymi w pliku
nagłówkowym time.h tj. time(), localtime(), asctime();
Funkcje czasowe daj
ą
nam 3 rodzaje czasów :
106
1/ czas kalendarzowy – czas bie
żą
cy w oparciu o kalendarz
gregoria
ń
ski
2/ czas lokalny – czas kalendarzowy w okre
ś
lonej strefie
czasowej
3/ czas zimowy/letni – czas strefowy z uwzgl
ę
dnieniem
przesuni
ę
cia zimowego/letniego.
Funkcja time() zwraca czas kalendarzowy
#include <time.h>
time_t time(time_t *timer);
time_t - tzw. typ arytmetyczny, stosowany da zapisu czasu
timer - zmienna typu wska
ź
nik wskazuj
ą
ca miejsce w pami
ę
ci, w
którym powinny zosta
ć
zapisane dane dotycz
ą
ce daty i czasu
zwracane przez funkcje;
Je
ż
eli dane dotycz
ą
ce czasu kalendarzowego s
ą
niemo
ż
liwe do
odczytania na danym komputerze to funkcja zwraca –1.
Funkcja localtime() zwraca czas lokalny po przekształceniu
czasu kalendarzowego
#include <time.h>
struct tm *localtime(const time_t *timer);
tm - struktura danych, zawieraj
ą
ca składniki czasu
kalendarzowego
timer - wska
ź
nik do adresu pami
ę
ci, gdzie przechowywany jest
czas kalendarzowy zwrócony wcze
ś
niej przez funkcje time();
aby przekształci
ć
dane dotycz
ą
ce daty i czasu w strukturze tm
w ła
ń
cuch znaków nale
ż
y wywoła
ć
funkcje asctime();
#include <time.h>
char *acstime(const strunct tm *timeptr)
timeprt - wska
ź
nik odwołuj
ą
cy si
ę
do struktury tm zwróconej
przez funkcje localtime();
107
Funkcje o stałej liczbie argumentów
int function_1(int x, int y);
Deklaruj
ą
c funkcj
ę
o stałej liczbie argumentów, nale
ż
y poda
ć
typy wszystkich argumentów (zalecane jest równie
ż
podanie ich
nazw);
Funkcje o zmiennej liczbie argumentów
np. printf()
int printf(const char *format , argument1,argument2,.....);
wielokropek jest oznaczeniem dla kompilatora C ,
ż
e ilo
ść
argumentów funkcji mo
ż
e by
ć
zmienna;
typ_danych nazwa_funkcji(typ_danych arg1,...);
wielokropek oznacza tu pozastałe argumenty, które nie zostały
wymienione na li
ś
cie argumentów;
printf(const char * format,...);
W pliku stdarg.h zadeklarowane zostały trzy podprogramy, które
pozwalaj
ą
na tworzenie i obsług
ę
funkcji o zmiennej liczbie
argumentów :
va_start()
va_arg()
va_end()
Aby zainicjowa
ć
tablic
ę
, która jest niezb
ę
dna do działania
makrorozkazów va_arg() oraz va_end() nale
ż
y zawsze najpierw
wywoła
ć
makro va_start().
Plik nagłówkowy stdarg.h zawiera tak
ż
e typ danych va_list,
który okre
ś
la typ tablicy odpowiedni do przechowywania danych
potrzebnych do działania makropolece
ń
va_start() , va_arg() ,
va_end() .
#include <stdarg.h>
108
void va_start(va_list tab, lastfix);
tab - inicjowana tym poleceniem tablica
lastfix - okre
ś
la ostatni argument funkcji przed wielokropkiem
w
deklaracji
Poprzez u
ż
ycie makropolecenia va_arg() mo
ż
na obsługiwa
ć
wyra
ż
enia okre
ś
lajace typ i warto
ść
nastepnego argumentu
funkcji. Makro va_arg() mo
ż
e by
ć
u
ż
yte do pobrania kolejnego
argumentu przekazywanego do funkcji,
#include <stdarg.h>
typ_danych va_arg()(va_list tab, typ_danych);
tab - tablica zainicjowana w momencie działania makra
va_start()
typ_danych - typ danych argumentu przesłanego do funkcji
Aby zapewni
ć
normalny i poprawny zwrot warto
ś
ci przez funkcj
ę
o zmiennej liczbie argumentów, nale
ż
y zastosowa
ć
makro
va_end(), po tym jak wszystkie argumenty zostan
ą
przetworzone.
#include (stdarg.h>
void va_end(va_list tab);
//p_76_0
/* Funkcja ze zmienn
ą
liczb
ą
argumentów */#include
<stdio.h>#include <stdarg.h>double AddDouble(int x, ...);main
(){ double d1 = 1.5; double d2 = 2.5; double d3 = 3.5; double
d4 = 4.5;
printf("Wprowadzony argument: %2.1f\n", d1);
printf("Wynik zwrócony przez AddDouble() jest: %2.1f\n\n",
AddDouble(1, d1));
printf("Wprowadzone argumenty: %2.1f and %2.1f\n", d1, d2);
printf("Wynik zwrócony przez AddDouble() jest: %2.1f\n\n",
AddDouble(2, d1, d2));
109
printf("Wprowadzone argumenty: %2.1f, %2.1f and %2.1f\n", d1,
d2, d3);
printf("Wynik zwrócony przez AddDouble() jest: %2.1f\n\n",
AddDouble(3, d1, d2, d3));
printf("Wprowadzone argumenty: %2.1f, %2.1f, %2.1f, and
%2.1f\n", d1, d2, d3, d4);
printf("Wynik zwrócony przez AddDouble() jest: %2.1f\n",
AddDouble(4, d1, d2, d3, d4));
return 0;
}
double AddDouble(int x, ...)
{
va_list arglist;
int i;
double result = 0.0;
printf("Liczba argumentów jest: %d\n", x);
va_start (arglist, x);
for (i=0; i<x; i++)
result += va_arg(arglist, double);
va_end (arglist);
return result;
}
Zastosowania wska
ź
ników
110
Arytmetyka wska
ź
ników
Skalarny wymiar wska
ź
nika
spec_typu_danych *nazwa_wsk;
nazwa_wsk + n
oznacza w bajtach
nazwa_wsk + n * sizeof(spec_typu_danych);
//p_76_1
/* arytmetyka wska
ź
ników */
#include <stdio.h>
#include <conio.h>
main()
{
char *ptr_ch;
int *ptr_int;
double *ptr_db;
clrscr();
/* char wsk. ptr_ch */
printf("Warto
ść
ptr_ch: 0x%p\n", ptr_ch);
printf(" ptr_ch + 1: 0x%p\n", ptr_ch + 1);
printf(" ptr_ch + 2: 0x%p\n", ptr_ch + 2);
printf(" ptr_ch - 1: 0x%p\n", ptr_ch - 1);
printf(" ptr_ch - 2: 0x%p\n", ptr_ch - 2);
/* int wsk. ptr_int */
printf("Warto
ść
ptr_int: 0x%p\n", ptr_int);
111
printf(" ptr_int + 1: 0x%p\n", ptr_int + 1);
printf(" ptr_int + 2: 0x%p\n", ptr_int + 2);
printf(" ptr_int - 1: 0x%p\n", ptr_int - 1);
printf(" ptr_int - 2: 0x%p\n", ptr_int - 2);
/* double wsk ptr_db */
printf("Warto
ść
ptr_db: 0x%p\n", ptr_db);
printf(" ptr_db + 1: 0x%p\n", ptr_db + 1);
printf(" ptr_db + 2: 0x%p\n", ptr_db + 2);
printf(" ptr_db - 1: 0x%p\n", ptr_db - 1);
printf(" ptr_db - 2: 0x%p\n", ptr_db - 2);
getch();
return 0;
}
Odejmowanie wska
ź
ników
typy odejmowanych wska
ź
ników musz
ą
by
ć
takie same;
// p_76_2
/* odejmowanie wska
ź
ników */
#include <stdio.h>
#include <conio.h>
main()
{
int *ptr_int1, *ptr_int2;
clrscr();
printf(" ptr_int1: 0x%p\n", ptr_int1);
112
ptr_int2 = ptr_int1 + 5;
printf(" ptr_int2 = ptr_int1 + 5: 0x%p\n", ptr_int2);
printf(" ptr_int2 - ptr_int1: %d\n", ptr_int2 - ptr_int1);
ptr_int2 = ptr_int1 - 5;
printf(" ptr_int2 = ptr_int1 - 5: 0x%p\n", ptr_int2);
printf(" ptr_int2 - ptr_int1: %d\n", ptr_int2 - ptr_int1);
getch();
return 0;
}
Dost
ę
p do tablic i elementów tablic za pomoc
ą
wska
ź
ników:
nazwa tablicy jest wska
ź
nikiem do jej 1 elementu;
dodanie liczby całkowitej do nazwy tablicy jest dost
ę
pem do
jej elementu o indeksie równym liczbie całkowitej
// p_76_3
/* dostep do tablic i elementów tablic za pomoc
ą
wska
ź
ników */
#include <stdio.h>
#include <conio.h>
main()
{
char str[] = "It's a string!";
char *ptr_str;
int list[] = {1, 2, 3, 4, 5};
int *ptr_int;
113
/* dost
ę
p do tablicy znaków */
clrscr();
ptr_str = str;
printf("Przed zmian
ą
str : %s\n", str);
printf("Przed zmian
ą
str[5] : %c\n", str[5]);
*(ptr_str + 5) = 'A';
printf("Po zmianie, str[5] : %c\n", str[5]);
printf("Po zmianie, str : %s\n", str);
/* dostep do tablicy liczb */
ptr_int = list;
printf("Przed zmian
ą
, list[2] : %d\n", list[2]);
*(ptr_int + 2) = -3;
printf("Po zmianie, list[2] : %d\n", list[2]);
getch();
return 0;
}
Przekazywanie tablicy jako argumentu do funkcji
jest metoda na proste przekazanie wi
ę
kszej ilo
ś
ci argumentów
do funkcji
//p_76_4
/* przekazywanie tablicy jako argumentu do funkcji */#include
<stdio.h>#include <conio.h>int AddThree(int list[]);main(){
int sum, list[3]; clrscr(); printf("Wprowad« 3 liczby :\n");
114
scanf("%d%d%d", &list[0], &list[1], &list[2]);
sum = AddThree(list);
printf("Ich suma wynosi : %d\n", sum);
getch();
return 0;
}
int AddThree(int list[])
{
int i;
int result = 0;
for (i=0; i<3; i++)
result += list[i];
return result;
}
Przekazywanie wska
ź
ników jako argumentów do funkcji
Nazwa tablicy po której nie nast
ę
puje indeks jest wska
ź
nikiem
do pierwszego elementu. Zatem adres do pierwszego elementu
tablicy b
ę
d
ą
cy wska
ź
nikiem mo
ż
e by
ć
przekazany do funkcji tak
jak tablica.
//p_76_5
/* przekazywanie wska
ź
ników jako argumentów do funkcji
*/#include <stdio.h>#include <conio.h>void ChPrint(char
*ch);int DataAdd(int *list, int max);
main()
{
char str[] = "It's a string!";
115
char *ptr_str;
int list[5] = {1, 2, 3, 4, 5};
int *ptr_int;
/* przypisanie adresu do wska
ź
nika */
clrscr();
ptr_str = str;
ChPrint(ptr_str);
ChPrint(str);
/* przypisanie adresu do wska
ź
nika */
ptr_int = list;
printf("The sum returned by DataAdd(): %d\n",
DataAdd(ptr_int, 5));
printf("The sum returned by DataAdd(): %d\n",
DataAdd(list, 5));
getch();
return 0;
}
void ChPrint(char *ch)
{
printf("%s\n", ch);
}
int DataAdd(int *list, int max)
{
int i;
int sum = 0;
116
for (i=0; i<max; i++)
sum += list[i];
return sum;
}
tablice znakowe i liczbowe przekazywane s
ą
do funkcji
wska
ź
nikiem
poprzez:
ptr = n_tablicy
lub
n_tablicy
Przekazywanie tablic wielowymiarowych do funkcji
Mo
ż
na przekaza
ć
nazw
ę
tablicy lub wska
ź
nik zawieraj
ą
cy adres
startowy tablicy wielowymiarowej.
//p_76_6
/* przekazywanie tablic wielowymiarowych jako argumentów do
funkcji */#include <stdio.h>#include <conio.h>/* deklaracje
funkcji */
int DataAdd1(int list[][5], int max1, int max2);
int DataAdd2(int *list, int max1, int max2);
/* funkcja main() */
main()
{
int list[2][5] = {1, 2, 3, 4, 5,
5, 4, 3, 2, 1};
int *ptr_int;
117
clrscr();
printf("Suma otrzymana przez DataAdd1(): %d\n",
DataAdd1(list, 2, 5));
ptr_int = &list[0][0];
printf("Suma otrzymana przez DataAdd2(): %d\n",
DataAdd2(ptr_int, 2, 5));
getch();
return 0;
}
/* definicja funkcji Data Add1 */
int DataAdd1(int list[][5], int max1, int max2)
{
int i, j;
int sum = 0;
for (i=0; i<max1; i++)
for (j=0; j<max2; j++)
sum += list[i][j];
return sum;
}
/* definicja funkcji DataAdd2 */
int DataAdd2(int *list, int max1, int max2)
{
int i, j;
int sum = 0;
for (i=0; i<max1; i++)
118
for (j=0; j<max2; j++)
sum += *(list + i*max2 + j);
return sum;
}
do funkcji przekazywana jest tablica
Add1 à przez warto
ść
/nazw
ę
/
Add2 à przez wska
ź
nik
W przykładach p_76_4 do p_76_6 deklaracje wymiaru tablic w
programie głównym i w funkcjach.
Tablice wska
ź
ników
deklaracja tablicy wska
ź
ników
int *ptr_int[5];
//p_76_7
/* Tablice wska
ź
ników */#include <stdio.h>#include <conio.h>/*
deklaracje funkcji */
void StrPrint1(char **str1, int size);
void StrPrint2(char *str2);
/* funkcja main() */
main()
{
char *str[4] = {"To jest zdanie 1;",
"To jest zdanie 2;",
"To jest zdanie 3;",
"To jest zdanie 4.\n"
119
};
int i, size;
clrscr();
size = 4;
StrPrint1(str, size);
for (i=0; i<4; i++)
StrPrint2(str[i]);
getch();
return 0;
}
/* definicja funkcji */
void StrPrint1(char **str1, int size)
{
int i;
for (i=0; i<size; i++)
printf("%s\n", str1[i]);
}
/* definicja funkcji */
void StrPrint2(char *str2)
{
printf("%s\n", str2);
}
deklarujemy i inicjujemy tablice składaj
ą
c
ą
si
ę
z wielu ci
ą
gów
znaków
mo
ż
emy ja potraktowac jako tablic
ę
dwuwymiarow
ą
120
1 wymiar – ilo
ść
stringów
2 wymiar – ilo
ść
znaków w stringu
mo
ż
emy ja równie
ż
potraktowac jako tablice wska
ź
ników do
poszczególnych stringów
tablica jest wyprowadzana na ekran przez dwie funkcje
StrPrint1 (wska
ź
nik do tablicy wska
ź
ników, wymiar)
nazwa tablicy
str – w programie głównym jest nazw
ą
tablicy b
ę
d
ą
c
ą
tablic
ą
wska
ź
ników do stringów;
jest zatem jako nazwa tablicy wska
ź
nikiem do jej pierwszego
elementu zatem jest wska
ź
nikiem do wska
ź
nika
wywołanie StrPrint1(str,size)
Funkcja StrPrint1(char **str1, int size)
StrPrint2 - argumentem funkcji jest pojedynczy ła
ń
cuch
/string/;
Zatem argumentem wywołania jest wska
ź
nik do stringa i w
tablicy [i]
Wywołanie StrPrint2(str[i])
Deklaracja StrPrint(char *str2)
Wska
ź
nik do funkcji
Poniewa
ż
funkcja ma warto
ść
lewostronn
ą
w postaci adresu
startowego w pami
ę
ci, podobnie zatem jak w przypadku tablic
mo
ż
na zadeklarowa
ć
i zainicjowa
ć
wska
ź
nik przy pomocy
lewostronnej warto
ś
ci (adresu) funkcji.
//p_76_8
/* wska
ź
nik do funkcji */
121
#include <stdio.h>
#include <conio.h>
/* deklaracja funkcji */
int StrPrint(char *str);
/* main() function */
main()
{
char str[22] = "Wskazanie funkcji.";
int (*ptr)(char *str);
clrscr();
ptr = StrPrint;
if (!(*ptr)(str))
printf("OK!\n");
getch();
return 0;
}
/* definicja funkcji */
int StrPrint(char *str)
{
printf("%s\n", str);
return 0;
}
funkcja zwraca typ int pobiera wska
ź
nik do znaku:
122
deklaracja funkcji
int StrPrint(char *str)
deklaracja wska
ź
nika do funkcji
int (*ptr)(char *str)
deklaracja wska
ź
nika - wska
ź
nik uj
ę
ty w nawiasy okr
ą
głe
wskazuje funk.
typ (*nazwa_wska
ź
nika)(typ argumentu funkcji)
zgodny z typem funkcji wska
ź
nik funkcji
ptr = StrPrint à przypisanie lewostronnej warto
ś
ci funkcji
wska
ź
nikowi
(*ptr)(str) à wywołanie funkcji wskazywanej przez wska
ź
nik
ptr z argumentem str à jest to przekazanie
do funkcji tablicy str
Funkcja drukuje ła
ń
cuch znaków, a po zako
ń
czeniu zwraca 0
(return 0;) if(!0) à wydruk OK
123
124
Dynamiczne przyporz
ą
dkowanie pami
ę
ci
Je
ż
eli chcemy w trakcie realizacji programu zarz
ą
dza
ć
pami
ę
ci
ą
dostepn
ą
do jego realizacji to mamy do dyspozycji nastepuj
ą
ce
funkcje z biblioteki stdlib.h :
1/ malloc()
2/ calloc()
3/ realloc()
4/ free()
Funkcja malloc()
Słu
ż
y do przyporz
ą
dkowania okreslonego obszaru pami
ę
ci
#include <stdlib.h>
void *malloc(size_t size);
size – wielko
ść
obszaru pami
ę
ci w bajtach przeznaczony do
przyporz
ą
dkowania
funkcja zwraca wska
ź
nik typu void (nieokre
ś
lony), wskazuj
ą
cy
pocz
ą
tkowy adres zarezerwowanego obszaru pami
ę
ci à typ tego
wska
ż
nika jest automatycznie poddawany konwersji i zmieniany
na typ wska
ź
nika, który znajduje si
ę
po lewej stronie
operatora przypisania.
Funkcja zwraca wska
ź
nik pusty, gdy operacja zarezerwowania
żą
danego obszaru pami
ę
ci sko
ń
czy si
ę
niepowodzeniem. Dlatego
zawsze przed u
ż
yciem takiego wska
ź
nika nale
ż
y sprzwdzi
ć
czy
nie jest pusty.
//p_76_9
125
/ U
ż
ycie funkcji malloc() */#include <stdio.h> #include
<stdlib.h>#include <string.h>/* function declaration */void
StrCopy(char *str1, char *str2);/* main() function */main(){
char str[] = "U
ż
ycie malloc() do rezerwacji pami
ę
ci.";
char *ptr_str;
int termination;
/* call malloc() */
ptr_str = malloc( strlen(str) + 1);
if (ptr_str != NULL){
StrCopy(str, ptr_str);
printf("Ła
ń
cuch okre
ś
lony wska
ź
nikiem ptr_str:\n%s\n",
ptr_str);
termination = 0;
}
else{
printf("malloc() function failed.\n");
termination = 1;
}
return termination;
}
/* function definition */
void StrCopy(char *str1, char *str2)
{
int i;
for (i=0; str1[i]; i++)
str2[i] = str1[i];
126
str2[i] = '\0';
}
Zadaniem funkcji malloc() jest zarezerwowanie pami
ę
ci dla
ła
ń
cucha znaków. Wska
ź
nik zwracany przez funkcj
ę
malloc() jest
wykorzystywany w operacji kopiowania ła
ń
cuchów.
Je
ż
eli po wykorzystaniu przyporz
ą
dkowanej dynamicznie pami
ę
ci
ta nie zostanie zwolniona, a w dalszej cz
ęś
ci programu
nast
ą
pi
ą
kolejne operacje przyporz
ą
dkowania pami
ę
ci to pami
ę
ci
mo
ż
e po prostu zabrakn
ąć
.
Dynamicznie przyporz
ą
dkowan
ą
pami
ęć
zwalnia funkcja free().
Funkcja free()
poniewa
ż
pami
ęć
dost
ę
pna w ka
ż
dym komputerze jest ograniczona,
nale
ż
y przyporz
ą
dkowa
ć
tylko tyle pami
ę
ci ile jest jest jej
rzeczywi
ś
cie potrzebne, a po wykorzystaniu j
ą
zwolni
ć
.
//p_76_10
/ Use the free() function */#include <stdio.h> #include
<stdlib.h>/* function declarations */ void DataMultiply(int
max, int *ptr);void TablePrint(int max, int *ptr);/* main()
function */main(){ int *ptr_int, max;
int termination;
char key = 'c';
max = 0;
termination = 0;
while (key != 'x'){
printf("Enter a single digit number:\n");
scanf("%d", &max);
/* call malloc() */
ptr_int = malloc(max * max * sizeof(int));
if (ptr_int != NULL){
127
DataMultiply(max, ptr_int);
TablePrint(max, ptr_int);
free(ptr_int);
}
else{
printf("malloc() function failed.\n");
termination = 1;
break;
}
printf("\nPress x-key to quit; other key to continue.\n");
scanf("%s", &key);
}
printf("\nBye!\n");
return termination;
}
/* function definition */
void DataMultiply(int max, int *ptr)
{
int i, j;
for (i=0; i<max; i++)
for (j=0; j<max; j++)
*(ptr + i * max + j) = (i+1) * (j+1);
}
/* function definition */
void TablePrint(int max, int *ptr)
128
{
int i, j;
printf("The multiplication table of %d is:\n",
max);
printf(" ");
for (i=0; i<max; i++)
printf("%4d", i+1);
printf("\n ");
for (i=0; i<max; i++)
printf("----", i+1);
for (i=0; i<max; i++){
printf("\n%d|", i+1);
for (j=0; j<max; j++)
printf("%3d ", *(ptr + i * max + j));
}
}
Działanie programu ma na celu zbudowanie dwuwymiarowej
numerycznej tablicy n x n z elementami zaczerpni
ę
tymi z
tabliczki mno
ż
enia. P
ę
tle w programie b
ę
d
ą
powtarzane, a
ż
do
naci
ś
ni
ę
cia znaku ‘x’, lub niepowodzenia w przyporz
ą
dkowaniu
pami
ę
ci przez funkcj
ę
malloc().
Aby zademonstrowa
ć
działanie funkcji free(), program dokonuje
tymczasowego obszaru pami
ę
ci, do przechowywania elementów
tabliczki mno
ż
enia. Zaraz po wydrukowaniu na ekran pami
ęć
ta
zostaje zwolniona poprzez działanie funkcji free().
Funkcja calloc()
Funkcja ta podobnie jak malloc() mo
ż
na stosowa
ć
do
dynamicznego przyporz
ą
dkowania pami
ę
ci. Funkcja calloc()
129
pobiera dwa argumenty i po zarezerwowaniu pami
ę
ci powoduje
dodatkowo wyzerowanie bajtów wchodz
ą
cych w skład tego obszaru.
#include <stdlib.h>
void *calloc(size_t nitem, size_t size);
nitem – oznacza ilo
ść
elementów, które chcemy przechowa
ć
w
pami
ę
ci
size – rozmiar pojedynczego elementu w bajtach
calloc() zwraca równie
ż
wska
ź
nik typu void
//p_76_11
/* 17L03.c: Use the calloc() function */
#include <stdio.h>
#include <stdlib.h>
/* main() function */
main()
{
float *ptr1, *ptr2;
int i, n;
int termination = 1;
n = 5;
ptr1 = malloc(n * sizeof(float));
ptr2 = calloc(n, sizeof(float));
if (ptr1 == NULL)
printf("malloc() failed.\n");
else if (ptr2 == NULL)
printf("calloc() failed.\n");
else{
for (i=0; i<n; i++)
130
printf("ptr1[%d]=%5.2f, ptr2[%d]=%5.2f\n",
i, *(ptr1 + i), i, *(ptr2 + i));
free(ptr1);
free(ptr2);
termination = 0;
}
return termination;
}
Aby sprawdzi
ć
czy pami
ęć
zarezerwowana przez funkcj
ę
calloc()
zostaje wyzerowana , pocz
ą
tkowa zawarto
ść
pami
ę
ci zostaje
wydrukowana i porównana z zawarto
ś
cia pami
ę
ci rezerwowanej
funkcj
ą
malloc().
Funkcja realloc()
Funkcja ta pozwala na zmiane rozmiaru bloku w dynamicznie
przyporz
ą
dkowanym obszarze pami
ę
ci, który został uprzednio
zarezerwowany przez funkcje malloc(), calloc() i realloc().
#include <stdlib.h>
void *realloc(void *block, size_t size)
blok - wska
ź
nik do obszaru pami
ę
ci uprzednio przyporz
ą
kowanego
dynamicznie;
size – rozmiar bloku pami
ę
ci, który powinien zosta
ć
przeorganizowany
Funkcja zwraca wska
ź
nik typu void, albo wska
ź
nik zerowy.
Funkcja realloc() wywołana z pierwszym argumentem zerowym jest
równowa
ż
na funkcji malloc().
ptr_flt = realloc(NULL, 10*sizeof(float));
ptr_flt = malloc(10*sizeof(float)); à s
ą
równowa
ż
ne
J
ęż
eli funkcja realloc() b
ę
dzie miała 2 argument równy zero to
jest równowa
ż
na fnkcji free();
131
free(prt);
realloc(prt,0); à sa równowa
ż
ne
//p_76_12
/* 17L04.c: Use the realloc() function */#include <stdio.h>
#include <stdlib.h>#include <string.h>/* function declaration
*/void StrCopy(char *str1, char *str2);
/* main() function */
main()
{
char *str[4] = {"There's music in the sighing of a reed;",
"There's music in the gushing of a rill;",
"There's music in all things if men had ears;",
"There earth is but an echo of the spheres.\n"
};
char *ptr;
int i;
int termination = 0;
ptr = malloc(strlen((str[0]) + 1) * sizeof(char));
if (ptr == NULL){
printf("malloc() failed.\n");
termination = 1;
}
else{
StrCopy(str[0], ptr);
printf("%s\n", ptr);
132
for (i=1; i<4; i++){
ptr = realloc(ptr, (strlen(str[i]) + 1) * sizeof(char));
if (ptr == NULL){
printf("realloc() failed.\n");
termination = 1;
break;
}
else{
StrCopy(str[i], ptr);
printf("%s\n", ptr);
}
}
}
free(ptr);
return termination;
}
/* funciton definition */
void StrCopy(char *str1, char *str2)
{
int i;
for (i=0; str1[i]; i++)
str2[i] = str1[i];
str2[i] = '\0';
}
Funkcja ma za zadanie przyporz
ą
dkowa
ć
dynamicznie blok pami
ę
ci
do przechowywania ła
ń
cucha znakowego. W przykł
ą
dzie wyst
ę
puj
ą
133
4 ła
ń
cuchy znakowe o ró
ż
nej długo
ś
ci. Aby przystosowa
ć
wielko
ść
poprzednio przyporz
ą
dkowanego obszaru pami
ę
ci do
nastepnego ła
ń
cucha znaków stosowana jest funkcja realloc().
Wykorzystano tablic
ę
wska
ź
ników str do 4 ła
ń
cuchów tekstowych.
Obszar pami
ę
ci zostaje przyporz
ą
dkowany, a jego rozmiar
dostosowany do aktualnych potrzeb w oparciu o długo
ść
ka
ż
dego
ł
ąń
cucha znaków. Obie stosowane funkcje malloc() i realloc()
dokonuj
ą
przydziału obszaru pami
ę
ci i regulacji jego rozmiaru
w sposób dynamiczny – tzn w ruchu programu.
Wyliczeniowy typ danych
Wyliczeniowy typ danych umo
ż
liwia skojarzenie nazw
symbolicznych ze stałymi numerycznymi typu integer.
Deklaracja:
enum nazwa {lista wyliczeniowa} lista zmiennych;
enum – słowo kluczowe;
nazwa – nazwa typu wyliczeniowego;
lista zmiennych – nazwy zmiennych danego typu wyliczeniowego;
134
lista wyliczeniowa – identyfikatory – zdefiniowane stałe
tekstowe, u
ż
ywane do reprezentacji numerycznych stałych
całkowitych;
wariant 1:
enum auto {sedan, pick_up, sport} krajowe, zagraniczne;
wariant 2:
enum auto {sedan, pick_up, sport};
auto krajowe, zagraniczne;
Przypisanie warto
ś
ci liczbowych do typu wyliczeniowego.
Standardowo gdy programista nie zadeklaruje inaczej:
Stała symboliczna wymieniona na pocz
ą
tku listy wyliczeniowej
ma przypisan
ą
warto
ść
0, nast
ę
pne kolejno i 1 wi
ę
ksz
ą
.
Sposób przyporz
ą
dkowania stałych int w programie:
enum auto {sedan=60, pick_up=30, sport=10};
//p_77
#include <stdio.h>#include <conio.h>void main(void){enum jezyk
{human=100,animal=50,computer};enum dni
{pon,wto,sro,czw,pio,sob,nie};clrscr();printf("human %d,
animal %d, computer %d\n",human,animal,computer);
printf("pon %d\n",pon);
printf("wto %d\n",wto);
135
printf("sro %d\n",sro);
printf("czw %d\n",czw);
printf("pio %d\n",pio);
printf("sob %d\n",sob);
printf("nie %d\n",nie);
getch();
}
powy
ż
szy przykład ilustruje automatyczne i r
ę
czne
przyporz
ą
dkowanie stałym symbolicznym warto
ś
ci numerycznych
typu int;
/p_78
#include <stdio.h>#include <conio.h>void main(void){enum
money_units{grosik=1,piatka=5,dycha=10,polowka=50,zlocisz=100}
; int money_units[5]={zlocisz,polowka,dycha,piatka,grosik};
char *unit_name[5]={"złocisz(-ów)","połów(-ka/ek)","dycha(-
ch)","pi
ą
tka(-ek)","grosik(-ow)"};
int cent,tmp,i;
clrscr();
printf("Wpisz sum
ę
w groszach:\n");
scanf("%d",¢);
printf("Odpowiada to zestawowi monet:\n");
tmp=0;
for(i=0;i<5;i++)
136
{
tmp=cent/money_units[i];
cent-=tmp*money_units[i];
if(tmp)
printf("%d %s ",tmp,unit_name[i]);
}
printf("\n");
getch();
}
Zadaniem programu jest wykorzystanie typu wyliczeniowego do
reprezentacji sumy wprowadzonej przez u
ż
ytkownika za pomoc
ą
zestawu monet.
typ wyliczeniowy money_units wykorzystywany jest do
przyporz
ą
dkowanie stałym symbolicznym warto
ś
ci monet złocisz –
100 (gr) , dycha – 10 (gr) itd;
deklarowana tablica numeryczna typu int inicjowana jest
stałymi symbolicznymi typu wyliczeniowego – co odpowiada :
int money_units[5]={100,50,10,5,1} à po zadeklarowaniu typu
wyliczeniowego mo
ż
na stosowa
ć
stałe symboliczne z listy
wyliczeniowej zamiast odpowiadaj
ą
cych im warto
ś
ci
numerycznych;
delaracja tablicy zło
ż
onej ze wska
ź
ników do ła
ń
cuchów
tekstowych umo
ż
liwi wyprowadzanie opisów;
Definiowanie typów u
ż
ytkownika.
137
typedef int liczba_2bajty;
liczba_2bajty i,j,k,l; ß à int i,j,k,l;
Definicja typu typedef tworzy synonim deklaracji typu i musi
wyst
ą
pi
ć
w programie zanim ten synonim zostanie u
ż
yty.
umo
ż
liwia uproszczenie nazwy skomplikowanego typu danych do
pojedynczego słowa;
po dokonaniu jednokrotnej korekty definicji synonimu, mo
ż
na
u
ż
ywac tego nowego synonimu wielokrotnie w przyszłosci;
138
Przekazywanie do funkcji main() argumentów z wiersza polece
ń
.
Argumenty z wiersza polece
ń
przekazujemy podczas uruchamiania
wersji exe programu napisanego w j
ę
zyku C.
Maj
ą
c program o nazwie prog.c à prog.exe
C:> prog argument1, argument2, argument3
Argumenty 1-3 sa argumentami z wiersza polece
ń
Funkcja main() posiada dwa wbudowane argumenty , które mog
ą
by
ć
wykorzystane do pobierania parametrów z wiersza polece
ń
systemu operacyjnego /trzeci odnosi si
ę
do otoczenia
systemowego/.
Pierwszy nazywa si
ę
argc – słu
ż
y on do przechowywania
całkowitej liczby parametrów przekazywanych do funkcji main()
z wiersza polece
ń
.
Drugi argv – jest wska
ź
nikiem do tablicy wska
ź
ników – ła
ń
cuchy
znaków. Ka
ż
dy element tej tablicy wskazuje jeden argument z
wiersza polece
ń
, traktowany jako ła
ń
cuch znaków;
typ_wy main(int argc, char *argv[])
{
}
Przy wywołaniu prog.exe argc=4 gdy
ż
nazwa programu jest
uznawana jako pierwszy argument z wiersza polece
ń
;
argv[0]=”c:\programy\prog.exe”
argv[1]=”argument1”
argv[2]=”argument2”
139
argv[3]=”argument3”
//p_79
#include <stdio.h>#include <conio.h>void main(int argc,char
*argv[]){ int i; clrscr(); printf("%d\n",argc);
printf("%d\n",argc); for(i=0;i<argc;i++)
printf("%s\n",argv[i]); getch();
}
140
Struktura – ł
ą
czenie ró
ż
nych typów danych
Struktura jest poł
ą
czeniem w cało
ść
danych ró
ż
nych typów, tak
aby mogły stanowi
ć
jeden moduł.
Róznica mi
ę
dzy strukturami a tablicami:
w obr
ę
bie struktury mog
ą
znajdowa
ć
ró
ż
ne typy;
ka
ż
dy element w strukturze ma swoj
ą
własna nazw
ę
;
Elementy danych wchodz
ą
ce w skł
ą
d struktury – pola struktury;
Deklarowanie struktur
struct nazwa_struct{
typ zmienna1;
typ zmienna2;
typ zmienna3;
};
struct auto{
int rok;
char model[8];
int moc_silnika;
float masa;
141
};
Definiowanie struktur
struct auto sedan,pick_up,sport;
struct auto{
int rok;
char model[8];
int moc_silnika;
float masa;
} seadan, pick_up, sport;
Odwoływanie si
ę
do elementów struktur – operator .
zmienna_struktury.nazwa_pola
ptr=sport.model;
//p_80
#include <stdio.h>#include <conio.h>void main(void){struct
komputer { float koszt; int rok; int cpu_cz; char cpu_typ[16];
} model; clrscr(); printf("Podaj typ CPU: \n");
gets(model.cpu_typ); printf("Podaj cz
ę
st. CPU w MHz: \n");
scanf("%d",&model.cpu_cz);
142
printf("Podaj rok produkcji: \n");
scanf("%d",&model.rok);
printf("Podaj cene jego zakupu: \n");
scanf("%f",&model.koszt);
printf("Oto wprowadzone dane: \n");
printf("Rok produkcji : %d \n",model.rok);
printf("Cena zakupu : %6.2f \n",model.koszt);
printf("Typ CPU : %s \n",model.cpu_typ);
printf("Szybko
ść
CPU w MHZ : %d \n",model.cpu_cz);
getch();
}
powy
ż
szy program demonstruje dowołania do poszczególnych pól
struktury
Inicjowanie struktur
Poni
ż
szy program przedstawia sposób inicjowania struktury, a
nast
ę
pnie aktualizacj
ę
zawarto
ś
ci pól danych przez
u
ż
ytkownika.
//p_81
#include <stdio.h>#include <conio.h>void main(void){struct
pracownik
{
int nr;
char nazwisko[32];
};
143
struct pracownik info = { 0001,"J.Nowak"};
clrscr();
printf("Wydruk pól struktury\n");
printf("Nazwisko pracownika: %s\n",info.nazwisko);
printf("Numer ID #: %04d\n",info.nr);
printf("Podaj swoje nazwisko: ? \n");
gets(info.nazwisko);
printf("Podaj swój numer: ? \n");
scanf("%d",&info.nr);
printf("Wprowadziłe
ś
dane: \n");
printf("Nazwisko pracownika: %s\n",info.nazwisko);
printf("Numer ID #: %04d\n",info.nr);
getch();
}
definicja, deklaracja i zainicjowanie struktury w pojedy
ń
czej
instrukcji
struct pracownik
{
int nr;
char nazwisko[30];
} info = {0001,”J.Nowak”};
144
Struktury a funkcje
J
ę
zyk C pozwala przekaza
ć
cał
ą
struktur
ę
jako argument do
funkcji, jak równie
ż
funkcja mo
ż
e zwrócic struktur
ę
jako
warto
ść
.
Demonstruje to poni
ż
szy przykład.
//p_82
#include <stdio.h>#include <conio.h>struct komputer { float
koszt; int rok; int cpu_cz; char cpu_typ[16]; }; typedef
struct komputer SC; SC PobierzDane(SC s);
void main(void)
{
SC model;
clrscr();
model=PobierzDane(model);
printf("Dane, które wprowadziłe
ś
: \n");
printf("Rok: %d \n",model.rok);
printf("Cena: %6.2f \n",model.koszt);
printf("CPU typ: %s \n",model.cpu_typ);
printf("Predko
ść
: %d MHz \n",model.cpu_cz);
getch();
}
SC PobierzDane(SC s)
{
printf("Podaj typ CPU: \n");
gets(s.cpu_typ);
printf("Podaj cz
ę
st. CPU w MHz: \n");
145
scanf("%d",&s.cpu_cz);
printf("Podaj rok produkcji: \n");
scanf("%d",&s.rok);
printf("Podaj cene jego zakupu: \n");
scanf("%f",&s.koszt);
return s;
}
Wska
ź
niki do struktur
Podobnie jak przekazuje si
ę
funkcjom wska
ź
niki do tablic, tak
mo
ż
na przekaza
ć
im równie
ż
w postaci argumentu wska
ź
nik
wskazuj
ą
cy struktur
ę
.
W przeciwie
ń
stwie do przekazywania całej struktury w formie
argumentu do funkcji , co powodowało na u
ż
ytek funkcji
tworzenie kopii całej struktury, przekazanie do funkcji
wska
ź
nika powoduje jedynie przekazanie jej adresu w pami
ę
ci,
pod którym zlokalizowana jest struktura. Funkcja mo
ż
e
posługiwac si
ę
tym adresem , odwołuj
ą
c si
ę
bezpo
ś
rednio do pól
struktury, a nie do kopii struktury.
Prezentuje to poni
ż
szy program.
//p_83
#include <stdio.h>#include <conio.h>struct komputer { float
koszt; int rok; int cpu_cz;
char cpu_typ[16];
};
typedef struct komputer SC;
void PobierzDane(SC *ptr_s);
void main(void)
{
146
SC model;
clrscr();
PobierzDane(&model);
printf("Dane, które wprowadziłe
ś
: \n");
printf("Rok: %d \n",model.rok);
printf("Cena: %6.2f \n",model.koszt);
printf("CPU typ: %s \n",model.cpu_typ);
printf("Predko
ść
: %d MHz \n",model.cpu_cz);
getch();
}
void PobierzDane(SC *ptr_s)
{
float pomoc;
printf("Podaj typ CPU: \n");
gets((*ptr_s).cpu_typ);
printf("Podaj cz
ę
st. CPU w MHz: \n");
scanf("%d",&(*ptr_s).cpu_cz);
printf("Podaj rok produkcji: \n");
scanf("%d",&(*ptr_s).rok);
printf("Podaj cene jego zakupu: \n");
scanf("%f",&pomoc);
(*ptr_s).koszt=pomoc;
147
// scanf("%f",&(*ptr_s).koszt);
}
(*ptr_s).pole à odwołanie si
ę
do pola struktury
co mo
ż
na zast
ą
pic przez
ptr_s à pole
natomiast wyra
ż
enie: &(*ptr_s).pole przez: &(ptr_s à pole)
ilustruje to poni
ż
szy przykład:
//p_84
#include <stdio.h>#include <conio.h>struct komputer {
float koszt;
int rok;
int cpu_cz;
char cpu_typ[16];
};
typedef struct komputer SC;
void PobierzDane(SC *ptr_s);
void main(void)
{
SC model;
clrscr();
PobierzDane(&model);
printf("Dane, kt˘re wprowadzi
�
e
�
: \n");
148
printf("Rok: %d \n",model.rok);
printf("Cena: %6.2f \n",model.koszt);
printf("CPU typ: %s \n",model.cpu_typ);
printf("Predko
ść
: %d MHz \n",model.cpu_cz);
getch();
}
void PobierzDane(SC *ptr_s)
{
float pomoc;
printf("Podaj typ CPU: \n");
gets(ptr_s->cpu_typ);
printf("Podaj cz
ę
st. CPU w MHz: \n");
scanf("%d",&(ptr_s->cpu_cz));
printf("Podaj rok produkcji: \n");
scanf("%d",&(ptr_s->rok));
printf("Podaj cene jego zakupu: \n");
scanf("%f",&pomoc);
ptr_s->koszt=pomoc;
// scanf("%f",&(*ptr_s.koszt));
}
149
Tablice struktur
W j
ę
zyku C mo
ż
na zadeklarowa
ć
tablic
ę
, której elementami b
ę
d
ą
struktury.
Nale
ż
y nazw
ę
tablicy (identyfikator) poprzedzi
ć
nazw
ą
typu
struktur.
struct x tablica[8];
jest deklaracj
ą
8-elementowej jednowymiarowej tablicy, której
elementami s
ą
struktury typu x.
//p_85
#include <stdio.h>#include <conio.h>struct wiersz { int
start_year; int end_year; char autor[16]; char str1[64]; char
str2[64]; char str3[64]; }; typedef struct wiersz WS;
void WyswietlDane(WS *ptr_s);
void main(void)
{
WS poemat[2]=
{
{1641,
1716,
"Autor1",
"Wiersz01",
"Wiersz02",
150
"Wiersz03"
},
{1729,
1781,
"Autor2",
"Wiersz11",
"Wiersz12",
"Wiersz13"
}
};
int i;
clrscr();
for(i=0;i<2;i++)
WyswietlDane(&poemat[i]);
getch();
}
void WyswietlDane(WS *ptr_s)
{
printf("%s\n",ptr_s->str1);
printf("%s\n",ptr_s->str2);
printf("%s\n",ptr_s->str3);
printf("---%s\n",ptr_s->autor);
printf(" (%d-%d)\n\n",ptr_s->start_year,ptr_s->end_year);
}
151
Struktury zagnie
ż
dzone
Struktury nazywane sa strukturami zagnie
ż
dzonymi je
ś
li co
najmniej jedno z pól struktury jest struktur
ą
.
struct x
{
int a;
float b;
};
struct y
{
int i;
char ch[10];
x strukt_wew
};
struktura y stanowi strukture zło
ż
ona z zagnie
ż
dzona wewn
ą
trz
struktur
ą
x
//p_86
#include <stdio.h>#include <conio.h>struct dzial { int kod;
char nazwa[32]; char stanowisko[16]; }; typedef struct dzial
DZ;
struct pracownik
{
DZ d;
int id;
char nazwisko[32];
};
152
typedef struct pracownik PRAC;
void InfoWyswietl(PRAC *ptr);
void InfoWprowadz(PRAC *ptr);
void main(void)
{
PRAC info =
{
{ 01,
"Marketing",
"Manager"
},
0001,
"J.Nowak"
};
clrscr();
printf("Przykład: \n");
InfoWyswietl(&info);
InfoWprowadz(&info);
printf("\nOto dane, które wprowadziłe
ś
: \n");
InfoWyswietl(&info);
getch();
}
void InfoWyswietl(PRAC *ptr)
{
printf("Nazwisko: %s \n",ptr->nazwisko);
printf("Numer : %04d \n",ptr->id);
153
printf("Nazwa działu : %s \n ",ptr->d.nazwa);
printf("Numer działu : %02d \n",ptr->d.kod);
printf("Stanowisko: %s \n",ptr->d.stanowisko);
}
void InfoWprowadz(PRAC *ptr)
{
printf("\n Wpisz swoje dane: \n");
printf("Nazwisko: \n");
gets((*ptr).nazwisko);
printf("Funkcja: \n");
gets((*ptr).d.stanowisko);
printf("Nazwa działu: \n");
gets((*ptr).d.nazwa);
printf("Numer działu: \n");
scanf("%d",&(ptr->d.kod));
printf("Twój numer ID : \n");
scanf("%d",&(ptr->id));
}
dost
ę
p do danych ptr à nazwa_zm_str_wew.nazwa_pola
Forward reference – wyprzedzaj
ą
ce odwoływanie si
ę
do struktur
Je
ż
eli jednym z elementów struktury jest wska
ź
nik do struktur
innego typu, który to typ struktur nie został jeszcze
zadeklarowany, to struktura taka nazywa si
ę
struktura ze
wskazaniem wyprzedzaj
ą
cym – forward referencing structure.
154
struct x
{
int i;
char ch[10];
struct y *ptr;
};
oczywi
ś
cie przy zało
ż
eniu
ż
e typ struktury y nie został
jeszcze zadeklarowany;
je
ż
eli wska
ź
nik b
ę
d
ą
cy elementem struktury wskazuje na ni
ą
sam
ą
, to struktura taka nazywa si
ę
auto referencyjn
ą
:
struct x
{
int i;
char ch[10];
struct x *ptr;
};
//p_87
#include <stdio.h>#include <conio.h>struct dane
{
char name[16];
struct date *p;
struct date *d;
};
struct date
{
155
int rok;
char szkola[32];
char stopien[8];
};
typedef struct dane DAN;
typedef struct date DAT;
void InfoWyswietl(DAN *ptr);
void main(void)
{
DAT pier =
{
1985,
"Politechnika",
"in
ľ
"
};
DAT drug =
{
1988,
"AGH",
"mgr in
ľ
"
};
DAT *pp,*pd;
pp=&pier;
pd=&drug;
DAN prac =
156
{
"Marek",
pp,
pd
//&pier,
//&drug
};
clrscr();
printf("To sa dane Marka: \n");
InfoWyswietl(&prac);
getch();
}
void InfoWyswietl(DAN *ptr)
{
printf("Imie: %s \n",ptr->name);
printf("Nazwa szkoły: %s \n",ptr->p->szkola);
printf("Data uzyskania tytułu %d \n",ptr->p->rok);
printf("Stopie
ń
: %s \n",ptr->p->stopien);
printf("Nazwa szkoły: %s \n",ptr->d->szkola);
printf("Data uzyskania tytułu %d \n",ptr->d->rok);
printf("Stopie
ń
: %s \n",ptr->d->stopien);
}
nowy sposób odwołania do pola : ptr à d à stopien
157
Unie
158
Unia jest to blok pami
ę
ci u
ż
ywany do przechowywania róznych
elementów danych.
W j
ę
zyku C unia jest podobna do struktury , z tym wyj
ą
tkiem
ż
e
dane zawarte w unii nakładaj
ą
si
ę
wzajemnie na siebie –
poniewa
ż
dziel
ą
mi
ę
dzy siebie ten sam obszar pami
ę
ci.
Deklarowanie unii
union auto {
int rok;
char model[8];
int moc_silnika;
float waga;
};
union – słowo kluczowe /okresla kategorie typu danych/
auto - nazwa typu danych
{
} - struktura wewn
ę
trzna unii zawieraj
ą
ca jej pola nazywane
równie
ż
jej elementami; poniewa
ż
elementy unii mog
ą
si
ę
nawzajem nakładac zatem nazwa element jest zasadniejsza od
nazwy pole;
Definiowanie zmiennych unii
union auto sedan, pick_up, sport;
union auto {
int rok;
char model[8];
int moc_silnika;
159
float waga;
} sedan, pick_up, sport;
je
ż
eli poł
ą
czymy deklaracj
ę
typu unii i definicj
ę
zmiennych
danego typu w pojedyncz
ą
instrukcj
ę
mo
ż
emy w tej instrukcji
pomin
ąć
identyfikator typu unii: (słowo auto)
union {
int rok;
char model[8];
int moc_silnika;
float waga;
} sedan, pick_up, sport;
podobnie jak w przypadku elementów struktury, tak i w
przypadku do elementów składowych unii mo
ż
e by
ć
stosowany
operator .
sedan.year=1997;
po zadeklarowaniu wska
ź
nika do zmiennych unii
union auto *ptr;
ptr à year = 1997;
//p_88
#include <stdio.h>#include <string.h>
#include <conio.h>
void main(void)
{
union menu
{
char nazwa[20];
double cena;
160
} danie;
clrscr();
printf("Zawarto
ść
unii\n");
strcpy(danie.nazwa,"kotlet schabowy");
printf("Nazwa dania: %s\n",danie.nazwa);
danie.cena=12.95;
printf("Cena dania: %5.2f\n",danie.cena);
printf("Ko
ń
cowa zawarto
ść
unii %s",danie.nazwa);
getch();
}
przykład powy
ż
szy pokazuje sposób dost
ę
pu do elementów unii;
ostatnia instrukcja printf jest dowodem nakładania w pami
ę
ci
elementów unii na siebie;
potwierdzaj
ą
to dwa poni
ż
sze przykłady:
//p_89
#include <stdio.h>#include <string.h>#include <conio.h>void
main(void){ union menu { char nazwa[20]; double cena; } danie;
clrscr(); printf("Zawarto
ść
unii\n"); danie.cena=12.95;
printf("Cena dania: %5.2f\n",danie.cena);
strcpy(danie.nazwa,"kotlet schabowy");
printf("Nazwa dania: %s\n",danie.nazwa);
printf("Ko
ń
cowa zawarto
ś
c unii %s\n",danie.nazwa);
printf("Cena dania: %5.2f\n",danie.cena);
getch();
}
//p_90
161
#include <stdio.h>#include <string.h>#include <conio.h>void
main(void){ union menu { char nazwa[20]; double cena; } danie;
clrscr(); printf("Zawarto
ś
c unii\n"); danie.cena=12.95;
printf("Cena dania: %5.2f\n",danie.cena);
strcpy(danie.nazwa,"kotlet schabowy");
printf("Nazwa dania: %s\n",danie.nazwa);
printf("Koäcowa zawarto
ść
unii %5.2f ",danie.cena);
getch();
}
Inicjowanie unii
Elementy danych unii nakładaj
ą
si
ę
nawzajem na siebie w
obr
ę
bie tego samego obszaru pami
ę
ci. Obszar ten jest
wykorzystywany do zapisu ró
ż
nych danych w ró
ż
nym czasie.
Rozmiar unii odpowiada rozmiarowi najwi
ę
kszego spo
ś
ród jej
elementów. Daltego nie ma sensu inicjowanie wszystkich
elementów unii jednoczesnie, poniewa
ż
warto
ść
ostatnio
inicjowanego elementu nadpisze si
ę
na warto
ść
poprzednich.
Element unii inicjuje si
ę
tylko wtedy gdy jeste
ś
my gotowi do
jego wykorzystania. Bie
żą
ca warto
ść
zawarta w unii jest zawsze
warto
ś
cia ostatniego elementu przypisanego unii.
union u {
char ch;
int x;
} n_unia;
n_unia.ch=’H’;
n_unia.x=365;
najpierw pami
ę
c przeznaczona na elementy unii zawierała ‘H’
potem warto
ś
c 365.
union u {
char ch;
162
int x;
} n_unia = {‘H’);
co si
ę
stanie gdy zainicjujemy wszystkie elementy unii
jednoczesnie ?
//p_91
#include <stdio.h>#include <string.h>#include <conio.h>void
main(void){ union sprawa { int rok; int dzial; int id; } info;
info.rok=1999; info.dzial=234; info.id=1234; clrscr();
printf("Rok: %d\n",info.rok);
printf("Numer dziaˆu: %d\n",info.dzial);
printf("Numer identyfikacyjny: %d\n",info.id);
getch();
}
wynik jest oczywisty à 1234
Rozmiar unii
163
Wielko
ść
unii jest równa obszarowi zajmowanemu przez
najwi
ę
kszy jej element.
W przeciwie
ń
stwie do unii, w strukturze wszystkie elementy
(pola) struktury mog
ą
by
ć
zainicjowane jednocze
ś
nie i nie
nakładaja si
ę
nawzajem. Dzieje si
ę
tak dlatego,
ż
e ka
ż
dy
element struktury ma własny obszar pami
ę
ci. Rozmiar struktury
to suma rozmiarów wszystkich jej elementów (pól), a nie jak w
przypadku unii rozmiar jej najwi
ę
kszego elementu.
Pokazuje to przykład:
//p_92
#include <stdio.h>#include <string.h>#include <conio.h>
void main(void)
{
union u
{
double x;
int y;
} a_union;
struct s
{
double x;
int y;
} a_struct;
clrscr();
printf("Rozmiar double: %d-bajtowe \n",sizeof(double));
printf("Rozmiar int : %d-bajtowe \n",sizeof(int));
printf("Rozmiar unii a_union: %d-bajtowe \n",sizeof(a_union));
164
printf("Rozmiar struktury a_struct: %d-bajtowe
\n",sizeof(a_struct));
getch();
}
Zastosowania unii
Odwoływanie si
ę
do tego samego obszaru pami
ę
ci na dwa ró
ż
ne
sposoby
Np.:
//p_93
165
#include <stdio.h>#include <string.h>#include <conio.h>union u
{ char ch[2]; int num; };int InicjalizacjaUnii(union u
val);void main(void){ union u val;
int x;
x=InicjalizacjaUnii(val);
clrscr();
printf("Dwie stałe znakowe zawarte w unii: \n");
printf("%c \n",x & 0x00FF); /*młodszy bajt*/
printf("%c \n",x>>8); /*starszy bajt*/
getch();
}
int InicjalizacjaUnii(union u val)
{
val.ch[0]='H';
val.ch[1]='i';
return val.num; /*posługujemy sie elementem numerycznym unii
*/
/*do przesłania danych do f. main()*/
}
Uelastycznienie struktur
Zagnie
ż
dzenie unii wewn
ą
trz struktury powoduje,
ż
e w polach
struktur mog
ą
by
ć
przechowywane dane ró
ż
nych typów.
166
Przykład:
//p_94
#include <stdio.h>#include <conio.h>#include <string.h>struct
ankieta { char name[20]; char c_d_p; int wiek; int
hour_per_week; union { char cable[16]; char sat[16];
} dostawca;
};
void DataEnter(struct ankieta *s);
void DataDisplay(struct ankieta *s);
void main(void)
{
struct ankieta tv;
clrscr();
DataEnter(&tv);
DataDisplay(&tv);
getch();
}
void DataEnter(struct ankieta *ptr)
{
char jest_tak[4];
printf("Czy korzystasz w domu z telewizji kablowej T/N \n");
gets(jest_tak);
if ((jest_tak[0]=='T')||(jest_tak[0]=='t'))
{
printf("Wpisz nazw
ę
firmy dostawcy TV kablowej: \n");
gets(ptr->dostawca.cable);
167
ptr->c_d_p='c';
}
else
{
printf("Czy korzystasz z TV sat T/N \n");
gets(jest_tak);
if((jest_tak[0]=='T')||(jest_tak[0]=='t'))
{
printf("Wpisz nazwe firmy diostwcy TV sat \n");
gets(ptr->dostawca.sat);
ptr->c_d_p='d';
}
else
ptr->c_d_p='p';
}
printf("Wpisz swoje nazwisko: \n");
gets(ptr->name);
printf("i sw˘j wiek: \n");
scanf("%d",&ptr->wiek);
printf("Ile godzin tygodniowo ogl
ą
dasz TV : \n");
scanf("%d",&ptr->hour_per_week);
}
void DataDisplay(struct ankieta *ptr)
{
printf("\nOto dane, kt˘re wprowadziłe
ś
: \n");
168
printf("Nazwisko: %s\n",ptr->name);
printf("Wiek: %d \n",ptr->wiek);
printf("Godzin tygodniowo: %d\n",ptr->hour_per_week);
if(ptr->c_d_p=='c')
printf("Twoja firma TV kablowej :%s\n",ptr->dostawca.cable);
else
if(ptr->c_d_p=='d')
printf("Twoja firma TV Sat: %s \n",ptr->dostawca.sat);
else
printf("Niekorzystasz ani z kabla ani z TV sat\n");
printf("Dzi
ę
kujemy -- Koniec aniekty! \n");
}
Definiowanie pól bitowych przy pomocy słowa kluczowego struct
Typ char to najmniejszy typ danych w j
ę
zyku C. Dane te zajmuja
8 bitów.
Jednak posługuj
ą
c si
ę
słowem kluczowym struct mo
ż
na
zadeklarowa
ć
obiekt jeszcze mniejszy - pole bitowe /bit
field/.
Pole bitowe umo
ż
liwia łatwy dost
ę
p do pojedynczych bitów.
Pojedynczy bit mo
ż
e przyjmowa
ć
jedna z warto
ś
ci 0 lub 1.
Format deklaracji:
struct nazwa {
data_typ_1 nazwa1: dlugosc1;
169
data_typ_2 nazwa2: dlugosc2;
.....................................................
data_typ_N nazwanN: dlugoscN;
} lista_zmiennych;
struct - słowo kluczowe
nazwa - nazwa typu zmiennych
data_typ_i - typ danych kolejnego pola bitowego (musi by
ć
jednym z typów : int, unsigned, signed)
nazwai - nazwy poszczególnych pól bitowych
długosci – długo
ś
ci poszczególnych pól bitowych, które nie
mog
ą
przekraczac długo
ś
ci typu danych int
lista_zmiennych - wyliczenie zmiennych danego typu
struct bf {
int jumper1: 1;
int jumper2: 2;
int jumper3: 3;
} jumpers;
jumper1 jumper2 jumper3 trzy pola bitowe o długo
ś
ciach
odpowiednio: 1, 2, 3 bity
zmienna o nazwie jumpers jest struktur
ą
zawieraj
ą
ca trzy pola
bitowe.
jumper1 jumepr2 jumper3
//p_95
#include <stdio.h>#include <conio.h>#include <string.h>struct
bit_field
170
{
int cable: 1;
int sat: 1;
};
struct ankieta
{
char name[20];
struct bit_field c_d;
int wiek;
int hour_per_week;
union
{
char cable[16];
char sat[16];
} dostawca;
};
void DataEnter(struct ankieta *s);
void DataDisplay(struct ankieta *s);
void main(void)
{
struct ankieta tv;
clrscr();
DataEnter(&tv);
DataDisplay(&tv);
getch();
171
}
void DataEnter(struct ankieta *ptr)
{
char jest_tak[4];
printf("Czy korzystasz w domu z telewizji kablowej T/N \n");
gets(jest_tak);
if ((jest_tak[0]=='T')||(jest_tak[0]=='t'))
{
printf("Wpisz nazw
ę
firmy dostawcy TV kablowej: \n");
gets(ptr->dostawca.cable);
ptr->c_d.cable=1;
ptr->c_d.sat=0;
}
else
{
printf("Czy korzystasz z TV sat T/N \n");
gets(jest_tak);
if((jest_tak[0]=='T')||(jest_tak[0]=='t'))
{
printf("Wpisz nazwe firmy diostwcy TV sat \n");
gets(ptr->dostawca.sat);
ptr->c_d.cable=0;
ptr->c_d.sat=1;
}
else
{
172
ptr->c_d.cable=0;
ptr->c_d.sat=0;
}
}
printf("Wpisz swoje nazwisko: \n");
gets(ptr->name);
printf("i swój wiek: \n");
scanf("%d",&ptr->wiek);
printf("Ile godzin tygodniowo ogl
Ą
dasz TV : \n");
scanf("%d",&ptr->hour_per_week);
}
void DataDisplay(struct ankieta *ptr)
{
printf("\nOto dane, które wprowadziłe
ś
: \n");
printf("Nazwisko: %s\n",ptr->name);
printf("Wiek: %d \n",ptr->wiek);
printf("Godzin tygodniowo: %d\n",ptr->hour_per_week);
if(ptr->c_d.cable && !ptr->c_d.sat)
printf("Twoja firma TV kablowej :%s\n",ptr->dostawca.cable);
else
if(!ptr->c_d.cable && ptr->c_d.sat)
printf("Twoja firma TV Sat: %s \n",ptr->dostawca.sat);
else
printf("Nie korzystasz ani z kabla ani z TV sat\n");
173
printf("Dzi©kujemy -- Koniec aniekty! \n");
}
Operacje na plikach dyskowych
Plik
Poj
ę
cie pliku odnosi si
ę
do urz
ą
dzenia peryferyjnego
(terminal, drukarka, plik na ta
ś
mie, plik na dysku) z którym
ma nast
ą
pi
ć
wymiana informacji.
Przed rozpocz
ę
ciem procesu wymiany informacji plik nale
ż
y
otworzy
ć
, za
ś
po zako
ń
czeniu tego procesu nale
ż
y go zamkn
ąć
.
Strumie
ń
Przepływ danych z programu do pliku lub odwrotnie nazywamy
strumieniem danych.
Strumie
ń
stanowi seri
ę
bajtów.
174
Strumie
ń
nie jest zwi
ą
zany z
ż
adnym urz
ą
dzeniem.
Aby przeprowadzi
ć
operacj
ę
wej
ś
cia/wyj
ś
cia nale
ż
y skojarzy
ć
plik ze strumieniem.
Istniej
ą
dwa formaty strumieni :
1/ Strumie
ń
tekstowy - zawiera sekwencje znaków; stosowany do
przesyłania danych tekstowych;
2/ Strumie
ń
binarny - stanowi seri
ę
bajtów (np. plik exe);
Stosowany do danych nietektowych;
Buforowanie wej
ś
cia/wyj
ś
cia
Buforem nazywamy obszar pami
ę
ci słu
żą
cy do tymczasowego
przechowywania danych przed przesłaniem ich do miejsca
przeznaczenia.
Strumienie wej
ś
cia/wyj
ś
cia s
ą
buforowane w sposób domy
ś
lny.
Buforowane wej
ś
cie/wyj
ś
cie na zywane jest obsług
ą
We/Wy
wysokiego poziomu, za
ś
nie buforowane wej
ś
cie/wyj
ś
cie obsług
ą
We/Wy niskiego poziomu.
Podstawy operacji We/Wy
Wska
ź
niki typu FILE
Struktura FILE słu
ż
y do zarz
ą
dzania plikami, zdefiniowana w
pliku nagłówkowym stdio.h.
Wska
ź
nik typu FILE jest wska
ź
nikiem plikowym i jest
wykorzystywany przez strumie
ń
do sterowania operacjami We/Wy .
FILE *fptr;
W obr
ę
bie struktury FILE znajduje si
ę
wska
ź
nik pozycji w
pliku, który wskazuje bie
żą
c
ą
pozycje podczas operacji
zapisu/odczytu danych.
Otwieranie pliku
175
Funkcja fopen() pozwala na otwarcie pliku i skojarzenie go ze
strumieniem danych. Wymaga ona podania dwóch argumentów: trybu
otwarcia i nazwy przedmiotowego pliku.
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
filename - nazwa pliku do otwarcia /wska
ź
nik do stałego
ła
ń
cucha znaków/
mode - tryb otwarcia pliku /wska
ź
nik do stałego ła
ń
cucha
znaków/
Funkcja zwraca wska
ź
nik typu FILE.
Je
ż
eli wystapi bł
ą
d otwarcia , funkcja zwraca wska
ź
nik pusty.
Tryby otwarcia pliku – mode
r - otwiera istniej
ą
cy plik tekstowy tylko do odczytu
w - tworzy nowy plik tekstowy do zapisu
a - otwiera istniej
ą
cy plik tekstowy w trybie dopisywania do
ko
ń
ca pliku
r+ - otwiera istniej
ą
cy plik tekstowy do odczytu i/lub zapisu
w+ - tworzy plik tekstowy do zapisu i/lub odczytu
a+ - otwiera lub tworzy plik tekstowy do dopisywania na ko
ń
cu
rb - otwiera istniej
ą
cy plik binarny do odczytu
wb - tworzy nowy plik binarny do zapisu
ab - otwiera istneij
ą
cy plik binarny w trybie dopisywania do
ko
ń
ca pliku
r+b - otwiera istniej
ą
cy plik binarny dla odczytu i/lub zapisu
w+b - tworzy plik binarny do zapisu i/lub zapisu
a+b - otwiera lub tworzy plik binarny do dopisywania na ko
ń
cu
próba otwarcia pliku test.txt
FILE *fprt;
176
if ((fptr = fopen(”test.txt”,”r”))==NULL)
{
printf(”Nie mog
ę
otworzy
ć
pliku test.txt \n”);
exit(1);
}
.........
Zamykanie pliku
Po wykonaniu operacji na otwartym pliku dyskowym (r,w,a),
nale
ż
y odł
ą
czy
ć
plik od strumienia danych – zamkn
ąć
go à
fclose().
#include <stdio.h>
int fclose(FILE *pointer);
pointer - wska
ź
nik skojarzony ze strumieniem do otwartego
pliku.
Je
ż
eli operacja zamkni
ę
cia powiedzie si
ę
funkcja zwraca 0, w
przeciwnym razie zwraca kod EOF, lub kod bł
ę
du je
ż
eli
dyskietka z plikiem została wyj
ę
ta z nap
ę
du b
ą
d
ż
brak jest
miejsca na dysku
Otwarcie i zamkni
ę
cie pliku dyskowego.
//p_96
/* Otwarcie i zamkni
ę
cie pliku */#include <stdio.h> enum
{SUCCESS, FAIL};main(void){ FILE *fptr; char filename[]=
"haiku.txt"; int reval = SUCCESS; clrscr();
if ((fptr = fopen(filename, "r")) == NULL){
printf("Nie mog
ę
otworzy
ć
%s.\n", filename);
reval = FAIL;
} else {
printf("Warto
ść
fptr: 0x%p\n", fptr);
177
fclose(fptr);
getch();
}
return reval;
}
-------------------------
#include <stdio.h>enum {SUCCESS, FAIL};int CharRead(FILE
*fin);main(void){ FILE *fptr; char filename[]= "haiku.txt";
int reval = SUCCESS; clrscr(); if ((fptr = fopen(filename,
"r")) == NULL){ printf("Nie mog
ę
otworzy
ć
%s.\n", filename);
reval = FAIL;
} else {
printf("\nIlo
ść
znaków -> %d.\n",
CharRead(fptr));
fclose(fptr);
}
getch();
return reval;
}
int CharRead(FILE *fin)
{
int c, num;
num = 0;
while ((c=fgetc(fin)) != EOF)
{
putchar(c);
178
++num;
}
return num;
}
Odczyt i zapis plików dyskowych
Sposoby przeprowadzania operacji wej
ś
cia/wyj
ś
cia :
1/ czyta
ć
i pisa
ć
znak po znaku
2/ czyta
ć
i pisa
ć
wiersz po wierszu
3/ czyta
ć
i pisa
ć
blok po bloku
Odczyt i zapis po znaku
Funkcje fgetc() i fputc() mo
ż
na zastosowac do odczytu i zapisu
znak po znaku.
#include <stdio.h>
int fgetc(FILE *stream);
stream - wska
ź
nik do pliku, który jest skojarzony ze
strumieniem danych
Funkcja fgetc() wczytuje kolejny znak ze strumienia stream.
179
Po przekształceniu wczytanego znaku na kod numeryczny int
funkcja zwraca t
ę
warto
ść
.
#include <stdio.h>
int fputc(int c, FILE *stream);
int c - numeryczny kod znaku c;
Odczyt i zapis metod
ą
znak po znaku
//p_97
/* Czytanie i pisanie znak po znaku */
#include <stdio.h>
enum {SUCCESS, FAIL};
void CharReadWrite(FILE *fin, FILE *fout);
main(void)
{
FILE *fptr1, *fptr2;
char filename1[]= "outhaiku.txt";
char filename2[]= "haiku.txt";
int reval = SUCCESS;
clrscr();
if ((fptr1 = fopen(filename1, "w")) == NULL){
printf("Bł
ą
d otwarcia %s.\n", filename1);
reval = FAIL;
} else if ((fptr2 = fopen(filename2, "r")) == NULL){
printf("Bł
ą
d otwarcia %s.\n", filename2);
reval = FAIL;
180
} else {
CharReadWrite(fptr2, fptr1);
fclose(fptr1);
fclose(fptr2);
}
getch();
return reval;
}
/* definicja funkcji */
void CharReadWrite(FILE *fin, FILE *fout)
{
int c;
while ((c=fgetc(fin)) != EOF){
putchar(c);
fputc(c, fout);
}
}
-----------------------
#include <stdio.h>
#include <string.h>
enum {SUCCESS, FAIL, MAX_LEN = 80};
void LineWrite(FILE *fout, char *str);
181
main(void)
{
FILE *fptr;
char str[MAX_LEN+1];
char filename[32];
int reval = SUCCESS;
clrscr();
printf("Podaj nazw
ę
pliku:\n");
gets(filename);
printf("Wprowad
ź
ła
ń
cuch znak˘w :\n");
gets(str);
if ((fptr = fopen(filename, "w")) == NULL){
printf("Bł
ą
d otwarcia %s dla zapisu.\n", filename);
reval = FAIL;
} else {
LineWrite(fptr, str);
fclose(fptr);
}
getch();
return reval;
}
/* definicja funkcji */
void LineWrite(FILE *fout, char *str)
{
fputs(str, fout);
182
printf("OK!\n");
}
Odczyt i zapis wiersz po wierszu
Mo
ż
na przeprowadzi
ć
zarówno zapis jak i odczyt wiersz po
wierszu.
Słu
żą
do tego celu funkcje fgets() i fputs().
#include <stdio.h>
char *fgets((char *s, int n, FILE *stream);
s - wska
ź
nik do tablicy znakowej u
ż
ywanej do zapami
ę
tania
znaków wczytanych z otwartego pliku wskazanego przez wska
ź
nik
stream.
stream - wska
ź
nik do pliku
n – maksymalna ilo
ść
elementów tablicy znakowej /l. znaków w
wierszu/
Je
ż
eli operacja wczytania wiersza zako
ń
czy si
ę
powodzeniem ,
funkcja zwraca wska
ź
nik char *s. Je
ż
eli funkcja napotka znak
ko
ń
cz apliku EOF funkcja zwraca pusty wska
ź
nik i pozostawia
tablic
ę
znakowa w stanie nienaruszonym. Je
ż
eli wyst
ą
pi bł
ą
d,
funkcja zwraca pusty wska
ź
nik, ale zawarto
ść
tablicy jest tym
razem nieokre
ś
lona.
Funkcja fgets() mo
ż
e wczyta
ć
n-1 znaków i mo
ż
e doł
ą
czy
ć
znak
ko
ń
ca ła
ń
cucha tekstowego ‘\0’ po wczytaniu ostatniego znaku,
dopóki nie napotka znaku przej
ś
cia do nowego wiersza lub znaku
ko
ń
ca pliku /EOF/.
Po napotkaniu znaku przej
ś
cia do nowego wiersza funkcja wł
ą
czy
go do wyj
ś
ciowej tablicy znakowej.
#include <stdio.h>
int fputs(const char *s, FILE *stream);
s - wskazuje tablic
ę
znakow
ą
, wktórej znajduje si
ę
tekst
przeznaczony do zapisu w pliku dyskowym skojarzonym ze
wska
ź
nikiem plikowym stream.
183
Odczyt i zapis metoda wiersz po wierszu
//p_98
/* Czytanie i zapis wierszami */
#include <stdio.h>
enum {SUCCESS, FAIL, MAX_LEN = 81};
void LineReadWrite(FILE *fin, FILE *fout);
main(void)
{
FILE *fptr1, *fptr2;
char filename1[]= "outhaiku.txt";
char filename2[]= "haiku.txt";
int reval = SUCCESS;
clrscr();
if ((fptr1 = fopen(filename1, "w")) == NULL){
printf("Bł
ą
d otwarcia %s dla zapisu.\n", filename1);
reval = FAIL;
} else if ((fptr2 = fopen(filename2, "r")) == NULL){
printf("Bł
ą
d otwarcia %s dla odczytu.\n", filename2);
reval = FAIL;
} else {
LineReadWrite(fptr2, fptr1);
fclose(fptr1);
fclose(fptr2);
}
getch();
184
return reval;
}
/* definicja funkcji */
void LineReadWrite(FILE *fin, FILE *fout)
{
char buff[MAX_LEN];
while (!feof(fin)){
fgets(buff, MAX_LEN, fin);
printf("%s", buff);
fputs(buff, fout);
}
}
--------------------
#include <stdio.h>
enum {SUCCESS, FAIL};
void CharWrite(FILE *fout, char *str);
main(void)
{
FILE *fptr;
char filename[]= "test_21.txt";
char str[]= "Plik dyskowy I/O ";
int reval = SUCCESS;
clrscr();
185
if ((fptr = fopen(filename, "w")) == NULL){
printf("Bł
ą
d otwarcia %s.\n", filename);
reval = FAIL;
} else {
CharWrite(fptr, str);
fclose(fptr);
}
getch();
return reval;
}
/* definicja funkcji */
void CharWrite(FILE *fout, char *str)
{
int i, c;
i = 0;
while ((c=str[i]) != '\0'){
putchar(c);
fputc(c, fout);
i++;
}
}
Odczyt i zapis blok po bloku
Do zapisu lub odczytu bloku danych do/z pliku wykorzystywane
s
ą
funkcje fread() , fwrite().
186
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
ptr - oznacza wska
ź
nik do tablicy, w której sa przechowywane
dane wczytane
size - rozmiar ka
ż
dego elementu tablicy
n - liczba elementów do odczytu
stream - wska
ź
nik skojarzony z plikiem otwartym do odczytu
size_t - typ numeryczny całkowity zdefiniowany w pliku
nagłówkowym stdio.h
Funkcja fread() zwraca liczb
ę
elementów, które wczytała.
Ilo
ść
elementów wczytanych przez funkcje powinna by
ć
równa jej
trzeciemu argumentowi /chyba
ż
e zdarzy si
ę
bł
ą
d lub funkcja
napotka na znak EOFà w takim przypadku zwróci rzeczywist
ą
ilo
ść
wczytanych elementów/.
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t n, FILE
*stream);
ptr – wska
ź
nik do tablicy, wktórej s
ą
przechowywane dane,
które nale
ż
y zapisa
ć
do otwartego pliku wskazanego przez
wska
ź
nik stream.
Parametr size okre
ś
la wielko
ść
elementów tablicy.
n - okre
ś
la ilo
ść
elementów tablicy, które nale
ż
y zapisa
ć
do
pliku.
Funkcja zwraca liczb
ę
rzeczywi
ś
cie zapisanych do pliku
elementów.
Je
ż
eli nie wystapiły
ż
adne bł
ę
dy, liczba zwrócona przez
funkcj
ę
fwrite() powinna by
ć
równa jej trzeciemu elementowi.
Je
ż
eli wyst
ą
pił bł
ą
d to warto
ść
zwrócona mo
ż
e by
ć
mniejsza.
Bardzo istotne jest sprawdzenie czy tablica jest wystarczaj
ą
co
du
ż
a , by pomie
ś
ci
ć
dane dla funkcji fread() i fwrite(). Dla
sprawdzenia kiedy nastapi znak ko
ń
ca pliku słuzy funkcja
feof().
187
Je
ż
eli w programie stwierdzimy napotkanie znaku ko
ń
ca pliku
(EOF) w obr
ę
bie pliku binarnego poprzez sprawdzenie warto
ś
ci
zwróconej przez funkcje fread(), mo
ż
emy zako
ń
czy
ć
prac
ę
w
nieprawidłowym miejscu (nie osi
ą
gn
ą
wszy rzeczywistego ko
ń
ca
pliku). Zastosowanie funkcji feof() pozwoli unikn
ąć
bł
ę
dów
wykrywaj
ą
c rzeczywisty koniec pliku.
#include <stdio.h>
int feof(FILE *stream)
stream - wska
ź
nik plikowy skojarzony z otwartym plikiem.
Funkcja ta zwraca 0 je
ż
eli koniec pliku nie został osi
ą
gni
ę
ty
, w przeciwnym razie zwraca niezerow
ą
warto
ść
całkowit
ą
.
Zapis i odczyt bloku znaków
//p_99
/* Odczyt i zapis blokami */
#include <stdio.h>
enum {SUCCESS, FAIL, MAX_LEN = 80};
void BlockReadWrite(FILE *fin, FILE *fout);
int ErrorMsg(char *str);
main(void)
{
FILE *fptr1, *fptr2;
char filename1[]= "outhaiku.txt";
188
char filename2[]= "haiku.txt";
int reval = SUCCESS;
clrscr();
if ((fptr1 = fopen(filename1, "w")) == NULL){
reval = ErrorMsg(filename1);
} else if ((fptr2 = fopen(filename2, "r")) == NULL){
reval = ErrorMsg(filename2);
} else {
BlockReadWrite(fptr2, fptr1);
fclose(fptr1);
fclose(fptr2);
}
getch();
return reval;
}
/* definicja funckji */
void BlockReadWrite(FILE *fin, FILE *fout)
{
int num;
char buff[MAX_LEN + 1];
while (!feof(fin)){
num = fread(buff, sizeof(char), MAX_LEN, fin);
buff[num * sizeof(char)] = '\0';
printf("%s", buff);
fwrite(buff, sizeof(char), num, fout);
189
}
}
/* definicja funkcji */
int ErrorMsg(char *str)
{
printf("Bł
ą
d otwarcia %s.\n", str);
return FAIL;
}
--------------------
#include <stdio.h>
#include <string.h>
enum {SUCCESS, FAIL};
void BlkWrite(FILE *fout, char *str);
main(void)
{
FILE *fptr;
char filename[]= "test_21.txt";
char str[]= "Plik dyskowy I/O ";
int reval = SUCCESS;
if ((fptr = fopen(filename, "w")) == NULL){
printf("Bł
ą
d otwarcia %s.\n", filename);
reval = FAIL;
} else {
BlkWrite(fptr, str);
190
fclose(fptr);
}
return reval;
}
/* definicja funkcji */
void BlkWrite(FILE *fout, char *str)
{
int num;
num = strlen(str);
fwrite(str, sizeof(char), num, fout);
printf("%s\n", str);
}
Dostep sekwencyjny i bezpo
ś
redni do pliku.
Zapis/Odczyt pliku od pocz
ą
tku bajt po bajcie, z mo
ż
liwo
ś
cia
dopisania danych na ko
ń
cu pliku nazywamy dospepem sekwencyjnym
do pliku,
Poszukiwanie informacji w pliku o taki dost
ę
pie odbywa si
ę
poprzez przegl
ą
ganie informacji od pierwszego bajtu zawartego
w pliku.
W przypadku pliku o dost
ę
pie swobodnym elementy danych mog
ą
by
ć
odczytywane w dowolnej kolejno
ś
ci /bez konieczno
ś
ci
odczytywania wszystkich poprzednich danych/.
191
Jednym z elementów struktury FILE jest znacznik pozycji pliku,
który mo
ż
na ustawi
ć
na poprzedniej pozycji przed operacj
ą
zapisu lub odczytu.
Funkcja fseek() - słu
ż
y do przesuwania znacznika pozycji we
wła
ś
ciwe miejsce w obr
ę
bie pliku.
#include <stdio.h>
int fseek(FILE *stream, long offset, int relation);
stream - wska
ź
nik plikowy skojarzony z otwartym plikiem
offset - oznacza przesuni
ę
cie w bajtach od punktu okre
ś
lonego
przez trzeci argument
relation - punkt odniesienia, od którego rozpoczyna si
ę
odliczania
SEEK_SET - licz
ą
c od pocz
ą
tku pliku
SEEK_CUR - licz
ą
c od bie
żą
cej pozycji znacznika w pliku
SEEK_END - licz
ą
c od ko
ń
ca pliku
je
ż
eli operacja powiedzie si
ę
funkcja fseek() zwraca 0, w
przeciwnym przypadku warto
ść
ró
ż
n
ą
od zera.
Je
ż
eli
relation = SEEK_SET offset > 0
relation = SEEK_END offset < 0
relation = SEEK_CUR
Aby odczyta
ć
bie
żą
c
ą
pozycj
ę
znacznika w pliku - funkcja
ftell()
#include <stdio.h>
long ftell(FILE *stream);
stream - wska
ź
nik plikowy skojarzony z otwartym plikiem
Funkcja zwraca bie
żą
c
ą
warto
ść
/typu long/ pozycji znacznika
licz
ą
c do bie
żą
cej pozycji od pocz
ą
tku pliku w bajtach. Je
ż
eli
wystapi bł
ą
d zwraca
-1L.
192
Swobodny dost
ę
p do pliku.
//p_100
/* Dost
ę
p swobodny do pliku */
#include <stdio.h>
enum {SUCCESS, FAIL, MAX_LEN = 80};
void PtrSeek(FILE *fptr);
long PtrTell(FILE *fptr);
void DataRead(FILE *fptr);
int ErrorMsg(char *str);
main(void)
{
FILE *fptr;
char filename[]= "haiku.txt";
int reval = SUCCESS;
clrscr();
if ((fptr = fopen(filename, "r")) == NULL){
reval = ErrorMsg(filename);
} else {
PtrSeek(fptr);
fclose(fptr);
193
}
getch();
return reval;
}
void PtrSeek(FILE *fptr)
{
long offset1, offset2, offset3;
offset1 = PtrTell(fptr);
DataRead(fptr);
offset2 = PtrTell(fptr);
/* skok do 3 wiersza haiku */
fseek(fptr, 26L, SEEK_CUR);
offset3 = PtrTell(fptr);
DataRead(fptr);
printf("\nodczyt z haiku:\n");
/* ponowny odczyt 3 wiersza haiku */
fseek(fptr, offset3, SEEK_SET);
DataRead(fptr);
/* odczyt 2 wiersza haiku */
fseek(fptr, offset2, SEEK_SET);
DataRead(fptr);
/* odczyt 1 wiersza haiku */
fseek(fptr, offset1, SEEK_SET);
DataRead(fptr);
194
}
long PtrTell(FILE *fptr)
{
long reval;
reval = ftell(fptr);
printf(" fptr jest w %ld\n", reval);
return reval;
}
void DataRead(FILE *fptr)
{
char buff[MAX_LEN];
fgets(buff, MAX_LEN, fptr);
printf("---%s", buff);
}
int ErrorMsg(char *str)
{
printf("Bł
ą
d otwarcia \n", str);
return FAIL;
}
----------------------
#include <stdio.h>
enum {SUCCESS, FAIL, MAX_LEN = 80};
void PtrSeek(FILE *fptr);
long PtrTell(FILE *fptr);
195
void DataRead(FILE *fptr);
int ErrorMsg(char *str);
main(void)
{
FILE *fptr;
char filename[]= "LaoTzu.txt";
int reval = SUCCESS;
clrscr();
if ((fptr = fopen(filename, "r")) == NULL){
reval = ErrorMsg(filename);
} else {
PtrSeek(fptr);
fclose(fptr);
}
getch();
return reval;
}
void PtrSeek(FILE *fptr)
{
long offset1, offset2, offset3;
offset1 = PtrTell(fptr);
DataRead(fptr);
offset2 = PtrTell(fptr);
DataRead(fptr);
196
offset3 = PtrTell(fptr);
DataRead(fptr);
printf("\nPonowny odczyt paragrafu:\n");
/* 3-ej sentencji */
fseek(fptr, offset3, SEEK_SET);
DataRead(fptr);
/* 2-ej sentencji */
fseek(fptr, offset2, SEEK_SET);
DataRead(fptr);
/* 1-szej sentencji */
fseek(fptr, offset1, SEEK_SET);
DataRead(fptr);
}
long PtrTell(FILE *fptr)
{
long reval;
reval = ftell(fptr);
printf(" fptr jest w %ld\n", reval);
return reval;
}
void DataRead(FILE *fptr)
{
char buff[MAX_LEN];
fgets(buff, MAX_LEN, fptr);
printf("%s", buff);
197
}
int ErrorMsg(char *str)
{
printf("Bł
ą
d otwarcia %s.\n", str);
return FAIL;
}
Funkcja rewind() - cofni
ę
cie znacznika pozycji na pocz
ą
tek
pliku
#include <stdio.h>
void rewind(FILE *stream);
stream - wska
ź
nik plikowy skojarzony z otwartym plikiem
Zatem równowa
ż
ne s
ą
:
rewind(ftpr); i fseek(ftpr, 0L, SEEK_SET);
Odczyt i zapis danych w trybie binarnym.
Otwarcie instniej
ą
cego pliku binarnego w trybie tylko do
odczytu.
fprt = fopen(”test.bin”, ”rb”);
Odczyt i zapis danych binarnych
//p_101
/* Zapis i odczyt danych binarnych */
198
#include <stdio.h>
enum {SUCCESS, FAIL, MAX_NUM = 3};
void DataWrite(FILE *fout);
void DataRead(FILE *fin);
int ErrorMsg(char *str);
main(void)
{
FILE *fptr;
char filename[]= "double.bin";
int reval = SUCCESS;
clrscr();
if ((fptr = fopen(filename, "wb+")) == NULL)
{
reval = ErrorMsg(filename);
} else
{
DataWrite(fptr);
rewind(fptr);
DataRead(fptr);
fclose(fptr);
}
getch();
return reval;
}
void DataWrite(FILE *fout)
{
199
int i;
double buff[MAX_NUM] = {
123.45,
567.89,
100.11};
printf("Wielko
ść
buff: %d-bajty\n", sizeof(buff));
for (i=0; i<MAX_NUM; i++){
printf("%5.2f\n", buff[i]);
fwrite(&buff[i], sizeof(double), 1, fout);
}
}
void DataRead(FILE *fin)
{
int i;
double x;
printf("\nCzytanie z pliku binarnego :\n");
for (i=0; i<MAX_NUM; i++){
fread(&x, sizeof(double), (size_t)1, fin);
printf("%5.2f\n", x);
}
}
int ErrorMsg(char *str)
{
printf("Bł
ą
d otwarcia %s.\n", str);
200
return FAIL;
}
---------------------
#include <stdio.h>
enum {SUCCESS, FAIL, MAX_LEN = 80};
void PtrSeek(FILE *fptr);
long PtrTell(FILE *fptr);
void DataRead(FILE *fptr);
int ErrorMsg(char *str);
main(void)
{
FILE *fptr;
char filename[]= "LaoTzu.txt";
int reval = SUCCESS;
clrscr();
if ((fptr = fopen(filename, "r")) == NULL){
reval = ErrorMsg(filename);
} else {
PtrSeek(fptr);
fclose(fptr);
}
getch();
return reval;
}
201
void PtrSeek(FILE *fptr)
{
long offset1, offset2, offset3;
offset1 = PtrTell(fptr);
DataRead(fptr);
offset2 = PtrTell(fptr);
DataRead(fptr);
offset3 = PtrTell(fptr);
DataRead(fptr);
printf("\nCzytanie paragrafu :\n");
/* 3 sentencja */
fseek(fptr, offset3, SEEK_SET);
DataRead(fptr);
/* 2 sentencja */
fseek(fptr, offset2, SEEK_SET);
DataRead(fptr);
/* 1 sentencja */
rewind(fptr); /* przewini
ę
cie pozycjonera */
DataRead(fptr);
}
long PtrTell(FILE *fptr)
{
long reval;
reval = ftell(fptr);
202
printf(" fptr jest w %ld\n", reval);
return reval;
}
void DataRead(FILE *fptr)
{
char buff[MAX_LEN];
fgets(buff, MAX_LEN, fptr);
printf("%s", buff);
}
int ErrorMsg(char *str)
{
printf("Bł
ą
d otwarcia %s.\n", str);
return FAIL;
}
Funkcje fscanf() i fprintf()
Funkcje printf() i scanf() słu
żą
do zapisu i odczytu
sformatowanych danych do/z strumieni do plików standardowego
urz
ą
dzenia We/Wy (stdout,stdin).
Dla plików dyskowych s
ą
dwa odpowiedniki tych funkcji :
fprintf() i fscanf(), które dodatkowo pozwalaj
ą
wybrac
strumie
ń
danych wej
ś
cia wyj
ś
cia stream.
#include <stdio.h>
int fscanf(FILE *stream, const char *format, ...);
stream - wska
ź
nik plikowy skojarzony z otwartym plikiem, a
zastosowanie pozostałych elementów jest takie jak w finkcji
scanf()
203
Funkcja zwraca liczb
ę
wczytanych argumentów lub EOF jako wynik
negatywny.
#include <stdio.h>
int fprintf(FILE *stream, const char *format, ... );
stream - wskaxnik plikowy skojarzony z otwartym plikiem,
zastosowanie pozostałych argumentów jest takie jak w funkcji
printf().
Funkcja zwraca liczb
ę
sformatowanych wyra
ż
e
ń
lub warto
ść
ujemn
ą
w przypadku negatywnym.
Zastosowanie funkcji fprintf() i fscanf().
//p_102
/* fscanf() i fprintf() */
#include <stdio.h>
enum {SUCCESS, FAIL,
MAX_NUM = 3,
STR_LEN = 23};
void DataWrite(FILE *fout);
void DataRead(FILE *fin);
int ErrorMsg(char *str);
main(void)
{
FILE *fptr;
char filename[]= "strnum.mix";
int reval = SUCCESS;
clrscr();
if ((fptr = fopen(filename, "w+")) == NULL){
reval = ErrorMsg(filename);
204
} else {
DataWrite(fptr);
rewind(fptr);
DataRead(fptr);
fclose(fptr);
}
getch();
return reval;
}
void DataWrite(FILE *fout)
{
int i;
char cities[MAX_NUM][STR_LEN] = {
"St.Louis->Houston:",
"Houston->Dallas:",
"Dallas->Philadelphia:"};
int miles[MAX_NUM] = {
845,
243,
1459};
printf("Zapis danych:\n");
for (i=0; i<MAX_NUM; i++){
printf("%-23s %d\n", cities[i], miles[i]);
fprintf(fout, "%s %d", cities[i], miles[i]);
}
205
}
void DataRead(FILE *fin)
{
int i;
int miles;
char cities[STR_LEN];
printf("\nCzytanie danych:\n");
for (i=0; i<MAX_NUM; i++){
fscanf(fin, "%s%d", cities, &miles);
printf("%-23s %d\n", cities, miles);
}
}
int ErrorMsg(char *str)
{
printf("Bł
ą
d otwarcia %s.\n", str);
return FAIL;
}
------------------
#include <stdio.h>
enum {SUCCESS, FAIL};
void DataWrite(FILE *fout);
void DataRead(FILE *fin);
int ErrorMsg(char *str);
main(void)
206
{
FILE *fptr;
char filename[]= "data.bin";
int reval = SUCCESS;
clrscr();
if ((fptr = fopen(filename, "wb+")) == NULL){
reval = ErrorMsg(filename);
} else {
DataWrite(fptr);
rewind(fptr);
DataRead(fptr);
fclose(fptr);
}
getch();
return reval;
}
void DataWrite(FILE *fout)
{
double dnum;
int inum;
dnum = 123.45;
inum = 10000;
printf("%5.2f\n", dnum);
fwrite(&dnum, sizeof(double), 1, fout);
207
printf("%d\n", inum);
fwrite(&inum, sizeof(int), 1, fout);
}
void DataRead(FILE *fin)
{
double x;
int y;
printf("\nCzytanie z pliku binarnego:\n");
fread(&x, sizeof(double), (size_t)1, fin);
printf("%5.2f\n", x);
fread(&y, sizeof(int), (size_t)1, fin);
printf("%d\n", y);
}
int ErrorMsg(char *str)
{
printf("Bł
ą
d otwarcia %s.\n", str);
return FAIL;
}
Funkcja freopen()
Standardowy przepływ strumieni danych mo
ż
na zmieni
ć
np. tak
aby strumienie stdin i stdout skojarzy
ć
z plikami dyskowymi.
U
ż
ywana do tego celu funkcja freopen().
#include <stdio.h>
208
FILE *freopen(const char *filename, const char *mode, FILE
*stream);
const char *filename - wska
ź
nik do stałego ła
ń
cucha znaków,
nazwy plików
Chodzi tu o ten plik, który nale
ż
y skojarzy
ć
ze standardowym
strumieniem (trzeci argument funkcji)
FILE *stream - wska
ź
nik do standardowego strumienia, który
nale
ż
y skojarzy
ć
z plikiem.
mode - wska
ź
nik typu *char wskazuj
ą
cy ła
ń
cuch znaków
okre
ś
laj
ą
cy tryb otwarcia danego pliku dyskowego; argument ten
mo
ż
e przybiera
ć
tu te same warto
ś
ci, co w przypadku funkcji
fopen();
Funkcja freopen() zwraca pusty wska
ź
nik w przypadku
wyst
ą
pienia bł
ę
du, w przeciwnym przypadku zwraca standardowy
strumie
ń
/wska
ź
nik typu FILE */. Ten standardowy strumie
ń
zostaje skojarzony z plikiem zadanym przez pierwszy argument
funkcji filename.
Skierowanie standardowego strumienia stdout do pliku dyskowego
//p_103
/* Zmiana kierunku przepˆywu standardowego srtumienia danych
*/
#include <stdio.h>
enum {SUCCESS, FAIL,
STR_NUM = 4};
void StrPrint(char **str);
int ErrorMsg(char *str);
main(void)
{
209
char *str[STR_NUM] = {
"Be bent, and you will remain straight.",
"Be vacant, and you will remain full.",
"Be worn, and you will remain new.",
"--- by Lao Tzu"};
char filename[]= "LaoTzu.txt";
int reval = SUCCESS;
clrscr();
StrPrint(str);
if (freopen(filename, "w", stdout) == NULL)
{
reval = ErrorMsg(filename);
} else
{
StrPrint(str);
fclose(stdout);
}
getch();
return reval;
}
void StrPrint(char **str)
{
int i;
for (i=0; i<STR_NUM; i++)
printf("%s\n", str[i]);
210
}
int ErrorMsg(char *str)
{
printf("Bł
ą
d otwarcia %s.\n", str);
return FAIL;
}
------------------
#include <stdio.h>
enum {SUCCESS, FAIL,
MAX_NUM = 3,
STR_LEN = 23};
void DataRead(FILE *fin);
int ErrorMsg(char *str);
main(void)
{
FILE *fptr;
char filename[]= "strnum.mix";
int reval = SUCCESS;
clrscr();
if ((fptr = freopen(filename, "r", stdin)) == NULL){
reval = ErrorMsg(filename);
} else {
DataRead(fptr);
211
fclose(fptr);
}
getch();
return reval;
}
void DataRead(FILE *fin)
{
int i;
int miles;
char cities[STR_LEN];
printf("Czytanie danych :\n");
for (i=0; i<MAX_NUM; i++){
scanf("%s%d", cities, &miles);
printf("%-23s %d\n", cities, miles);
}
}
int ErrorMsg(char *str)
{
printf("Bł
ą
d otwarcia %s.\n", str);
return FAIL;
}
212
Preprocesor
Preprocesor to specjalny program pozwalaj
ą
cy na definiowanie i
kojarzenie nazw symboli ze stałymi. Preprocesor jest
uruchamiany przed kompilatorem. Przed uruchomieniem
kompilatora preprocesor przetwarza makropolecenia.
makrodefinicj
ę
mo
ż
na umie
ś
cic w dowolnym miejscu programu,
jednak makronazwa musi zosta
ć
zdefiniowana przed jej pierwszym
u
ż
yciem w programie.
Preprocesor pozwala równie
ż
na doł
ą
czanie do kodu
ź
ródłowego
programu innych plików
ź
ródłowych (stdlib.h,
strung.h,stdio.h).
Preprocesor ma własn
ą
składni
ę
.
Rozkazy jego rozpoczynaja si
ę
od znaku # i ko
ń
cz
ą
znakiem
przej
ś
cia do nowego wiersza (nie
ś
rednika jak w j
ę
zyku C);
Preprocesor C pracuje w trybie wiersz-po-wierszu.
Najcz
ęś
ciej u
ż
ywane dyrektywy preprocesora C :
#define - zdefiniuj
#undef - anuluj definicj
ę
213
#if - je
ż
eli
#elif - w przeciwnym razie, je
ś
li...
#else - w przeciwnym razie
#ifdef - je
ś
li zdefiniowane jest...
#ifndef - je
ś
li nie jest zdefiniowane...
#endif - koniec bloku warunkowego
Makrorozkazy /te, które maja by
ć
zast
ą
pione stałymi/ s
ą
zazwyczaj pisane du
ż
ymi literami.
Dyrektywy #define #undef
#define macro_name macro_body
macro_name - identyfikator
macro_body - ła
ń
cuch zło
ż
ony z elementów danych zastepuj
ą
cy
identyfikator przy ka
ż
dym jego wyst
ą
pieniu w programie
np.
#define MY_NAME ‘Artur’
#define SUMA (12+3)
Dla anulowania dyrektywy #define słuzy dyrektywa #undef
#undef macro_name
np.
#undef MY_NAME ‘Artur’
Definiowanie makropolece
ń
na podobie
ń
stwo funkcji przy pomocy
dyrektywy #define
214
W makronazwie definiowanej przy pomocy dyrektywy #define ,
mo
ż
na podobnie jak w przypadku funkcji definiowa
ć
jeden lub
wi
ę
cej argumentów.
#define MULTIPLY (val1,val2) ((val1)*(val2))
rezult = MULTIPLY(2,3) + 10;
Zastosowanie dyrektywy #define
//p_104
Zagnie
ż
d
ż
anie makrodefinicji
Uprzednio zdefiniowane makro mo
ż
e by
ć
zastosowane w nast
ę
pnej
definicji
#define JEDEN 1
#define DWA (JEDEN + JEDEN)
#define TRZY (JEDEN + DWA)
wynik = DWA + TRZY;
#define SUMA 12 + 8
wynik = SUMA * 10; à 92
#define SUMA (12 + 8)
wynik = SUMA * 10; à 200
Kompilacja warunkowa
215
Dyrektywy #infdef i #endif
wyznaczaj
ą
pocz
ą
tek i koniec fragmentu kodu
ź
ródłowego
decyduj
ą
czy w/w fragment kodu zostanie skompilowany
#ifdef macro_name
instr1;
instr2;
instr3;
...
#endif
nacro_name - dowolny ła
ń
cuch zdefiniowany dyrektyw
ą
define
Instrukcje zostan
ą
skompilowane i wejd
ą
w skład kodu, je
ż
eli w
chwili przetwarzania identyfikator macro_name jest
zdefiniowany.
Dyrektywa #ifndef
Dyrektywa ta pozwala na warunkow
ą
kompilacj
ę
feagmentu kodu
ź
ródłowego, je
ż
eli okre
ś
lona makronazwa nie jest zdefiniowana.
#ifndef
instr1;
instr2;
instr3;
...
#endif
Zastosowanie dyrektyw : #ifdef, #ifndef, #endif
//p_105
216
Dyrektywy #if, #elif, #else
Dyrektywa #if okre
ś
la warunki ewentualnej kompilacji i
wł
ą
czenia do kodu wykonywalnego pewnych instrukcji pod
warunkiem,
ż
e wyra
ż
enie warunkowe zwróci warto
ść
niezerow
ą
(warunek spełniony). Wyra
ż
enie warunkowe mo
ż
e by
ć
np.
wyra
ż
eniem arytmetycznym.
#if wyra
ż
enie
instr1;
instr2;
instr3;
...
#endif
Przy wyborze jednej z dwu mozliwo
ś
ci :
#if
instr1;
instr2;
instr3;
...
#else
ins1;
ins2;
ins3;
...
#endif
#ifdef DEBUG
instrukcja1;
217
#else
instrukcja2;
#endif
#if 1
instr1; à zawsze b
ę
dzie kompilowana
#endif
dyrektywa #elif oznacza to samo co else...if
Zastosowanie dyrektyw #if #elif #else
//p_106
Zagnie
ż
d
ż
anie bloków kompilacji warunkowej
/standard ANSI C max 8 poziomów/
#if makro1
#if makro2
#if makro3
instr1;
#else
instr2;
#endif
#else
instr3;
218
#endif
#else
instr4;
#endif
Zagnie
ż
d
ż
anie dyrektywy #if
//p_107