Jason. Cała informatyka w jednym miejscu!

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. 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 :)?

PODOBNE ARTYKUŁY