Convenience! GLib for lists, sets, maps, and strings

GLib is a versatile utility library used in many applications and frameworks, especially those in the GNOME ecosystem. It provides data structures and utilities for C programming. Here's a guide on how to use some of its core features like ArrayLists, Sets, HashMaps, and Strings, along with installation and compilation instructions for Ubuntu.

Installing GLib in Ubuntu

  1. Update Package Lists:

     sudo apt update
    
  2. Install GLib:

     sudo apt install libglib2.0-dev
    

Compiling Code with GLib

To compile a program that uses GLib, use gcc with the pkg-config utility:

gcc `pkg-config --cflags --libs glib-2.0` -o your_program your_program.c

Replace your_program.c with the name of your C source file, and your_program with the desired name of the compiled executable.

Sample Code and Explanation

1. ArrayLists (GArray)

GArray is a resizable array which can hold any data type. Here's an example of using it with integers:

#include <glib.h>

int main() {
    GArray *array = g_array_new(FALSE, FALSE, sizeof(int));
    int num = 15;

    // Adding elements
    g_array_append_val(array, num);

    // Accessing elements
    num = g_array_index(array, int, 0);

    // Removing an element
    g_array_remove_index(array, 0);

    // Free the array
    g_array_free(array, TRUE);

    return 0;
}

Including GLib

#include <glib.h>

This line includes the GLib header file, which contains the necessary declarations for using the GLib library in your program.

main Function

int main() {

This line starts the definition of the main function, which is the entry point of a C program.

Creating a GArray

GArray *array = g_array_new(FALSE, FALSE, sizeof(int));
  • g_array_new: This function creates a new GArray.

  • The first argument (FALSE) indicates that the array should not have zero-terminated elements. This is often set to TRUE for arrays of characters (strings), but for an integer array, FALSE is appropriate.

  • The second argument (FALSE) decides whether the array elements should be cleared to 0 when they are allocated. For simple data types like int, this is typically not necessary.

  • The third argument (sizeof(int)) specifies the size of each element in the array. In this case, we are storing integers, so the size is sizeof(int).

Adding an Element to the Array

int num = 15;
g_array_append_val(array, num);
  • First, an integer num is initialized to 15.

  • g_array_append_val: This macro appends the value of num to the end of the array. It's a convenient way to add elements to a GArray.

Accessing Elements

num = g_array_index(array, int, 0);
  • g_array_index: This macro is used for accessing elements of the array.

  • It takes three arguments: the array, the type of the elements (int in this case), and the index of the element to access (0 here, which is the first element).

Removing an Element

g_array_remove_index(array, 0);
  • This function removes an element from the array.

  • The first argument is the array, and the second argument is the index of the element to remove. Here, it removes the element at index 0.

Freeing the Array

g_array_free(array, TRUE);
  • g_array_free: This function is used to free the memory allocated for the array.

  • The first argument is the array to be freed.

  • The second argument (TRUE) decides whether to free the actual element data. If set to TRUE, it frees the memory allocated for the elements as well. If your array holds pointers to dynamically allocated data, you might need to manually free those before calling g_array_free.

2. Sets (GHashSet)

GHashSet provides a way to store unique elements. Here's how you can use it:

#include <glib.h>

int main() {
    GHashTable *set = g_hash_table_new(g_direct_hash, g_direct_equal);

    // Adding elements
    g_hash_table_add(set, GINT_TO_POINTER(1));

    // Checking if an element is in the set
    gboolean is_present = g_hash_table_contains(set, GINT_TO_POINTER(1));

    // Removing an element
    g_hash_table_remove(set, GINT_TO_POINTER(1));

    // Free the set
    g_hash_table_destroy(set);

    return 0;
}

The provided code snippet demonstrates the usage of GHashTable in GLib as a set. GHashTable is a versatile hash table structure that can be used to implement various data structures, including sets and maps. In this example, it's used as a set to store unique elements. Let's break down the code:

Creating a GHashTable

GHashTable *set = g_hash_table_new(g_direct_hash, g_direct_equal);
  • g_hash_table_new: This function creates a new GHashTable.

  • g_direct_hash: A function pointer to a hashing function. g_direct_hash is suitable for hashing pointers or integer values directly. It basically returns the key as its own hash.

  • g_direct_equal: A function pointer to a key equality function. g_direct_equal compares pointers for equality, which is appropriate when using the hash table as a set of integers.

Adding Elements

g_hash_table_add(set, GINT_TO_POINTER(1));
  • g_hash_table_add: This function adds a unique element to the set. If the element already exists in the set, the function does nothing.

  • GINT_TO_POINTER(1): This macro converts an integer to a pointer. In C, hash tables cannot directly handle integers as keys or values since they work with pointers. This is a common technique to store integers in a data structure that expects pointers.

Checking if an Element is in the Set

gboolean is_present = g_hash_table_contains(set, GINT_TO_POINTER(1));
  • g_hash_table_contains: This function checks whether the set contains a specific element.

  • GINT_TO_POINTER(1): Again, the integer 1 is converted to a pointer for the check.

  • The result (TRUE or FALSE) is stored in the gboolean variable is_present.

Removing an Element

g_hash_table_remove(set, GINT_TO_POINTER(1));
  • g_hash_table_remove: This function removes an element from the set.

  • The element to remove is specified by GINT_TO_POINTER(1), which is the pointer representation of the integer 1.

Freeing the Set

g_hash_table_destroy(set);
  • g_hash_table_destroy: This function releases all memory used by the GHashTable.

  • It not only frees the memory used by the hash table structure itself but also the memory for the elements stored in it. Since in this case, the elements are simple integer pointers (not dynamically allocated memory), there's no need for additional cleanup.

3. HashMaps (GHashTable)

GHashTable maps keys to values. This is a small example of using it:

#include <glib.h>

int main() {
    GHashTable *hash = g_hash_table_new(g_str_hash, g_str_equal);

    // Inserting key-value pairs
    g_hash_table_insert(hash, "key1", "value1");

    // Accessing value by key
    char *value = g_hash_table_lookup(hash, "key1");

    // Removing a key-value pair
    g_hash_table_remove(hash, "key1");

    // Free the hash table
    g_hash_table_destroy(hash);

    return 0;
}

Sure, let's go through this code snippet, which demonstrates the use of GHashTable as a map in GLib. A hash table is a data structure that maps keys to values, providing efficient lookup, insertion, and deletion. In GLib, GHashTable is a generic implementation of such a hash table. The code snippet uses strings as keys and values, which is a common use case.

Creating a GHashTable

GHashTable *hash = g_hash_table_new(g_str_hash, g_str_equal);
  • g_hash_table_new: This function creates a new GHashTable.

  • g_str_hash: A function pointer to a hashing function for strings. It calculates a hash value for a given string key. This is important for efficiently storing and retrieving data based on string keys.

  • g_str_equal: A function pointer to a key comparison function for strings. It determines how to compare two string keys for equality, which is crucial for operations like lookup and removal.

Inserting Key-Value Pairs

g_hash_table_insert(hash, "key1", "value1");
  • g_hash_table_insert: This function inserts a new key-value pair into the hash table.

  • "key1": The string used as the key.

  • "value1": The string used as the value associated with "key1".

  • Note: In this particular usage, the keys and values are string literals. In a more dynamic scenario, you might use dynamically allocated strings or other types of data.

Accessing Value by Key

char *value = g_hash_table_lookup(hash, "key1");
  • g_hash_table_lookup: This function is used to find the value associated with a given key in the hash table.

  • "key1": The key for which the value is to be retrieved.

  • The return value is a pointer to the value associated with the key. If the key is not found in the hash table, the function returns NULL.

Removing a Key-Value Pair

g_hash_table_remove(hash, "key1");
  • g_hash_table_remove: This function removes a key-value pair from the hash table.

  • "key1": The key of the key-value pair to be removed.

  • When a key-value pair is removed, both the key and the value are removed from the table. If you have dynamically allocated memory for keys or values, you should free it before removing them from the hash table.

Freeing the Hash Table

g_hash_table_destroy(hash);
  • g_hash_table_destroy: This function releases all the memory used by the GHashTable.

  • It frees the memory used by the hash table structure. If the hash table contains dynamically allocated memory as keys or values, you must free them using a custom destroy function or manually free them before calling this function.

4. Strings (GString)

GString is a mutable string utility in GLib:

#include <glib.h>

int main() {
    GString *str = g_string_new("Hello");

    // Appending to a string
    g_string_append(str, " World");

    // Accessing the string's value
    printf("%s\n", str->str);

    // Replacing part of the string
    g_string_replace(str, "World", "GLib");

    // Free the string
    g_string_free(str, TRUE);

    return 0;
}

This code snippet demonstrates the use of GString, a dynamic string utility provided by GLib. GString is used for string manipulation, offering more flexibility than standard C strings. Let's break down the code:

Creating a GString

GString *str = g_string_new("Hello");
  • g_string_new: This function creates a new GString and initializes it with the given string.

  • "Hello": The initial value of the GString.

  • str: A pointer to the GString object.

Appending to a String

g_string_append(str, " World");
  • g_string_append: This function appends a string to the end of the GString.

  • " World": The string to be appended.

  • After this operation, str will contain "Hello World".

Accessing the String's Value

printf("%s\n", str->str);
  • str->str: This is how you access the actual C string (char *) contained within the GString object. GString maintains a null-terminated C string for compatibility.

  • The printf function is then used to print the current value of the GString, which at this point is "Hello World".

Replacing Part of the String

g_string_replace(str, "World", "GLib");
  • g_string_replace: This function is not a standard GLib function. Typically, g_string_replace would be a custom function or part of an extension to GLib. Assuming it replaces all occurrences of a substring with another substring within the GString.

  • The code intends to replace "World" with "GLib" in the GString. However, without the implementation details of g_string_replace, we can't be sure how it behaves. If it works as expected, the GString str would then contain "Hello GLib".

Freeing the String

g_string_free(str, TRUE);
  • g_string_free: This function is used to free the memory allocated for the GString.

  • str: The GString to be freed.

  • The TRUE argument indicates that the function should also free the character data (str->str). If set to FALSE, the function would only free the GString wrapper, and you would need to free str->str manually.

0
Subscribe to my newsletter

Read articles from Jyotiprakash Mishra directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jyotiprakash Mishra
Jyotiprakash Mishra

I am Jyotiprakash, a deeply driven computer systems engineer, software developer, teacher, and philosopher. With a decade of professional experience, I have contributed to various cutting-edge software products in network security, mobile apps, and healthcare software at renowned companies like Oracle, Yahoo, and Epic. My academic journey has taken me to prestigious institutions such as the University of Wisconsin-Madison and BITS Pilani in India, where I consistently ranked among the top of my class. At my core, I am a computer enthusiast with a profound interest in understanding the intricacies of computer programming. My skills are not limited to application programming in Java; I have also delved deeply into computer hardware, learning about various architectures, low-level assembly programming, Linux kernel implementation, and writing device drivers. The contributions of Linus Torvalds, Ken Thompson, and Dennis Ritchie—who revolutionized the computer industry—inspire me. I believe that real contributions to computer science are made by mastering all levels of abstraction and understanding systems inside out. In addition to my professional pursuits, I am passionate about teaching and sharing knowledge. I have spent two years as a teaching assistant at UW Madison, where I taught complex concepts in operating systems, computer graphics, and data structures to both graduate and undergraduate students. Currently, I am an assistant professor at KIIT, Bhubaneswar, where I continue to teach computer science to undergraduate and graduate students. I am also working on writing a few free books on systems programming, as I believe in freely sharing knowledge to empower others.