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ěší