代码之家  ›  专栏  ›  技术社区  ›  Hanlon

迭代器不属于其指定的文本缓冲区

  •  1
  • Hanlon  · 技术社区  · 6 年前

    这是赤裸裸的 save_as()

    gint save_as(GtkWidget *parent, struct buffers B)
    {
        GtkWidget *file_chooser = gtk_file_chooser_dialog_new("Save As", GTK_WINDOW(parent), GTK_FILE_CHOOSER_ACTION_SAVE, "Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_OK, NULL);
        gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser), "Untitled");
    
        gint response = gtk_dialog_run(GTK_DIALOG(file_chooser));
        switch(response)
        {
            case GTK_RESPONSE_OK:
                    GFile *file = g_file_new_for_path(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)));
                    GtkTextIter *start;
                    gtk_text_buffer_get_start(B.buffer0, &start);
                    GtkTextIter *end;
                    gtk_text_buffer_get_end(B.buffer0, &end);
                    // program abnormally terminates on the following line
                    gchar *contents = gtk_text_buffer_get_text(B.buffer0, &start, &end, FALSE);
                    g_file_replace_contents(file, contents, strlen(contents), NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, NULL);
                    g_free(contents);
                    gtk_widget_destroy(file_chooser);
                    return GTK_RESPONSE_OK;
                    break;
            case GTK_RESPONSE_CANCEL:
                    gtk_widget_destroy(file_chooser);
                    return GTK_RESPONSE_CANCEL;
        }
        // user pressed X
        gtk_widget_destroy(file_chooser);
        return GTK_RESPONSE_CANCEL;
    }
    

    这几乎是我们诊断和解决问题所需要的全部。

    这是我尝试点击时得到的完整信息 保存

    (test:4478): Gtk-WARNING **: 11:56:20.184: Invalid text buffer iterator: either the iterator is uninitialized, or the characters/pixbufs/widgets in the buffer have been modified since the iterator was created.
    You must use marks, character numbers, or line numbers to preserve a position across buffer modifications.
    You can apply tags and insert marks without invalidating your iterators, but any mutation that affects 'indexable' buffer contents (contents that can be referred to by character offset) will invalidate all outstanding iterators
    
    
    (test:4478): Gtk-CRITICAL **: 11:56:20.184: gtk_text_buffer_get_text: assertion 'gtk_text_iter_get_buffer (start) == buffer' failed
    Segmentation fault (core dumped)
    

    出于某种原因,迭代器 start end 不属于 B.buffer0 GTK+3 documentation ,我也跟着回答 this question 作为向导。

    为什么会发生这种情况,如何解决?


    gtk_text_buffer_get_start_iter(B.buffer0, &start); gtk_text_buffer_get_start_iter(B.buffer0, start);

    gtk_text_buffer_get_start_iter(B.buffer0, &end); gtk_text_buffer_get_start_iter(B.buffer0, end);

    gchar *contents = gtk_text_buffer_get_text(B.buffer0, &start, &end, FALSE); gchar *contents = gtk_text_buffer_get_text(B.buffer0, start, end, FALSE);

    唯一的错误是:

    Segmentation fault (core dumped)
    

    这也应该是根据 documentation .

    另外,我试着替换 contents = gtk_text_buffer_get_text(B.buffer0, start, end, FALSE); 具有 contents = gtk_text_iter_get_text(start, end);

    我还注意到,在应用这些更改之后,在编译过程中会收到两个警告:

    src/save.c:96:5: warning: ‘start’ may be used uninitialized in this function [-Wmaybe-uninitialized]
         gtk_text_buffer_get_start_iter(B.buffer0, start);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    src/save.c:98:5: warning: ‘end’ may be used uninitialized in this function [-Wmaybe-uninitialized]
         gtk_text_buffer_get_end_iter(B.buffer0, end);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    这显然意味着 gtk_text_buffer_get_start/end_iter() 开始 结束 具有 ,但为什么?上面说 结束


    结构缓冲区的定义在一个名为 buffer.h . 这里是(不是整个文件,只是结构定义):
    struct buffers
    {
        GtkTextBuffer *buffer0;
        GtkTextBuffer *buffer1;
        GtkTextBuffer *buffer2;
    };
    

    我使用的实例是:

    struct buffers Buffer;
    

    包含在每个使用 Buffer . 当然,为了同样的目的(全球性),它是被宣布的 extern struct buffers Buffer; 在与定义它的源文件关联的头文件中。

    这个缓冲区被传递给一个函数 另存为()

    gint response = save_as(main_window, Buffer);
    

    如果您想知道为什么我不使用全局变量而不是将其作为参数传递,那是因为我可以传递任何类型的变量 struct buffers save_file() 结构缓冲区 变量。


    GtkTextIter *start = NULL;
    GtkTextIter *end = NULL;
    

    文件->另存为 然后 ,程序退出,我收到消息:

    (test:4081): Gtk-CRITICAL **: 19:48:29.843: gtk_text_buffer_get_start_iter: assertion 'iter != NULL' failed
    
    (test:4081): Gtk-CRITICAL **: 19:48:29.844: gtk_text_buffer_get_end_iter: assertion 'iter != NULL' failed
    
    (test:4081): Gtk-CRITICAL **: 19:48:29.844: gtk_text_buffer_get_text: assertion 'start != NULL' failed
    

    开始 结束 迭代器是 NULL 开始 结束 分别指向文件开头和结尾的迭代器?因此,为什么在这之前设置什么迭代器很重要呢?

    1 回复  |  直到 6 年前
        1
  •  0
  •   Hanlon    6 年前

    终于解决了。看起来是这样的 GtkTextIter 与大多数GTK类型略有不同。

    gint save_as(GtkWidget *parent, struct buffers B)
    {
        GtkWidget *file_chooser = gtk_file_chooser_dialog_new("Save As", GTK_WINDOW(parent), GTK_FILE_CHOOSER_ACTION_SAVE, "Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_OK, NULL);
        gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser), "Untitled");
    
        gint response = gtk_dialog_run(GTK_DIALOG(file_chooser));
        switch(response)
        {
            case GTK_RESPONSE_OK:
                    GFile *file = g_file_new_for_path(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)));
                    GtkTextIter start;
                    gtk_text_buffer_get_start(B.buffer0, &start);
                    GtkTextIter end;
                    gtk_text_buffer_get_end(B.buffer0, &end);
                    // program abnormally terminates on the following line
                    gchar *contents = gtk_text_buffer_get_text(B.buffer0, &start, &end, FALSE);
                    g_file_replace_contents(file, contents, strlen(contents), NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, NULL);
                    g_free(contents);
                    gtk_widget_destroy(file_chooser);
                    return GTK_RESPONSE_OK;
                    break;
            case GTK_RESPONSE_CANCEL:
                    gtk_widget_destroy(file_chooser);
                    return GTK_RESPONSE_CANCEL;
        }
        // user pressed X
        gtk_widget_destroy(file_chooser);
        return GTK_RESPONSE_CANCEL;
    }
    

    如您所见,此代码与我的问题代码的唯一区别在于以下两行:

    GtkTextIter *start;
    GtkTextIter *end;
    

    赖特

    GtkTextIter start;
    GtkTextIter end;
    

    大多数GTK类型都希望您使它们成为指针,但这一个是个例外。