C语言中两次调用sprintf后m1_hex意外为空的问题排查
问题:字符串转十六进制后未修改的数组值莫名为空
我写了一段C语言代码将字符串转为十六进制表示,首次调用turnCharToHexString处理m1后,m1_hex值正常;但第二次调用该函数处理m2后,未被修改的m1_hex却变成了空字符串。代码及运行输出如下:
#include <stdio.h> #include <string.h> #include <openssl/bn.h> typedef unsigned char text; typedef const size_t slen; void turnCharToHexString(text *pt, text *ht, slen size){ for(size_t i = 0, j = 0; i < size; ++i, j+=2){ sprintf(ht + j, "%02x", pt[i] & 0xff); } printf("The msg %s in hex is %s\n", pt, ht); } int main(){ text* m1 = "I owe you $2000."; text* m2 = "I owe you $3000."; slen sm1 = strlen(m1); text m1_hex[sm1 * 2]; text m2_hex[sm1 * 2]; turnCharToHexString(m1, m1_hex, sm1); printf("what is m1_hex (1): '%s'\n", m1_hex); turnCharToHexString(m2, m2_hex, sm1); printf("what is m1_hex (2): '%s'\n", m1_hex); printf("what is m2_hex (1): '%s'\n", m2_hex); exit(EXIT_SUCCESS); }
运行输出:
The msg I owe you $2000. in hex is 49206f776520796f752024323030302e what is m1_hex (1): '49206f776520796f752024323030302e' The msg I owe you $3000. in hex is 49206f776520796f752024333030302e what is m1_hex (2): '' //disappear what is m2_hex (1): '49206f776520796f752024333030302e'
原因分析
核心问题是未给十六进制字符串数组添加字符串结束符\0,属于C语言中字符串未正确终止导致的未定义行为:
- 你定义的
m1_hex和m2_hex大小为sm1 * 2,刚好能放下所有十六进制字符,但没有额外空间存储\0。 - 首次调用函数后,
m1_hex内存区域的后续栈空间刚好存在一个随机的\0,所以printf能正常识别并输出完整字符串。 - 第二次调用函数处理
m2_hex时,栈上的变量布局导致m2_hex的写入操作覆盖了m1_hex末尾后的临时\0,甚至可能直接修改了m1_hex的内存内容(栈变量通常相邻存储)。此时m1_hex失去了有效的终止符,printf读取时会在内存中寻找第一个\0,而恰好m1_hex起始位置附近被覆盖为0,最终输出空字符串。
修复方案
- 修改数组定义,多预留1个字节用于存储结束符:
text m1_hex[sm1 * 2 + 1]; text m2_hex[sm1 * 2 + 1];
- 在
turnCharToHexString函数的循环结束后,手动添加字符串结束符:
void turnCharToHexString(text *pt, text *ht, slen size){ for(size_t i = 0, j = 0; i < size; ++i, j+=2){ sprintf(ht + j, "%02x", pt[i] & 0xff); } // 添加结束符 ht[size * 2] = '\0'; printf("The msg %s in hex is %s\n", pt, ht); }
内容的提问来源于stack exchange,提问作者BiotieriaA
相关产品推荐
相关产品推荐

