为何CS50替换密码实现中密文长度超出预期?
CS50替换密码问题:为何必须手动添加
'\0'才能正常输出? 问题描述
我正在解决CS50的替换密码问题,代码可运行但未优化。问题在于必须在末尾添加代码行cipher_text[strlen(plain_text)] = '\0';才能正常工作,否则密文长度会超出预期。请告诉我原因是什么?
以下是编写的代码:
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <string.h> int main(int argc, string argv[]) { // check if there's 1 argument, if there are > 1 or < 0 print error message and return 1 if (argc != 2) { printf("Error, type 1 command\n"); return 1; } string key = argv[1]; long lenght = strlen(key); // check if the key is valid (26 characters) or not, if not return 1 and print error if (lenght != 26) { printf("Key must contain 26 characters.\n"); return 1; } // iterate throughout the key, element after element whith the 1st for loop //check if contains letters or something else in the 1st if //make the key all lower in order to compare letter repetition in the else if //check for double letters (compare every letter (key[i]) with all the other letters) in the second for loop for (int i = 0 ; i < lenght ; i++) { if (isalpha(key[i]) == 0) //(key[i] < 65 || key[i] > 90) && (key[i] < 97 || key[i] > 122)) { printf("Key must contain only letters\n"); return 1; } else if (isupper(key[i])) { key[i] = tolower(key[i]); } for (int j = 0 ; j < lenght ; j++) { if (j != i && key[j] == key[i]) { printf("You can't repeat letters in key (you've repeated the letter %c)\n", key[j]); return 1; } } } //ask user for the text to cipher string plain_text = get_string("plaintext: "); char alphabet[] = "abcdefghijklmnopqrstuvwxyz"; char ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char cipher_text[strlen(plain_text)]; // iterate through every index in plain_text //if it is not alphabetical, add it to cipher text //otherwise, check if it is lower or upper, and add to cipher_text // for (int j = 0; j < strlen(plain_text) ; j++) { if (isalpha(plain_text[j]) == 0) { cipher_text[j] = plain_text[j]; } for (int x = 0 ; x < lenght ; x++) { if(islower(plain_text[j])) { if (plain_text[j] == alphabet[x]) { cipher_text[j] = key[x]; } } else if (isupper(plain_text[j])) { if (plain_text[j] == ALPHABET[x]) { cipher_text[j] = toupper(key[x]); } } } } cipher_text[strlen(plain_text)] = '\0'; printf("ciphertext: %s\n", cipher_text); return 0; }
原因解析
C语言中的字符串本质是字符数组,但必须以**空字符'\0'**作为结束标记——所有标准字符串处理函数(比如printf("%s")、strlen)都会从数组起始地址开始读取数据,直到碰到'\0'才停止。
你的代码中存在两个关键点:
char cipher_text[strlen(plain_text)];只分配了与明文字符数相等的内存空间,这个空间不会自动填充'\0'。- 如果不手动添加
cipher_text[strlen(plain_text)] = '\0';,printf输出密文时会持续读取内存中的数据,直到随机遇到某个'\0',最终导致输出内容长度超出预期(甚至出现乱码)。
额外注意:数组越界隐患
你当前的数组定义存在未定义行为风险:数组大小为strlen(plain_text),有效索引范围是0到strlen(plain_text)-1,但你赋值'\0'的位置是strlen(plain_text),属于越界访问内存。这次能运行只是环境巧合,正确的写法应该是给数组多分配一个字节来存放终止符:
char cipher_text[strlen(plain_text) + 1];
内容的提问来源于stack exchange,提问作者Andrea Visani
相关产品推荐
相关产品推荐

