W rozdziale Zmienne w C dowiedziałeś się, jak przechowywać pojedyncze liczby oraz znaki. Czasami zdarza się jednak, że potrzebujemy przechować kilka, kilkanaście albo i więcej zmiennych jednego typu. Nie tworzymy wtedy np. dwudziestu osobnych zmiennych. W takich przypadkach z pomocą przychodzi nam tablica.

Tablica to ciąg zmiennych jednego typu. Ciąg taki posiada jedną nazwę a do jego poszczególnych elementów odnosimy się przez numer (indeks).

Wstęp Typy tablic

Podział wg sposobu definiowania: statyczne dynamiczne tablice, których rozmiar jest definiowany przez zmienną ( ang. Variable-length array)Variable-length_array w ang. wikipediistackoverflow question: whats-the-point-of-vla-anyway tablice, których rozmiar jest niezdefiniowany. Tablice te są elementem struktury.(ang. Flexible array member)Flexible_array_member w ang. wikipedii

Podział wg typu elementu tablice znaków tablice liczb całkowitych

Podział wg rozmiaru jednowymiarowe wielowymiarowe

Tablice znaków Tablice znaków, tj. typu char oraz unsigned char, posiadają dwie ogólnie przyjęte nazwy, zależnie od ich przeznaczenia: bufory - gdy wykorzystujemy je do przechowywania ogólnie pojętych danych, gdy traktujemy je jako po prostu "ciągi bajtów" (typ char ma rozmiar 1 bajta, więc jest elastyczny do przechowywania np. danych wczytanych z pliku przed ich przetworzeniem). napisy - gdy zawarte w nich dane traktujemy jako ciągi liter; jest im poświęcony osobny rozdział Napisy.

Przykład:

/* http://joequery.me/code/snprintf-c/

gcc a.c -Wall ./a.out

012345678 hello th\0 turtle\078 2222\05678

* / # include # define BUFSIZE 9

void init_buf(char *buf, size_t size){ int i; for(i=0; i<size; i++){ buf[i] = i + '0'; // int to char conversion

void print_buf(char *buf){ int i; char c; for(i=0; i<BUFSIZE; i++){ c = buf[i]; if(c == '\0'){ printf("\\0");

else{ printf("%c", buf[i]);

printf("\n"); }

int main(){ char buf[BUFSIZE]; init_buf(buf, BUFSIZE); print_buf(buf);

// hello there! == 12 characters, > BUFSIZE init_buf(buf, BUFSIZE); snprintf(buf, BUFSIZE, "hello there!"); print_buf(buf);

// turtle == 6 charaters, 5 init_buf(buf, BUFSIZE); snprintf(buf, 5, "%d", 222222 * 10); print_buf(buf);

return 0; }

Tablice wielowymiarowe

Rozważmy teraz konieczność przechowania w pamięci komputera całej macierzy o wymiarach 10 x 10. Można by tego dokonać tworząc 10 osobnych tablic jednowymiarowych, reprezentujących poszczególne wiersze macierzy. Jednak język C dostarcza nam dużo wygodniejszej metody, która w dodatku jest bardzo łatwa w użyciu. Są to tablice wielowymiarowegeeksforgeeks: dynamically-allocate-2d-array-c, lub inaczej "tablice tablic". Tablice wielowymiarowe definiujemy podając przy zmiennej kilka wymiarów, np.: float macierz; Tak samo wygląda dostęp do poszczególnych elementów tablicy: macierz = 1.2; Jak widać ten sposób jest dużo wygodniejszy (i zapewne dużo bardziej "naturalny") niż deklarowanie 10 osobnych tablic jednowymiarowych. Aby zainicjować tablicę wielowymiarową należy zastosować zagłębianie klamr, np.: float macierz = { { 1.6, 4.5, 2.4, 5.6 }, /* pierwszy wiersz */ { 5.7, 4.3, 3.6, 4.3 }, /* drugi wiersz */ { 8.8, 7.5, 4.3, 8.6 } /* trzeci wiersz */

Dodatkowo, pierwszego wymiaru nie musimy określać (podobnie jak dla tablic jednowymiarowych) i wówczas kompilator sam ustali odpowiednią wielkość, np.: float macierz[] = { { 1.6, 4.5, 2.4, 5.6 }, /* pierwszy wiersz */ { 5.7, 4.3, 3.6, 4.3 }, /* drugi wiersz */ { 8.8, 7.5, 4.3, 8.6 }, /* trzeci wiersz */ { 6.3, 2.7, 5.7, 2.7 } /* czwarty wiersz */

Innym, bardziej elastycznym sposobem deklarowania tablic wielowymiarowych, jest użycie wskaźników. Opisane to zostało w następnym rozdziale.

Kolejność głównych wierszy Kolejność głównych wierszy ( ang. Row Major Order = ROMRow-major_order w ang wikipedii)

W C tablica wielowymiarowa A[n][m] : jest przechowywana wierszamiMetody obliczeniowe w nauce i technice - laboratorium informatyka II rok, Katarzyna Zając : numeracja indeksów rozpoczyna się od zera

A, A, ..., A[m-1], A, A,..., A[n-1][m-1]

+ C: row-major order (lexicographical access order), zero-based indexing Addressx + N_x*y AccessA[y][x] Value 0 A 1 A 2 A 3 A 4 A 5 A

Przykładowy program : /* http://stackoverflow.com/questions/2151084/map-a-2d-array-onto-a-1d-array-c/2151113

* / #include

int main(int argc, char **argv) { int i, j, k; int arr; int *arr2 = (int*)arr;

for (k=0; k<15; k++) { arr2[k] = k; printf("arr[%d] = %2d\n", k, arr2[k]);

for (i=0; i<5; i++) { for (j=0; j< 3; j++) { printf("arr2[%d][%d] = %2d\n", i, j ,arr[i][j]);

Działania na tablicach deklaracja inicjacja dostęp do elementów użycie tablicy jako parametru funkcji Zapisywanie tablic do pliku

Sposoby deklaracji tablic Tablicę deklaruje się w następujący sposób: typ nazwa_tablicy[rozmiar]; gdzie rozmiar oznacza ile zmiennych danego typu możemy zmieścić w tablicy. Zatem aby np. zadeklarować tablicę, mieszczącą 20 liczb całkowitych możemy napisać tak: int tablica; Podobnie jak przy deklaracji zmiennych, także tablicy możemy nadać wartości początkowe przy jej deklaracji. Odbywa się to przez umieszczenie wartości kolejnych elementów oddzielonych przecinkami wewnątrz nawiasów klamrowych: int tablica = {0,1,2};

Niekoniecznie trzeba podawać rozmiar tablicy, np.: int tablica[] = {1, 2, 3, 4, 5}; W takim przypadku kompilator sam ustali rozmiar tablicy (w tym przypadku - 5 elementów).

Rozpatrzmy następujący kod: #include #define ROZMIAR 3 int main() { int tab[ROZMIAR] = {3,6,8}; int i; puts ("Druk tablicy tab:");

for (i=0; i<ROZMIAR; ++i) { printf ("Element numer %d = %d\n", i, tab[i]);

return 0; } Wynik:

Druk tablicy tab: Element numer 0 = 3 Element numer 1 = 6 Element numer 2 = 8

Jak widać, wszystko się zgadza.

W powyżej zamieszczonym przykładzie użyliśmy stałej do podania rozmiaru tablicy. Jest to o tyle pożądany zwyczaj, że w razie potrzeby zmiany rozmiaru tablicy, zmieniana jest tylko wartość w jednej linijce kodu przy #define, w innym przypadku musielibyśmy szukać wszystkich wystąpień rozmiaru rozsianych po kodzie całego programu.

Odczyt/zapis wartości do tablicy Tablicami posługujemy się tak samo jak zwykłymi zmiennymi. Różnica polega jedynie na podawaniu indeksu tablicy. Określa on, z którego elementu (wartości) chcemy skorzystać spośród wszystkich umieszczonych w tablicy. Numeracja indeksów rozpoczyna się od zera, co oznacza, że pierwszy element tablicy ma indeks równy 0, drugi 1, trzeci 2, itd.

Spróbujmy przedstawić to na działającym przykładzie. Przeanalizuj następujący kod: int tablica = {0}; int i = 0; tablica = 3; tablica = 7; for (i=0;i!=5;++i) { printf ("tablica[%d]=%d\n", i, tablica[i]); } Jak widać, na początku deklarujemy 5-elementową tablicę, którą od razu zerujemy. Następnie pod trzeci i czwarty element (liczone począwszy od 0) podstawiamy liczby 3 i 7. Pętla ma za zadanie wyprowadzić wynik naszych działań.

Tablica może być również zmieniana w obrębie funkcji

rozmiar tablicy Rozmiar tablicy jednowymiarowejstackoverflow question : how-do-i-determine-the-size-of-my-array-in-c

size_t n = sizeof( a ) / sizeof( a );

Zobacz : gcc Wsizeof-array-argument

Ograniczenia tablic Pomimo swej wygody tablice statyczne mają ograniczony, z góry zdefiniowany rozmiar, którego nie można zmienić w trakcie działania programu. Dlatego też w niektórych zastosowaniach tablice statyczne zostały wyparte tablicami dynamicznymi, których rozmiar może być określony w trakcie działania programu. Zagadnienie to zostało opisane w następnym rozdziale.

Wystarczy pomylić się o jedno miejsce (tzw. błąd off by one) by spowodować, że działanie programu zostanie nagle przerwane przez system operacyjny ( błąd przy uruchamianiu ) : int foo; int i;

for (i=0; i<=100; i+=1) /* powinno być i<100 */ foo[i] = 0;

/* program powinien zakończyć się błędem */

Rozwiązanie: cppcheck sprawdza zakres (Bounds checking )

Zobacz też Więcej o tablicach (rozszerzenie materiału) Tablice jako parameter funkcji tablice dynamiczne zfp to biblioteka C/C++ typu open source dla skompresowanych tablic numerycznych, która obsługuje dostęp swobodny do odczytu i zapisu o dużej przepustowości. zfp obsługuje również kompresję strumieniową danych całkowitych i zmiennoprzecinkowych, np. dla aplikacji, które odczytują i zapisują duże zbiory danych na dysku iz niego. zfp jest napisany głównie w C i C++, ale zawiera również powiązania Python i Fortran. BitArray in C by Isaac Turner