Czas wrócić do niedokończonego epizodu na temat tablic w języku C! Zakończmy te dwa artykuły, o których była mowa. Teraźniejszy temat to będzie tablica o zmiennym rozmiarze (ang. variable length array), czyli w skrócie "VLA" w języku C, to kolejny dodatek standardu C99 z 1999 roku wprowadzony przez organizację ISO (Międzynarodowa Organizacja Normalizacyjna). Patrząc na termin to trochę może być dziwne rozumowanie czym konkretnie jest "zmienny rozmiar". Czyżby język C oferował jakąś prototypową rewolucję w postaci tablicy dynamicznej? A może chodzi o możliwość wprowadzania do funkcji tablic o różnych rozmiarach, nie tylko sztywno ustawionych w kodzie? Rozwiejmy te wątpliwości raz na zawsze.
CO NAM OFERUJE TABLICA O ZMIENNYM ROZMIARZE, "VLA" W JĘZYKU C?
Tablica o zmiennym rozmiarze umożliwia nam definiowanie tablic podając rozmiary wymiarów w postaci zmiennych, zatem wbrew wstępnemu wnioskowaniu to NIE JEST żadna tablica dynamiczna, że sobie żonglujemy rozmiarami jak chcemy (taki hokus-pokus to tylko przy manualnym zarządzaniu pamięcią) :D. Wadą tego jest to, że nie możemy zadeklarować tablicy i za jednym zamachem wprowadzić wartości. Dla zobrazowania o co mi chodzi. Taki zapis:
int numbers[ROWS][COLUMNS] = {{...}, {...}, ...};
jest niedopuszczalny! Natomiast przy tradycyjnej tablicy już to jest dozwolone:
int numbers[2][4] = {{5, 7, 34, -100}, {-97, 56, 8, 42}};
PRZYKŁAD KODU ŹRÓDŁOWEGO
Dobrze, wytknęliśmy wadę. A zalety? Oprócz możliwości uzależnienia rozmiaru tablicy od zmiennych typu "liczba całkowita", "VLA" w języku C jest szczególnie użyteczne przy definiowaniu funkcji dokonujących operacji na tablicach. Tradycyjnie, musielibyśmy definiować każdą osobną funkcję dla rozmiaru N drugiego wymiaru w taki sposób:
#define COLUMNS 3
int printNumbers(int array[][COLUMNS], int rows)
{
for (int r = 0; r < rows; ++r)
{
for (int c = 0; c < COLUMNS; ++c)
{
printf("array[%d][%d] = %d\n", r, c, array[r][c]);
}
}
}
Wywołania przy których drugi wymiar jest zawsze równy 3 wypalą, ale w razie innego rozmiaru byłby już spory kłopot. W języku C, sztywno ustawiane rozmiary wymiarów tablic MUSZĄ być jasno określone w nagłówku funkcji za wyjątkiem pierwszego wymiaru najbardziej "wysuniętego na lewo" po nazwie. A to dlatego, że język automatycznie traktuje podaną tablicę jako wskaźnik i żeby móc przemieszczać się po argumentach "wskaźnikowo", kompilator musi wiedzieć jakiego rozmiaru są wszystkie wymiary. Wyjątkiem jest ten pierwszy wymiar z racji tego, że zgodnie z notacją wskaźnikową, inkrementowanie samego adresu tablicy powoduje "przesunięcie się" o jeden wymiar do przodu (w tym przypadku o jeden cały rząd).
A teraz dla porównania, tak wygląda "VLA" w języku C w akcji:
#include <stdio.h>
void assignNumbers(int rows, int columns, int array[rows][columns]);
void printSum(int rows, int columns, int array[rows][columns]);
int main(void)
{
int numbersA[3][2] =
{
{67, 105},
{100, -97},
{88, -915}
};
const int ROWS = 4, COLUMNS = 6;
int numbersB[ROWS][COLUMNS]; // tablica o zmiennym rozmiarze (VLA)
assignNumbers(ROWS, COLUMNS, numbersB);
printSum(3, 2, numbersA);
printSum(ROWS, COLUMNS, numbersB);
getchar();
return 0;
}
void assignNumbers(int rows, int columns, int array[rows][columns])
{
for (int r = 0; r < rows; ++r)
{
for (int c = 0; c < columns; ++c)
{
array[r][c] = columns*r + c + 1;
}
}
}
void printSum(int rows, int columns, int array[rows][columns])
{
for (int r = 0; r < rows; ++r)
{
for (int c = 0; c < columns; ++c)
{
printf("array[%d][%d] = %d\n", r, c, array[r][c]);
}
}
putchar('\n');
}
To już nieco większy kod. Po ustaleniu prototypów funkcji, w "main" tworzymy dwie tablice dwuwymiarowe. Jedna za pomocą tradycyjnego zapisu ANSI C, a druga to tablica o zmiennym rozmiarze. "VLA" w języku C otrzymuje rozmiary wymiarów na podstawie użytych stałych liczb całkowitych. Ponieważ tutaj niemożliwe jest inicjalizowanie wartości, wywołujemy funkcję przypisującą numerki do argumentów, a następnie sprawdzamy wszystkie wartości obu tablic przy użyciu funkcji "printSum". Takie są wnioski końcowe.
Czy jesteście przygotowani na kolejny artykuł o tablicach :)?