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

GTK应用中char*值被莫名破坏的原因及g_strdup修复原理

问题分析与解答

问题代码

#include <stdio.h>

struct TStruct {
    char *string;
};

void func(struct TStruct *tstruct) {
    char chara[8];
    sprintf(chara, "%.*s", 4, "testing");
    tstruct->string = chara;
}

int  main() {
    struct TStruct tstruct;
    tstruct.string = NULL;
    func(&tstruct);
    printf("%s", tstruct.string);
    return 0;
}

问题描述

该代码片段单独运行正常,但在GTK应用中,在该片段之后创建任何GTK对象都会破坏tstruct.string的值。请问:

  1. 这是什么原因?
  2. 原代码的字符串赋值方式是否合理?
  3. 将tstruct->string = chara修改为tstruct->string = g_strdup(chara)后问题得以解决,该修复的原理是什么?

解答

1. 问题原因

chara是func函数内的局部栈数组,内存分配在栈帧上。当func执行完毕返回时,对应的栈帧会被销毁,这块内存会被标记为可复用状态。

  • 单独运行时,printf在func返回后立即执行,栈内存还未被新操作覆盖,tstruct.string指向的旧栈内存内容仍能被读取,因此看起来运行正常。
  • 在GTK应用中,创建GTK对象会触发大量函数调用,这些调用会重新使用栈空间,直接覆盖了chara原本所在的内存区域,导致tstruct.string指向的内容被破坏。

2. 原代码赋值方式的合理性

完全不合理。这种赋值是把局部栈变量的地址赋值给结构体指针,函数返回后该地址对应的内存已无效,属于野指针。后续对tstruct.string的访问是未定义行为,程序表现全靠内存使用的巧合,随时可能崩溃或出现随机错误。

3. 修复原理

g_strdup是GLib库提供的字符串复制函数,核心行为如下:

  • 在堆内存上分配足够容纳目标字符串(含终止符\0)的空间;
  • 将输入字符串的内容完整复制到这块堆内存中;
  • 返回堆内存的起始地址。

堆内存的生命周期不受函数栈帧影响,不会随函数返回而销毁,只有主动调用g_free时才会被回收。因此tstruct.string指向的是有效的堆内存,后续GTK操作栈内存的行为不会干扰到它,也就不会出现值被破坏的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 15:33:41