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

使用sprintf和strcat转换哈希时的字符串异常问题求助

问题分析与解决方案

嘿,这个问题我太熟悉了!咱们来一步步拆解:

核心问题出在两个地方:

  1. 未初始化的hash数组缺少字符串终止符
  2. hash数组的空间不足以容纳字符串终止符,引发未定义行为

先解释第一个问题:你声明的unsigned char hash[8][32];是未初始化的数组,内存里的初始值是随机的。而strcat的工作逻辑是从目标字符串的末尾'\0'开始追加内容——如果目标字符串没有'\0',它会一直往内存深处找,直到碰巧遇到一个,这就会越界覆盖后面的hash[4]、hash[5]等空间。

循环内输出看似正常,是因为你刚追加完32个字符后,碰巧在当前hash[k]的末尾附近有个随机的'\0';但循环结束后,后续的循环已经把后面的空间都写满了数据,没有了那个碰巧的终止符,所以printf(hash[3])会一直输出直到遇到内存里某个遥远的'\0',就把后面所有哈希内容都带上了。

第二个隐藏问题:C语言的字符串必须以'\0'结尾,32个字符的哈希字符串需要33个字节的空间(32个字符+1个终止符)。你现在的hash[8][32]刚好只能放下32个字符,没有空间放'\0',这本身就是未定义行为,随时可能出问题。


修复方案(按推荐程度排序)

方案1:初始化数组+调整空间大小(最稳妥)

直接把hash数组初始化为全0,同时调整大小为33字节,确保每个子数组一开始就有'\0',且能容纳终止符:

// 全部初始化为0,每个子数组的第一个字节就是'\0',空间足够放32字符+终止符
unsigned char hash[8][33] = {0}; 
unsigned char hashResults[8][16]; 
unsigned char tmp[3]; // 改成3,因为%02x会输出2个字符+'\0',避免溢出

transformation("toto", 4, hashResults); 

for (int k = 0; k < 8; ++k) {
    for (int i = 0; i < 16; ++i) {
        sprintf(tmp,"%02x",hashResults[k][i]);
        strcat(hash[k],tmp);
    }
    printf("%zu \n%s\n", strlen(hash[k]), hash[k]); // 用%zu对应size_t类型的strlen返回值
} 
printf("Test : %s\n", hash[3]); 

方案2:直接定位写入,避免strcat(更高效)

其实完全不需要用strcat,我们可以直接计算每个字符的位置,用sprintf直接写入,既高效又能避免终止符问题:

unsigned char hash[8][33] = {0}; 
unsigned char hashResults[8][16]; 

transformation("toto", 4, hashResults); 

for (int k = 0; k < 8; ++k) {
    for (int i = 0; i < 16; ++i) {
        // 每个字节对应2个字符,偏移量是i*2
        sprintf(&hash[k][i*2], "%02x", hashResults[k][i]);
    }
    printf("%zu \n%s\n", strlen(hash[k]), hash[k]);
} 
printf("Test : %s\n", hash[3]); 

方案3:手动初始化每个子数组(应急修复)

如果不想改数组大小(不推荐,因为还是有空间隐患),可以在每次处理hash[k]前手动设置终止符:

unsigned char hash[8][32]; 
unsigned char hashResults[8][16]; 
unsigned char tmp[3];

transformation("toto", 4, hashResults); 

for (int k = 0; k < 8; ++k) {
    hash[k][0] = '\0'; // 手动把当前子数组初始化为空字符串
    for (int i = 0; i < 16; ++i) {
        sprintf(tmp,"%02x",hashResults[k][i]);
        strcat(hash[k],tmp);
    }
    // 注意:这里strlen返回32是因为刚好没有越界到终止符,但数组已经满了,属于未定义行为
    printf("%zu \n%s\n", strlen(hash[k]), hash[k]);
} 

额外提醒

  • 用%02x代替%2.2x,效果是一样的,但更符合C语言格式化字符串的常规写法
  • strlen的返回值是size_t类型,输出时应该用%zu而不是%d,避免类型不匹配的警告

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:27:54