CS50第二周替换密码:为何要在ciphertext数组中存储'\0'?
CS50替换密码:字符串结束符
'\0'的作用问题 我在CS50第二周的替换密码问题中,使用以下代码实现功能:
#include <cs50.h> #include <stdio.h> #include <string.h> #include <ctype.h> bool check_char(string key); void cipher_function(string plaintext, string argv); int main(int argc, string argv[]) { if (argc != 2) { printf("Usage: ./substitution key\n"); return 1; } if (!check_char(argv[1])) { printf("Key must contain 26 unique characters.\n"); return 1; } // Get plaintext from user string plaintext = get_string("plaintext: "); // Function to generate and print ciphertext based on plaintext and key cipher_function(plaintext, argv[1]); } bool check_char(string key) { int length; length = strlen(key); if (length != 26) { return false; } for (int i = 0; i < length; i++) { key[i] = toupper(key[i]); } for (int i = 0; i < length; i++) { if (!isalpha(key[i])) { return false; } for (int j = i + 1; j < length; j++) { if (key[i] == key[j]) { return false; } } } return true; } void cipher_function(string plaintext, string argv) { int length = strlen(plaintext); int index; char ciphertext[length + 1]; for (int i = 0; i < length; i++) { if (islower(plaintext[i])) // If plaintext character is lowercase { index = plaintext[i] - 97; ciphertext[i] = argv[index]; if (isupper(ciphertext[i])) // If the ciphertext char for corresponding plaintext is upper, then convert to lower { ciphertext[i] += 32; } } else if (isupper(plaintext[i])) // If plaintext character is uppercase { index = plaintext[i] - 65; ciphertext[i] = argv[index]; if (islower(ciphertext[i])) { ciphertext[i] -= 32; // If the ciphertext char for corresponding plaintext is lower, then convert to upper } } else { ciphertext[i] = plaintext[i]; // To print out non-alpha characters in the plaintext like spaces, numbers etc. } } ciphertext[length] = '\0'; printf("ciphertext: %s\n", ciphertext); }
当我移除第92行的ciphertext[length] = '\0';,并将第65行的ciphertext数组长度设为与明文数组长度相同时,部分输入的输出末尾会出现带问号的奇怪符号。我了解到'\0'用于标记字符串结束,但不清楚这一规则如何作用于数组,特此问询原因。
问题解释
C语言中字符串的本质
C语言里没有原生的"字符串"类型,我们说的字符串其实是以'\0'(ASCII值为0的空字符)结尾的字符数组。所有处理字符串的标准函数(比如printf("%s")、strlen)都依赖这个结束符来判断字符串的边界:它们会从数组的起始地址开始逐个读取字符,直到碰到'\0'才停止。
代码出问题的具体原因
- 当你把
ciphertext的长度设为和明文长度length一致时,数组的所有位置(下标0到length-1)都被明文转换后的字符填满了,没有多余空间存放'\0'。 - 如果你不手动添加
'\0',数组末尾之后的内存区域是未初始化的垃圾数据——里面可能是任意随机值,几乎不可能刚好是'\0'。 - 当
printf打印这个数组时,它会越过数组边界继续读取内存中的垃圾数据,直到某个位置碰巧出现'\0'才停下。那些末尾的问号或乱码,就是这些未定义的垃圾数据被解析成字符后的结果。
原代码正常的原因
原代码定义char ciphertext[length + 1];,多出来的1个元素位置就是专门留给'\0'的。手动添加ciphertext[length] = '\0';后,printf读到这个位置就会停止,不会越界读取垃圾数据。
内容的提问来源于stack exchange,提问作者King Brain
相关产品推荐
相关产品推荐

