Hlavní navigace

GLib: Soupravy dat (2)

27. 11. 2000
Doba čtení: 4 minuty

Sdílet

V dnešním díle vyprávění o soupravách dat dokončíme.

Odstraňování prvků z datových souprav

#define g_dataset_id_remove_data(l, k)
#define g_dataset_remove_data(l, k)

Tyto makra slouží ke zrušení položek soupravy dat napojených na data l. Rušenou položku můžete určit buď číselnou ( GQuark ovou) konstantou k (v případě g_dataset_id_remove_data()) nebo řetězcovým klíčem k (u makra g_dataset_remove_data()). Má-li rušená položka přiřazenou dealokovací funkci, její data se navíc automaticky uvolní z paměti.

Podobně jako v klíčovaných seznamech i u datových souprav máte možnost odstranit položku bez automatického volání dealokovací funkce. Provede se to jedním z následujících dvou způsobů:

void g_dataset_id_remove_no_notify(gconstpointer dataset_location,
                                   GQuark key_id);
#define g_dataset_remove_no_notify(l, k)

Přístupy se opět liší pouze způsobem adresace rušené položky. dataset_location a l je lokace „hlavních“ dat v paměti, key_id GQuark ový klíč a k řetězcový klíč odstraňované položky. I kdyby rušená položka měla asociovánu dealokovací funkci, voláním těchto dvou rutin se proces uvolnění dat nikdy neprovede.

Konstrukce „foreach“

void g_dataset_foreach(gconstpointer dataset_location,
                       GDataForeachFunc func,
                       gpointer user_data);

void(*GDataForeachFunc)(GQuark key_id, gpointer data,
                        gpointer user_data);

Pokud čtete články o knihovně GLib pravidelně, musí vás už (stejně jako mě) dost nudit znovu a znovu číst o funkcích „foreach“. Aby ale tento seriál mohl sloužit také trochu jako referenční příručka, nezbývá mi než poznamenat, že také soupravy dat disponují tímto voláním a ještě jednou zopakovat, jak funkce „foreach“ fungují:

Funkce g_dataset_foreach() zavolá na každý prvek soupravy dat, jejíž rozpoznávacím znakem je pointer dataset_location, uživatelskou funkci func, které předá GQuark ový klíč key_id prvku, jeho data data a uživatelská data user_data. Vykoná se tak něco jako příkaz „pro každou položku soupravy dat udělej __něco__“.

Uvolnění soupravy dat z paměti

void g_dataset_destroy(gconstpointer dataset_location); 

…voláním této funkce se souprava dat, která je napojena na dataset_location, uvolní z paměti. Na všechny její prvky budou zavolány (pokud existují) příslušné dealokovací funkce, takže se uvolní i uložená data. S „hlavními“ daty dataset_location se pochopitelně nestane nic – to musíte obstarat sami.

Příklad

Následující příklad simuluje typické použití souprav dat. Sestává ze tří souborů: libclovek.c a libclovek.h je jakási knihovna funkcí pro práci s databází kontaktů (opravdu primitivní – jen pro ukázku). Soubor main.c je pak hlavní program, který tuto knihovnu používá.

/************** Soubor: libclovek.h ***************/

/* struktura definujici jednoho cloveka */
typedef struct {
  gchar *jmeno;
  gchar *prijmeni;
} LibClovek;

/* deklarace funkce */
extern LibClovek* lib_cti_cloveka(void);



/************** Soubor: libclovek.c ***************/

/* Vnejsi knihovna pracujici s databazi kontaktu */

#include <glib.h>
#include „libclovek.h“

/* Funkce, ktera cte jednoho cloveka z databaze */
LibClovek* lib_cti_cloveka(void)
{
  LibClovek *clovek;

  clovek = g_malloc(sizeof(LibClovek));

  /* Tady by spravne melo byt cteni z databaze.
   * Pro jednoduchost vsak promennou clovek jen nejak
   * inicializujeme: */
  clovek->jmeno = "Karel";
  clovek->prijmeni = "Novak";

  return clovek;
}


/* Nacteni dalsiho cloveka :-) */
LibClovek* lib_cti_dalsiho_cloveka(void)
{
  LibClovek *clovek;

  clovek = g_malloc(sizeof(LibClovek));

  clovek->jmeno = "Josef";
  clovek->prijmeni = "Kvetinac";

  return clovek;
}



/**************** Soubor: main.c ******************/

/* Hlavni program */

#include <glib.h>
#include „libclovek.h“

#define ADRESA  1
#define TELEFON 2

gint main(void)
{
  LibClovek *clovek, *clovek2;

  /* Nacteni cloveka z databaze */
  clovek = lib_cti_cloveka();

  /* Struktura LibClovek nam nestaci. Chteli bychom u kazdeho
   * cloveka uchovavat jeste jeho telefonni cislo a adresu. */
  g_dataset_id_set_data(clovek, ADRESA, "Polni 22, Praha 8");
  g_dataset_id_set_data(clovek, TELEFON, "02/321321");

  /* Nacteni dalsiho cloveka */
  clovek2 = lib_cti_dalsiho_cloveka();
  g_dataset_id_set_data(clovek2, ADRESA, "Zahradni 1, Liberec");
  g_dataset_id_set_data(clovek2, TELEFON, "0386/111222");

/* ... nejake zpracovani ... */

  /* Kontrolni tisk */
  printf("%s %s, %s; telefon: %s\n",
    clovek->jmeno, clovek2->prijmeni,
    g_dataset_id_get_data(clovek, ADRESA),
    g_dataset_id_get_data(clovek, TELEFON));

  printf("%s %s, %s; telefon: %s\n",
    clovek2->jmeno, clovek2->prijmeni,
    g_dataset_id_get_data(clovek2, ADRESA),
    g_dataset_id_get_data(clovek2, TELEFON));

  g_dataset_destroy(clovek);
  g_dataset_destroy(clovek2);
  g_free(clovek);
  g_free(clovek2);
}

Soubor libclovek.h definuje strukturu LibClovek jejímiž prvky jsou řetězce jmenoprijmeni.

Soubor libclovek.c obsahuje dvě funkce, které toho opravdu moc nedělají – slouží jen k demonstraci. V reálném programu by načítaly z databáze jeden záznam a ve struktuře LibClovek jej předávaly jako návratovou hodnotu. Pro naši ukázku stačí, když alokují místo pro jeden záznam a inicializují ho nějakými statickými hodnotami.

Dostáváme k hlavnímu programu, souboru main.c. Jeho úkolem by v reálné situaci bylo nějakým způsobem údaje o lidech zpracovávat. Program využívá knihovnu libclovek, ale struktura LibClovek jeho účelům nestačí. Bylo by třeba u každého záznamu uchovávat ještě nějaké další údaje: třeba adresu a telefonní číslo. Do „standardní“ knihovny libclovek zasahovat nemůžeme, proto použijeme soupravy dat.

Ve zdrojovém kódu můžete vidět, jak se k adrese paměti, kterou uchovávají pointery clovek a clovek2 asociují řetězcové položky s klíči ADRESA a TELEFON.

Následuje kontrolní tisk všech údajů na obrazovku a dealokování veškerých dynamických dat.

V příkladu jsem záměrně nepoužil řetězcové konstanty – dokonce jsem vypustil celý mechanizmus kvarků. Chtěl jsem totiž ukázat, že k použití souprav dat, ale i klíčovaných seznamů dat je vůbec nepotřebujeme. Stačí, když si uvědomíme, že GQuark y nejsou nic jiného než přirozená čísla (1..???). A tak místo řetězců můžeme jednoduše používat konstantní makra (viz ADRESA a TELEFON).

Cloud 24 - tip 1

Ukázka by po zkompilování měla vypsat:

Karel Novak, Polni 22, Praha 8; telefon: 02/321321
Josef Kvetinac, Zahradni 1, Liberec; telefon: 0386/111222

Byl pro vás článek přínosný?

Autor článku

Michal Burda vystudoval informatiku a aplikovanou matematiku a nyní pracuje na Ostravské univerzitě jako odborný asistent. Zajímá se o data mining, Javu a Linux.