Přístup k těmto polím je velice podobný přístupu k automaticky rostoucím řetězcům GString – vždyť také mají mnoho společného. „Nafukovací“ pole knihovny GLib jsou definovány strukturou GArray:
struct GArray
{
gchar *data;
guint len;
}
Přístup k údajům v této struktuře není omezován, měli byste však být opatrní, chcete-li na nich cokoliv měnit.
Prvek data je pointer na informace uložené v poli a můžete k němu přistupovat jako ke standardnímu céčkovskému poli. Jak se však bude pole zvětšovat, bude se také realokovat a proto se tento pointer může měnit. len uchovává počet položek v poli.
Vytvoření pole GArray
Nové, dynamicky se zvětšující pole GArray vytvoříte funkcí
GArray* g_array_new(gboolean zero_terminated, gboolean clear,
guint element_size);
Argument zero_terminated nastavte na TRUE, chcete-li, aby pole mělo vždy na svém konci vynulovaný prvek (aby bylo ukončeno nulovým (‚0‘) prvkem). Jinak použijte hodnotu FALSE.
Chcete-li, aby byly všechny nově alokované položky vynulovány (nastaveny na samé ‚0‘) zvolte jako argument clear hodnotu TRUE.
element_size
Funkce vrátí pointer na nově alokovaný GArray, který by měl být nakonec zrušen voláním g_array_free().
Přidávání položek do pole GArray
#define g_array_append_val(a,v)
…vytvoří na konci pole a nový prvek a zkopíruje do něj hodnotu v. GArray a svou velikost podle potřeby zvětší. Makro vrátí hodnotu argumentu a.
Důležité. g_array_append_val() je makro, kterým ve skutečnosti voláte funkci g_array_append_vals(). Používá se v něm reference na v, což znamená, že v MUSÍ být proměnná (a ne konstanta, jako např. „ 96“).
GArray* g_array_append_vals(GArray *array, gconstpointer data,
guint len);
Tato funkce vloží len prvků pole data na konec dynamického pole array. data je tedy pointer na první položku, která se má do pole přidat a len je počet těchto položek. GArray array se podle potřeby automaticky zvětší.
Obdobou k této dvojici jsou:
#define g_array_prepend_val(a,v)
GArray* g_array_prepend_vals(GArray *array, gconstpointer data,
guint len);
…které dělají totéž co makro g_array_append_val() a funkce g_array_append_vals() s tím rozdílem, že položky nepřidávají na konec, ale na začátek pole a ( array). Je třeba znovu upozornit na fakt, že argument v (makra g_array_prepend_val) musí být proměnná a ne jen konstanta (jako např. „ 96“), protože po rozvinutí makra se žádá reference ( &) na něj.
Operace přidání prvku na začátek GArray je pomalejší než přidávání na konec, protože se všechny prvky pole musí v paměti posunout, aby uvolnily místo první, nově vkládané, položce.
#define g_array_insert_val(a,i,v)
…vytvoří novou položku v dynamickém poli a na pozici i a zkopíruje do ní hodnotu argumentu v. Že parametr v musí být proměnná, už snad nemusím zdůrazňovat.
GArray* g_array_insert_vals(GArray *array, guint index,
gconstpointer data, guint len);
Tato funkce se postará o vložení len prvků z adresy data na index-tou pozici v dynamickém poli array. data je tedy pointer na první vkládaný prvek, len je počet prvků a index je místo v poli array, kam se položky umístí. Prvky pole array za tímto indexem se pochopitelně automaticky posunou, aby udělaly pro nově vkládané položky místo a GArray array podle potřeby zvětší svou velikost tak, aby mohl pojmout všechny údaje.
GArray* g_array_set_size(GArray *array, guint length);
…nastaví velikost pole array na hodnotu length. Pole se podle potřeby realokuje. Bylo-li pole array vytvořeno s argumentem clear nastaveným na TRUE, budou všechny nové položky vynulovány (všechny jejich bajty nastaveny na 0) – viz funkce g_array_create(). Funkce vrátí hodnotu argumentu array.
Odstraňování položek z GArray
GArray* g_array_remove_index(GArray *array, guint index);
…odstraní z dynamického pole array položku s indexem index. Vzniklá mezera se vyplní posunutím zbývajících prvků pole na její místo. Funkce zachovává pořadí prvků. Vrácenou hodnotou je pointer na GArray.
GArray* g_array_remove_index_fast(GArray *array, guint index);
Jak již název napovídá, půjde o rychlejší variantu funkce na odstranění položky z pole array. Čas na vykonání operace se ušetří tak, že po odstranění položky s indexem index se místo posouvání zbývajících prvků do vzniklé mezery přesune poslední prvek pole. Funkce g_array_remove_index_fast() proběhne o něco rychleji než funkce g_array_remove_index(), její nevýhodou však je, že nezachovává pořadí prvků v poli. To ji tedy předurčuje k použití pouze tam, kde tato vlastnost nevadí (kde nezáleží na pořadí položek v poli a je jedno, jaký index prvky mají).
Odkazování se na položky pole
K přístupu k položkám dynamických polí můžete použít makro
#define g_array_index(a,t,i)
…které vrátí položku pole a s indexem i. Výsledek je přetypován na typ t.
Podívejme se však blíže, jak je makro g_array_index() definováno:
#define g_array_index(a,t,i) (((t*) (a)->data) [(i)])
To, že v podstatě pouze zastřešuje práci s položkou data struktury GArray, jej předurčuje i k poněkud kurióznějším použitím, které by v případě, že by g_array_index() byla funkce, nebylo možné. Následující použití jsou plně v souladu se syntaxí jazyka C:
/* prirazeni hodnoty 5. polozce pole */
g_array_index(array, gint, 5) = 0;
/* prace s polozkou number struktury MyStruct,
ktera je 7. prvkem pole */
g_array_index(array, struct MyStruct, 7).number = 12;
/* ziskani pointeru na 3. polozku pole */
p = &(g_array_index(array, gfloat, 3));
Příklad:
/* ukazka prace s makrem g_array_index() */
#include <glib.h>
/* Definice nasi struktury */
struct MyStruct {
gint number;
gfloat value;
gchar *name;
};
gint main(void)
{
GArray *array;
struct MyStruct item, *item2;
gint x;
/* vytvoreni noveho GArray */
array = g_array_new(FALSE, FALSE, sizeof(struct MyStruct));
/* vytvoreni nekolika polozek pole s nejakymi hodnotami */ for (x = 0; x < 20; x++) { item.number = x; item.value = x * 134.28; g_array_append_val(array, item); }
/* obsah 15. prvku se zkopiruje do promenne item */
item = g_array_index(array, struct MyStruct, 15);
item.number = 30; /* s prvkem pole se nic nestane */
printf("%d-ta polozka: number = %d\n", 15,
g_array_index(array, struct MyStruct, 15).number);
/* prepisujeme hodnoty 15. prvku pole */
g_array_index(array, struct MyStruct, 15).number = 333;
printf("%d-ta polozka: number = %d\n", 15,
g_array_index(array, struct MyStruct, 15).number);
/* nyni chceme pointer na 15. polozku pole */
item2 = &(g_array_index(array, struct MyStruct, 15));
item2->number = 100;
printf("%d-ta polozka: number = %d\n", 15,
g_array_index(array, struct MyStruct, 15).number);
/* znovu prepisujeme hodnoty 15. prvku pole */
g_array_index(array, struct MyStruct, 15).number = 500;
/* dukaz, ze jsme pointer vytvorili spravne */
printf("%d-ta polozka: number = %d\n", 15,
item2->number);
/* dealokace pole vcetne jeho polozek z pameti */
g_array_free(array, TRUE);
return(0);
}
Pro informaci, tento příklad by měl po spuštění vypsat:
15-ta polozka: number = 15 15-ta polozka: number = 333 15-ta polozka: number = 100 15-ta polozka: number = 500
Pečlivý čtenář si jistě prostuduje, co to znamená.
Uvolnění GArray z paměti
Ukončíte-li práci s poli automatické velikosti GArray, musíte je dealokovat. K tomu slouží funkce
void g_array_free(GArray *array, gboolean free_segment);
Je-li free_segment nastaven na TRUE, uvolní se také data udržované polem array. Je-li naopak free_segment roven FALSE, můžete data i nadále používat jako obyčejné céčkovské pole. (Nesmíte však zapomenout je nakonec uvolnit voláním g_free()!)
Příklad:
Na závěr ještě jeden příklad na použití „nafukovacího“ pole GArray.
/* ukazka prace s GArray */
#include <glib.h>
gint main(void)
{
GArray *array;
gint item;
gint items[20];
gint *my_data;
gint x;
/* vytvoreni noveho GArray (ktery bude zero-terminated) */
array = g_array_new(TRUE, FALSE, sizeof(gint));
/* vytvoreni nekolika polozek pole s nejakymi hodnotami */
for (x = 0; x < 1000; x++) {
item = x + 1;
g_array_append_val(array, item);
}
/* vlozeni pole items do "nafukovaciho" pole array */
for (x = 0; x < 20; x++) {
items[x] = x + 1001;
}
g_array_append_vals(array, items, sizeof(items) / sizeof(gint));
my_data = (gint *) array->data;
/* dealokace pole (polozky v pameti zustavaji) */
g_array_free(array, FALSE);
/* kontrolni vypis */
x = 0;
while (my_data[x] != 0) {
printf("%d ", my_data[x]);
x++;
}
puts("");
/* dealokace polozek pole */
g_free(my_data);
return(0);
}
Tento příklad ukazuje možné použití pole GArray. Na začátku je pole vytvořeno s příznakem zero-terminated nastaveným na TRUE, abychom mohli jednoznačně identifikovat jeho konec. To znamená, že bude obsahovat vždy o jednu položku navíc, která bude vynulována. Pak jsou do něj přidávána nějaká data a nakonec je pole dealokováno funkcí g_array_free(). Její parametr free_segment je však nastaven na FALSE, což znamená že se dealokuje pouze pole array – jeho data zůstanou v paměti nedotčena. Proto také s nimi můžeme ještě pracovat a vypsat kontrolní výpis. Nakonec je však třeba i tyto data dealokovat.
Vše samozřejmě mohlo proběhnout i jinak. Kontrolní výpis jsme mohli provést ještě před voláním funkce g_array_free() a pak jejím voláním dealokovat všechno najednou:
g_array_free(array, TRUE)
K výpisu celého obsahu pole jsme mohli místo zavedení posledního nulového prvku ( zero-terminated nastaveno na TRUE) využít skutečnosti, že array->len obsahuje počet prvků v poli a podobně.
A to je pro dnešek z mé strany vše. U dalšího povídání o knihovně GLib se těší