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的值。请问:
- 这是什么原因?
- 原代码的字符串赋值方式是否合理?
- 将
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
相关产品推荐
相关产品推荐

