Home > Mobile >  How do you pass pointers/arrays as parameters to a GTK callback function?
How do you pass pointers/arrays as parameters to a GTK callback function?

Time:09-16

I want to pass a list of integers, numbers to a callback function printer, which will print the contents of numbers when a button is pressed. The last post in this forum thread suggests that I do something like this:

#include <gtk/gtk.h>

static void printer(GtkButton *button, gpointer user_data)
{
    int *array = user_data;
    g_print("%d %d %d %d %d\n", array[0], array[1], array[2], array[3], array[4]);
}

static void activate(GtkApplication *app, gpointer user_data)
{
    GtkWidget *win;
    GtkWidget *box;
    GtkWidget *button;

    // initialize numbers
    int numbers[5] = {2, 3, 5, 7, 11};
   
    // window
    win = gtk_application_window_new(GTK_APPLICATION(app));
    gtk_window_set_title(GTK_WINDOW(win), "Printer");
    gtk_window_set_default_size(GTK_WINDOW(win), 80, 80);
    
    // box
    box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    gtk_window_set_child(GTK_WINDOW(win), box);  
    
    // button
    button = gtk_button_new_with_label("Test");
    g_signal_connect(button, "clicked", G_CALLBACK(printer), (gpointer) numbers);
    gtk_box_append(GTK_BOX(box), button);

    gtk_window_present(GTK_WINDOW(win));
}

int main (int argc, char **argv)
{
    GtkApplication *app;
    int status;
    
    app = gtk_application_new("com.example.printer", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);
    
    return status;
}

However, when I try to execute this, the program outputs:

0 0 0 32583 0

If the callback function modifies the contents of the array before it prints them, then the results printed will be correct:

static void printer(GtkButton *button, gpointer user_data)
{
    int *array = user_data;
    array[0] = 3;
    array[1] = 2;
    array[2] = 1;
    array[3] = 0;
    array[4] = -1;
    g_print("%d %d %d %d %d\n", array[0], array[1], array[2], array[3], array[4]);
}

This outputs 3 2 1 0 -1 as expected.

I'm not sure why array[x] are different in both cases. Is this the recommended way for passing arrays into a callback function, and why doesarray[x] return different values in both cases?

CodePudding user response:

The array whose address you are passing to the callback function is local to the activate function. So, when that callback is (later) actually made, the activate function has finished and the data buffer pointed to (numbers) has gone out of scope. Thus, you have undefined behaviour.

In your case, that memory is still accessible to the callback routine (but don't rely on this) but the data you placed there in the initialization have been overwritten (by what code sector and how many times, is almost impossible to tell, as the memory will likely be somewhere on the stack) – hence the garbage values you're seeing. However, when you give new values in the callback function (printer), those values are displayed correctly (but you still, technically, have undefined behaviour, because the memory pointed to by user_data may no longer be available).

One way to fix this would be to make the numbers array static, so that the memory is preserved when the activate function finishes:

static void activate(GtkApplication *app, gpointer user_data)
{
    GtkWidget *win;
    GtkWidget *box;
    GtkWidget *button;

    // initialize numbers
    static int numbers[5] = {2, 3, 5, 7, 11}; // Make "static" to preserve after call

//...   

Other options would be: (a) make the numbers array a global variable (not so good and often much frowned-upon); (b) allocate the memory for the array dynamically (on the heap), using malloc (but you would then need to free that memory when you're done with it).

  • Related