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).