Programowanie
w języku C
Programowanie
w języku C
© 2009
Grzegorz Łukawski & Maciej Lasota
Politechnika Świętokrzyska w Kielcach
Wykład nr 4:
Tablice
Struktury
Unie
Własne typy danych
Tablice w języku C
●
Indeksy tablic zawsze liczone są od zera (jak w asemblerze)!
●
Kompilator nie sprawdza zakresu indeksów!
●
Jako indeks tablicy może być użyta liczba całkowita – można to
obejść przez rzutowanie dowolnego typu na typ całkowity.
Tablica to grupa takich samych, uporządkowanych elementów danych,
umieszczona w jednym spójnym obszarze pamięci operacyjnej.
UWAGA!
Ponieważ indeksy tablic zawsze liczone są od zera, pierwszy element
tablicy n-elementowej ma indeks 0, a ostatni n-1.
Inicjalizacja przy deklaracji tablicy:
int tab1[30];
// 0 lub ?
int tab2[] = {5, 10, 15};
float t[32] = {0.1, 0.2, 0.3, 0.4};
// Pozostałe?
Tablice
int
tablica
[20];
// 0..19
int i;long suma=0;
for(i=0;i < 20;i++) {
printf(”Podaj element %d:”,i);
scanf(”%d”,&
tablica
[i]);
}
for(i=0;i < 20;i++)
suma = suma +
tablica
[i];
printf(”Suma: %ld\n”,suma);
Operator sizeof() zwraca całkowitą liczbę bajtów zajmowaną przez
tablicę:
Tablice – wielkość tablic
int
tablica
[20];
double
dane
[4];
printf(”tablica - %dB\n”, sizeof(
tablica
));
// 20 * sizeof(int) = 20 * 4 = 80
printf(”dane - %dB\n”, sizeof(
dane
));
// 4 * sizeof(double) = 4 * 8 = 32
int
tab1
[30],
tab2
[30];
int
rozne
;
(…)
rozne
= 0;
for(int i=0;i < 30;i++)
if(
tab1
[i] !=
tab2
[i])
rozne
= 1;
Porównywanie i kopiowanie tablic
int
t1
[20]; int
t2
[20];
if( t1 == t2 )
puts(”Takie same”);
Porównywanie tablic:
Kopiowanie tablic:
int
tab1
[30],
tab2
[30];
(…)
for(int i=0;i < 30;i++)
tab1
[i] =
tab2
[i];
Tablice wielowymiarowe
typ nazwa[wymiar1][wymiar2];
int tab2w[3][5] = {
{1,2,3,4,5},
{6,6,6,6,6},
{7,7,7,7,7}
};
printf(”%d”, tab2w[0][0]);
tab2w[2][4] = 0;
UWAGA!
W tablicach wielowymiarowych, analogicznie do tablic jednowymiarowych,
indeksy liczone są od zera dla każdego z wymiarów.
Tablice znakowe zachowują się (prawie) jak zwykłe tablice. Na każdym znaku
z osobna można wykonywać dowolne operacje – również arytmetyczne.
Tablice znakowe
Tablica znakowa (złożona z elementów typu char) służy do przechowywania
ciągów znaków. Traktowana jest przez kompilator języka C w szczególny
sposób...
0
'T' 'e' 'k'
0
1
2
3
4
5
's' 't'
84
101 107 115 116
0
char tekst1[] = {'T','e','k','s','t',0};
char tekst2[] = ”Tekst”;
#include <string.h>
int strcmp(t1,t2);
Porównuje dwa ciągi znaków, zwraca 0 (gdy takie same),
wartość <0 (t1<t2), lub >0 (t1>t2).
int strncmp(t1,t2,n);
J.w. ale porównuje co najwyżej „n” znaków.
strcpy(to,from);
Kopiuje ciąg znaków z „from” do „to” wliczając znak 0.
strncpy(to,from,n);
Kopiuje co najwyżej „n” znaków,
jeżeli „from” ma mniej znaków niż „n”, uzupełnia znakami 0.
Tablice znakowe – funkcje standardowe
Tablicy znakowej nie można wprost porównywać ani kopiować!
●
Można napisać własną funkcję, lub...
●
...skorzystać z jednej z funkcji standardowych.
Tablice znakowe – funkcje standardowe
strcat(to,from);
Dopisuje „from” do końca „to”.
strncat(to,from,n);
Jak wyżej, ale dopisuje co najwyżej „n” znaków.
strlen(t);
Zwraca długość ciągu (nie wliczając znaku 0).
char t1[] =
”Mam na imię ”
;
char t2[256];
strcpy
(t2, t1);
strcat
(t2,
”Stefan”
);
puts(t2);
printf(
”Długość = %d\n”
,
strlen
(t2));
Tablice znakowe – funkcje standardowe
puts(tekst);
Wyświetla „tekst” na ekranie, dodając znak końca linii „\n”.
printf(”Mam na imię %s\n”, imie);
Ciąg „%s” zastępowany jest ciągiem znaków.
gets(tekst);
Wczytuje ciąg znaków, aż do naciśnięcia klawisza Enter
(
Niebezpieczna
– funkcja nie otrzymuje informacji o ilości miejsca na znaki!).
fgets(tekst, dlugosc, stdin);
Jak wyżej, ale wczyta co najwyżej „dlugosc” znaków – funkcja znacznie
bezpieczniejsza niż gets()!
UWAGA!
Żadna z funkcji standardowych nie tworzy miejsca na
wczytywane/kopiowane znaki. Programista musi zapewnić odpowiednią
ilość miejsca w pamięci!
poz.cena = 0.5;
x = poz.ilosc / 2;
strcpy(poz.nazwa, ”CD-R”);
Struktury
Struktura to obiekt złożony z kilku zmiennych, możliwe że różnych typów,
zgrupowanych pod jedną wspólną nazwą. Każda składowa struktury ma swój
identyfikator (nazwę pola).
struct
{
char
nazwa
[32];
float
cena
;
short
ilosc
;
} poz, *wpoz;
wpoz->cena = 0.5;
wpoz->ilosc = 1000;
puts(wpoz->nazwa);
Typ strukturalny
struct
element
{
char nazwa[32];
float cena;
long ilosc;
};
struct
element
pozycja;
struct
element
*wpozycja;
struct
punkt
{
int x, y;
}
p1
,
p2
;
Wartości początkowe – analogicznie jak dla zmiennych lokalnych/globalnych
innych rodzajów i typów!
struct
element
pozycja = {”Monitor LCD”, 499.99, 100};
Tablica struktur
struct
element
oferta[] = {
{”Monitor LCD”, 499.99, 100},
{”Klawiatura”, 19.99, 250},
{”Kabel 220V”, 8.50, 133}
};
for(int n=0;n < 3;n++) {
printf(”Nazwa: %s\n”,
oferta
[n].
nazwa
);
printf(”Cena: %f\n”,
oferta
[n].
cena
);
printf(”Ilość: %d\n”,
oferta
[n].
ilosc
);
}
Struktury zagnieżdżone
struct transport {
float waga;
struct element towar;
} t1, t2;
t1.waga = 155;
t1.towar.cena = 4.99;
puts(t2.towar.nazwa);
struct transport *wt;
wt->waga = 10.25;
wt->towar.ilosc = 1;
Dla zmiennych wskaźnikowych:
Struktury wskazujące na same siebie
struct el_li {
char nazwa[32];
float cena;
long ilosc;
struct el_li *next;
};
Jest to przykład klasycznej listy jednokierunkowej – każdy element zawiera
wskaźnik na kolejny element tego samego typu.
Unie
Unia to rodzaj zmiennej, która w jednym wspólnym obszarze pamięci może
przechowywać obiekty różnych typów i rozmiarów.
union
zmienne {
long w_long;
double w_double;
short w_short;
} z;
Wielkość unii odpowiada wielkości największego jej pola:
sizeof(z) = 8;
// sizeof(double) = 8
Odwołanie do pól unii – analogicznie jak do struktur:
z
.w_long = 1000;
x =
z
.w_short;
Wartość początkowa unii musi dotyczyć jej pierwszego pola (typu).
eax.b.al = 0x10;
eax.b.ah = 0x20;
x = eax.ax;
// x = 0x2010
Unie i struktury
Elementem składowym unii może być struktura i vice versa.
Odwołanie do pól zagnieżdżonych unii/struktur następuje identycznie jak dla
struktur.
union
rejestr_eax {
long eax;
short ax;
struct {
char al, ah;
} b;
} eax;
Przykład – rejestr EAX procesora 80x86 reprezentowany przez unię:
eax
ax
ah
al
32b (4B)
Definicja własnych typów danych
typedef
istniejący_typ
nowy_typ
;
typedef
unsigned long
ULong
;
(…)
ULong
licznik = 5;
ULong
tabela[32];
typedef char String[64];
String s1 = "ABCD";
puts(s1);
typedef
struct {
int szer, wys;
char kolor;
}
Prostokat
;
(…)
Prostokat
pr = {10,10,0};