C语言使用toupper()实现替换密码时密文最后一位被截断问题
问题原因排查
你遇到的丢字符问题本质是未定义行为触发的栈内存异常,和toupper本身没有直接关系,之前用tolower没出问题只是巧合,具体问题点如下:
- 第一个错误:
strncat的入参要求目标必须是合法的、以\0结尾的C字符串。你声明char ciphertext[strlen(plaintext)];后没有做初始化,数组内全是栈上的随机垃圾值,strncat会从第一个找到的\0位置开始拼接,位置完全随机。你修改为toupper后改变了栈内存的布局,随机\0的位置发生变化,就触发了丢字符的现象。 - 第二个错误:
ciphertext数组长度不足。如果要存储和明文等长的密文字符,还要额外预留1个字节存储字符串结束符\0,你的数组长度只和明文长度相同,空间不够。 - 冗余操作:完全不需要用
strncat拼接单个字符,直接按索引给ciphertext的对应位置赋值即可,性能更高也不会触发字符串操作的异常。
修复后的代码示例
#include <stdio.h> #include <string.h> #include <ctype.h> #include <cs50.h> // get_string、string类型为CS50库提供,需引入对应头文件 int main(int argc, string argv[]) { // 前置参数合法性校验,避免非法输入崩溃 if (argc != 2 || strlen(argv[1]) != 26) { printf("参数错误,请传入26位密钥\n"); return 1; } string plaintext = get_string("plaintext: "); int plain_len = strlen(plaintext); char key[26]; for (int i = 0; i < 26; i++) { key[i] = argv[1][i]; } // 数组长度+1,预留结束符位置 char ciphertext[plain_len + 1]; // 直接按索引赋值,无需使用strncat for (int i = 0; i < plain_len; i++) { if (islower(plaintext[i])) { int idx = plaintext[i] - 'a'; ciphertext[i] = tolower(key[idx]); } else if (isupper(plaintext[i])) { int idx = plaintext[i] - 'A'; ciphertext[i] = toupper(key[idx]); } else { ciphertext[i] = plaintext[i]; } } // 手动添加字符串结束符 ciphertext[plain_len] = '\0'; printf("ciphertext: %s\n", ciphertext); return 0; }
使用你给出的密钥YTNSHKVEFXRBAUQZCLWDMIPGJO、明文HELLO测试,可正常输出预期密文EHBBQ。
内容的提问来源于stack exchange,提问作者Soccerball123
相关产品推荐
相关产品推荐

