如何将 pointers/arrays 作为参数传递给 GTK 回调函数?

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

我想将整数列表 numbers 传递给回调函数 printer,按下按钮时它将打印 numbers 的内容。 this 论坛帖子中的最后一个 post 建议我这样做:

#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;
}

然而,当我尝试执行这个时,程序输出:

0 0 0 32583 0

如果回调函数在打印之前修改了数组的内容,那么打印的结果将是正确的:

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]);
}

这会按预期输出 3 2 1 0 -1

我不确定为什么 array[x] 在这两种情况下都不一样。这是将数组传递给回调函数的推荐方法吗?为什么 array[x] return 两种情况下的值不同?

您要传递给回调函数的地址数组是 localactivate 函数。因此,当(稍后)实际进行回调时,activate 函数已完成并且指向 (numbers) 的数据缓冲区已超出范围。因此,您有未定义的行为。

在你的情况下,回调例程仍然可以访问该内存(但不要依赖于此)但是你在初始化中放置在那里的数据已被覆盖(被什么代码扇区和多少次,是几乎不可能分辨,因为内存很可能在堆栈的某个地方)——因此你看到的是垃圾值。但是,当您在回调函数 (printer) 中提供 new 值时,这些值会正确显示(但从技术上讲,您仍然有未定义的行为,因为内存指向来自 user_data 可能 不再可用)。

解决此问题的一种方法是创建 numbers 数组 static,以便在 activate 函数完成时保留内存:

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

//...   

其他选项是:(a) 使 numbers 数组成为一个全局变量(不太好,而且常常不受欢迎); (b) 使用 malloc 为数组动态分配内存(在堆上)(但是当你用完它时你需要释放该内存)。