使用gtk_window_get_title时GTK3+出现段错误问题求助
问题分析与修复
你的代码出现段错误的核心原因有两个:
- 访问已销毁的对象:你先销毁了旧的
grid,再通过这个已经被释放的grid调用gtk_widget_get_toplevel获取窗口,这时候grid的内存已经被回收,后续操作属于非法内存访问,导致获取窗口标题返回null,触发strcmp的段错误。 - 按钮挂载到错误的容器:返回页面1的分支里,你把按钮添加到了已经销毁的旧
grid,而不是新创建的gridNew,这同样会引发非法访问问题。
另外,直接用strcmp比较titles存在风险,需要先判断titles是否不为null,避免空指针传入strcmp导致崩溃。
修复后的完整代码
#include <stdio.h> #include <string.h> #include <gtk/gtk.h> char *PgTwo = "Page 2"; char *PgOne = "Page 1"; static void NewCallback(GtkWidget *grid, gpointer user_data) { GtkWidget *gridNew; GtkWidget *window; GtkWidget *button; // 提前获取顶层窗口,在销毁grid之前完成,避免访问已销毁对象 window = gtk_widget_get_toplevel(grid); // 确保获取的是有效窗口 if (!GTK_IS_WINDOW(window)) { return; } gridNew = gtk_grid_new(); gtk_widget_destroy(grid); char *titles = gtk_window_get_title(GTK_WINDOW(window)); // 先判断titles是否非空,再进行字符串比较 if (titles && strcmp(titles, PgTwo) == 0) { gtk_window_set_title(GTK_WINDOW(window), "Page 1"); gtk_container_add(GTK_CONTAINER(window), gridNew); button = gtk_button_new_with_label("Next Page"); g_signal_connect_swapped(button, "clicked", G_CALLBACK(NewCallback), gridNew); gtk_grid_attach(GTK_GRID(gridNew), button, 0, 1, 2, 1); button = gtk_button_new_with_label("Quit"); g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_widget_destroy), window); gtk_grid_attach(GTK_GRID(gridNew), button, 0, 2, 2, 1); } else if ((!titles || strcmp(titles, PgOne) == 0)) { gtk_window_set_title(GTK_WINDOW(window), "Page 2"); gtk_container_add(GTK_CONTAINER(window), gridNew); button = gtk_button_new_with_label("Back to Main Menu"); g_signal_connect_swapped(button, "clicked", G_CALLBACK(NewCallback), gridNew); gtk_grid_attach(GTK_GRID(gridNew), button, 0, 1, 2, 1); } gtk_widget_show_all(window); } static void activate(GtkApplication *app, gpointer user_data) { GtkWidget *window; GtkWidget *grid; GtkWidget *button; window = gtk_application_window_new(app); gtk_window_set_title(GTK_WINDOW(window), "Page 1"); gtk_container_set_border_width(GTK_CONTAINER(window), 100); grid = gtk_grid_new(); gtk_container_add(GTK_CONTAINER(window), grid); button = gtk_button_new_with_label("Next Page"); g_signal_connect_swapped(button, "clicked", G_CALLBACK(NewCallback), grid); gtk_grid_attach(GTK_GRID(grid), button, 0, 1, 2, 1); button = gtk_button_new_with_label("Quit"); g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_widget_destroy), window); gtk_grid_attach(GTK_GRID(grid), button, 0, 2, 2, 1); gtk_widget_show_all(window); } int main(int argc, char **argv) { GtkApplication *app; int status; app = gtk_application_new("org.gtk.example", 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; }
关键修改点说明
- 提前获取窗口对象:在销毁旧
grid之前就调用gtk_widget_get_toplevel拿到窗口,确保操作的是有效对象。 - 添加窗口有效性检查:用
GTK_IS_WINDOW判断获取的顶层窗口是否有效,避免后续无效操作。 - 空指针防护:调用
strcmp前先检查titles是否为null,防止空指针引发崩溃。 - 修正容器挂载目标:所有按钮都挂载到新创建的
gridNew上,不再操作已销毁的旧grid。 - 信号连接的对象修正:把按钮的回调参数改为
gridNew,确保下一次切换时操作的是当前有效的网格容器。
内容的提问来源于stack exchange,提问作者Alexio
相关产品推荐
相关产品推荐

