Search code examples
cpointersglib

gpointer cast to gint * causes segmentation fault - why?


I'm trying to learn using void pointers in C. Here's a code I've written using GLib:

#include <stdio.h>
#include <gtk/gtk.h>

int
main (void)
{
  GList *l = NULL;
  l = g_list_append (l, GINT_TO_POINTER (1));
  l = g_list_append (l, GINT_TO_POINTER (2));
  l = g_list_append (l, GINT_TO_POINTER (3));
  GList *l1 = g_list_nth (l, 1);
  gpointer snd_element = (l1->data);
  gint *digit = snd_element;
  gint forty_two = 40;
  forty_two = forty_two + *digit;
  printf ("%d\n", forty_two);

  return 0;
}

The behaviour I expect from this program would be to print 42. Unfortunately running it causes segmentation fault. Why?


Solution

  • g_list_append expects a pointer to the data you want to store to be passed. GINT_TO_POINTER simply converts the given integer to a pointer (i.e. it's basically (gpointer)x), hence the pointer isn't actually pointing at any valid data, it's just a number. After adding the data to the list, the pointers will have the value 1, 2 and 3.

    Assuming that g_list_nth is successful, l1->data will be the pointer passed to g_list_append earlier. In this case, the value of the pointer will be 2 (not the value being pointed to). You then attempt to dereference this pointer, which will cause a segmentation fault.

    Instead, just cast it straight back to an int and don't dereference to get the value back. You should probably use the provided reverse macro GPOINTER_TO_INT though, e.g.

    gpointer snd_element = (l1->data);
    gint digit = GPOINTER_TO_INT(snd_element); // Note I've removed the *...
    gint forty_two = 40;
    forty_two = forty_two + digit; // Note I've not attempted to dereference it