This is an old revision of the document!
Tablica to ciąg wartości tego samego typu (np. liczb) przechowywanych obok siebie.
Uogólniona deklaracja tablicy:
typ_danych nazwa_tablicy[liczba_elementow];
przy czym dostępne typy elementów są identyczne, jak dla “zwykłych” zmiennych (int
, float
itd.)
Przykład:
int tab[8]; // tablica osmiu wartosci typu calkowitego
Definicja tablicy polega na przypisaniu do tablicy podanej w nawiasach klamrowych listy wartości kolejnych elementów (rozdzielonych przecinkami).
Przykład:
int tab[4] = {3, 2, 5, 1};
W przypadku podania zbyt małej liczby wartości do inicjalizacji, pozostałe elementy tablicy otrzymują wartość 0.
Dostęp do poszczególnych elementów tablicy można uzyskać za pomocą indeksu elementu, będącego zawsze liczbą naturalną, umieszczonego w nawiasach kwadratowych.
W języku C indeksowanie zaczyna się od zera – czyli aby uzyskać wartość pierwszego elementu piszemy
tab[0]
!
Przykład:
int tab[] = {1, 2, 3, 4}; int elem = tab[2]; // przypisz zmiennej `elem` wartosc TRZECIEGO elementu tablicy `tab`
Cóż… Niestety, język C nie pozwala na wyświetlanie tablicy jedną instrukcję.
Tablicę trzeba wyświetlać element po elemencie.
Podobnie w przypadku, gdy to użytkownik ma podawać wartości elementów tablicy, trzeba to zrobić element po elemencie (najlepiej – w pętli!).
Stwórz jednowymiarową tablicę czterech wartości zmiennoprzecinkowych, zainicjalizuj ją wybranymi przez siebie wartościami, a następnie oblicz sumę jej elementów.
Wskazówka: Skorzystaj z pętli for
.
Napisz program, który wyznaczy największą wartość w jednowymiarowej tablicy pięciu liczb całkowitych.
W poniższym przykładzie mimo, że tablica składa się z trzech elementów (a więc poprawne indeksy to 0, 1 i 2), możemy odwołać się do elementów spoza zakresu – ani kompilator nie zgłosi błędów, ani (w tym przypadku) nie wystąpi błąd podczas wykonania programu:
#include <stdio.h> int main() { int tab[3] = {1, 2, 3}; printf("%d\n", tab[-1]); printf("%d\n", tab[3]); return 0; }
Tyle, że… wartości tab[-1]
i tab[3]
zawierają “śmieci”. W dodatku ta pamięć nie należy już do zmiennej tab
.
W ogólnym przypadku odwoływanie się do nie-swojej pamięci może spowodować błąd działania programu.
Jeśli definiujemy tablicę z użyciem listy, możemy nie podawać jej rozmiaru – po prostu pozostawić puste nawiasy kwadratowe.
Kompilator sam automatycznie dobierze rozmiar tablicy tak, aby zmieściły się w niej wszystkie elementy z listy.
int tab1[] = {1, 2, 3}; // tab1 ma rozmiar 3 elementów int tab2[] = {1, 2, 3, 4}; // tab2 ma rozmiar 4 elementów
Standard ANSI C nie pozwala na używanie zmiennych bądź stałych do określania rozmiaru tablicy podczas deklaracji:
int n = 3; int tab[n]; // blad
const int n = 3; int tab[n]; // blad
Mimo to wygodnie jest mieć w programie zdefiniowaną w jednym miejscu w programie wartość określającą ilość elementów tablicy – aby później korzystać z niej np. w pętlach (i uczynić program elastycznym). Dobrze, aby wartość ta była określana automatycznie – zmniejszymy w ten sposób ryzyko błędów. Z pomocą przychodzi operator sizeof
.
Operator sizeof
zwraca rozmiar operandu (w bajtach). Używa się go podobnie do wywołania funkcji, przy czym argumentem może być nazwa zmiennej lub typ danych:
int s = sizeof(char); // wartosc `s` to 1, bo tyle wynosi rozmiar typu 'char' int s2 = sizeof(s); // wartosc `s2` to (prawdopodobnie) 4
Operator ten można wykorzystać, aby otrzymać ilość elementów tablicy w następujący sposób:
int tab[5]; int ilosc_elementow = sizeof(tab) / sizeof(tab[0]); // ilosc elementow = rozmiar całej tablicy (w bajtach) / rozmiar pojedynczego elementu (w bajtach)
Język C udostępnia arytmetyczne operatory przypisania <op>=
(gdzie <op>
oznacza operator arytmetyczny: +
, -
, *
, /
bądź %
): instrukcja x <op>= y;
jest równoważna x = x <op> (y);
Przykład:
int a = 5; int b = 2; a *= 3; // nowa wartosc `a` to 5 * 3 = 15 b *= 3 + 1; // nowa wartosc `b` to 2 * (3 + 1) = 8
Operatory inkrementacji (++
) i dekrementacji (--
) powodują odpowiednio zwiększenie bądź zmniejszenie wartości zmiennej o 1.
Są one dostępne w dwóch trybach:
++i
i++
Przykład:
int a1 = 3; int a2 = 3; int b_pre = 2 * ++a1; //po wykonaniu instrukcji: b_pre = 6, a1 = 3 int b_post = 2 * a2++; //po wykonaniu instrukcji: b_post = 4, a2 = 3 printf("a = %d, b_pre = %d, b_post = %d\n", b_pre, b_post);
Zwróć uwagę na to, że np.
i+1
to nie to samo co i++
:
int tab[3] = {1, 2, 3}; int i = 0; printf("%d\n", tab[i++]); // wypisz i-ty element ORAZ (nastepnie) zwieksz `i` o 1 // teraz `i` wynosi 1 printf("%d\n", tab[i+1]); // wypisz (i+1)-wszy element (ale nie zmnieniaj wartosci `i`) // `i` nadal wynosi 1
Operatory inkrementacji i dekrementacji działają tylko dla zmiennych (a ściślej: dla modyfikowalnych l-wartości). Oznacza to, że instrukcja int a = 6++;
jest błędna.
Stosuj powyższe operatory ostrożnie – zwiększają one zwięzłość kodu, lecz łatwo popełnić błąd w zapisie.
Nie łącz zbyt wielu operatorów w jednym wyrażeniu, nie rób “optymalizacji” długości kodu kosztem czytelności – w ten sposób unikniesz wielu błędów. W szczególności:
Na przykład po wykonaniu kodu
int n = 3; int y = n++ + n++;
y
może mieć albo wartość 6
– jeśli kompilator dwukrotnie użyje starej wartości – albo wartość 7
(3 + 4
), jeśli zwiększenie nastąpi przed obliczeniem sumy. Standard języka C nie narzuca jednego słusznego sposobu obliczania takiego wyrażenia.
(poziom trudności: )
Napisz program, który uzupełni tablicę typu int
(o rozmiarze 10) losowymi wartościami z przedziału $\langle 0, 99 \rangle$.
(poziom trudności: )
Napisz program, który odwróci kolejność elementów tablicy “w miejscu”, czyli bez deklarowania tablicy pomocniczej.
Przykład: {1, 4, 3}
→ {3, 4, 1}
.
Wskazówka: Stosowanie “zwykłej” zmiennej pomocniczej jest dozwolone!