You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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;
}

关键修改点说明

  1. 提前获取窗口对象:在销毁旧grid之前就调用gtk_widget_get_toplevel拿到窗口,确保操作的是有效对象。
  2. 添加窗口有效性检查:用GTK_IS_WINDOW判断获取的顶层窗口是否有效,避免后续无效操作。
  3. 空指针防护:调用strcmp前先检查titles是否为null,防止空指针引发崩溃。
  4. 修正容器挂载目标:所有按钮都挂载到新创建的gridNew上,不再操作已销毁的旧grid。
  5. 信号连接的对象修正:把按钮的回调参数改为gridNew,确保下一次切换时操作的是当前有效的网格容器。

内容的提问来源于stack exchange,提问作者Alexio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 22:55:18