Progr
Programowanie
nie
w jęz
w ję yku C
zyku C
© 2009
Grzegorz Łukawski & Maciej Lasota
Politechnika Świętokrzyska w Kielcach
Wykład nr 4:
Tablice
Struktury
Unie
Własne typy danych
Tablica to grupa takich samych, uporządkowanych elementów danych, umieszczona w jednym spójnym obszarze pamięci operacyjnej.
● 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.
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?
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);
Tablice – wielkość tablic Operator sizeof() zwraca całkowitą liczbę bajtów zajmowaną przez 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
Porównywanie i kopiowanie tablic int t1[20]; int t2[20];
if( t1 == t2 )
puts(”Takie same”);
Porównywanie tablic:
int tab1[30],tab2[30];
int rozne;
(…)
rozne = 0;
for(int i=0;i < 30;i++)
if(tab1[i] != tab2[i]) rozne = 1;
Kopiowanie tablic:
int tab1[30],tab2[30];
(…)
for(int i=0;i < 30;i++)
tab1[i] = tab2[i];
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.
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
1
2
3
4
5
'T' 'e' 'k' 's' 't'
0
84
101 107 115 116
0
char tekst1[] = {'T','e','k','s','t',0}; char tekst2[] = ”Tekst”;
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 – 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.
#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 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 lini „\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!
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;
poz.cena = 0.5;
wpoz->cena = 0.5;
x = poz.ilosc / 2;
wpoz->ilosc = 1000;
strcpy(poz.nazwa, ”CD-R”);
puts(wpoz->nazwa);
struct element {
char nazwa[32];
struct punkt {
float cena;
int x, y;
long ilosc;
} p1, p2;
};
struct element pozycja;
struct element *wpozycja;
Wartości początkowe – analogicznie jak dla zmiennych lokalnych/globalnych innych rodzajów i typów!
struct element pozycja = {”Monitor LCD”, 499.99, 100};
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);
}
struct transport {
float waga;
struct element towar;
} t1, t2;
t1.waga = 155;
t1.towar.cena = 4.99;
puts(t2.towar.nazwa);
Dla zmiennych wskaźnikowych:
struct transport *wt;
wt->waga = 10.25;
wt->towar.ilosc = 1;
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.
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ść uni odpowiada wielkości największego jej pola: sizeof(z) = 8;
// sizeof(double) = 8
Odwołanie do pól uni – analogicznie jak do struktur: z.w_long = 1000;
x = z.w_short;
Wartość początkowa uni musi dotyczyć jej pierwszego pola (typu).
Elementem składowym uni może być struktura i vice versa.
Odwołanie do pól zagnieżdżonych uni /struktur następuje identycznie jak dla struktur.
Przykład – rejestr EAX procesora 80x86 reprezentowany przez unię: union rejestr_eax {
eax
long eax;
short ax;
ax
struct {
char al, ah;
ah
al
} b;
} eax;
32b (4B)
eax.b.al = 0x10;
eax.b.ah = 0x20;
x = eax.ax;
// x = 0x2010
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];
typedef struct {
String s1 = "ABCD";
int szer, wys;
puts(s1);
char kolor;
} Prostokat;
(…)
Prostokat pr = {10,10,0};