指针与字符串问题:Diceware密码生成器输出乱码求助
Diceware密码短语生成器乱码问题修复
核心错误分析
- 字符串赋值错误:
*word = wordline;是把指针的内存地址赋值给单个char变量,完全不是字符串复制操作,这是乱码的直接原因。 - 匹配逻辑错误:原代码用
strstr(line, combo)判断匹配,只要行中包含目标数字串就会触发,但词表中目标数字是行首固定的5位,这种判断会误匹配单词中包含相同数字序列的行。 - 未终止循环:找到匹配行后未跳出循环,会继续读取后续行,可能覆盖正确结果。
- 缺少成功返回值:
get_word函数成功执行后未返回0,会导致main函数误判操作失败。 - 冗余指针声明:
char *ptr = &word1;完全多余,数组名本身就是指向首元素的指针,直接传递word1即可。
修复后的完整代码
#include <stdio.h> #include <string.h> #include <sodium.h> void roll_dice(char *combo) { uint32_t dice1, dice2, dice3, dice4, dice5; uint32_t upper = 6; dice1 = randombytes_uniform(upper) + 1; dice2 = randombytes_uniform(upper) + 1; dice3 = randombytes_uniform(upper) + 1; dice4 = randombytes_uniform(upper) + 1; dice5 = randombytes_uniform(upper) + 1; sprintf(combo, "%d%d%d%d%d", dice1, dice2, dice3, dice4, dice5); } int get_word(char *combo, char *word) { FILE *stream; char line[20]; char *tab_pos; stream = fopen("/usr/local/etc/passwiz/eff_large_wordlist.txt", "r"); if (NULL == stream) { printf("Failed to open wordlist\n"); return -1; } while (fgets(line, sizeof(line), stream)) { // 精确匹配行首的5位数字 if (strncmp(line, combo, 5) == 0) { // 定位制表符,提取后续单词 tab_pos = strchr(line, '\t'); if (tab_pos != NULL) { // 去除行尾换行符并复制单词到目标缓冲区 strtok(tab_pos + 1, "\n"); strcpy(word, tab_pos + 1); fclose(stream); return 0; // 找到结果后立即终止循环并返回 } } } // 未找到匹配单词的情况 printf("No matching word found for combo: %s\n", combo); fclose(stream); return -1; } int main(void) { if (sodium_init() < 0) { return 1; } char combo[6]; roll_dice(combo); printf("Dice numbers: %s\n", combo); char word1[20]; if (get_word(combo, word1) < 0) { return 1; } printf("First word: %s\n", word1); // TODO: 获取6个单词 return 0; }
关键修复说明
- 正确的字符串复制:用
strcpy(word, tab_pos + 1)替代错误的指针赋值,将提取到的单词复制到传入的缓冲区中。 - 精准匹配逻辑:使用
strncmp(line, combo, 5)确保只匹配行首的5位数字,避免误匹配。 - 高效终止流程:找到匹配行后立即关闭文件并返回,避免无效的后续读取操作。
- 完善的单词提取:通过
strchr定位制表符,跳过分隔符后提取单词,并用strtok去除行尾的换行符,保证输出格式正确。 - 简化指针传递:移除冗余的指针声明,直接传递数组名,符合C语言的数组使用规范。
内容的提问来源于stack exchange,提问作者Douglas Silva
相关产品推荐
相关产品推荐

