C语言加密程序循环提前终止及Segmentation fault问题求助
解决替换密码程序中的段错误与循环问题
核心问题分析
- 空数组越界访问:你定义的
int cypher[] = {}是长度为0的空数组,尝试给cypher[i]赋值时会访问未分配的内存区域,这是触发段错误的直接原因。C语言中空数组没有预留存储空间,写入操作属于非法内存访问。 - 错误的循环条件:转换大小写的循环使用
i < plain[i]作为终止条件完全不符合逻辑——plain[i]是字符的ASCII值(比如'H'对应72),这会导致循环要么提前终止,要么遍历远超字符串长度的范围,破坏内存。 - 缺失参数合法性检查:程序未验证用户是否传入密钥参数(即
argc == 2),如果直接运行程序不输入密钥,argv[1]为NULL,调用strlen(argv[1])会直接崩溃。 - 大小写处理逻辑混淆:注释标注要将key转为大写,但实际代码修改的是plain字符串,且直接修改原字符串可能引发问题,同时丢失了原字符的大小写信息。
修正后的代码
#include <cs50.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> int main(int argc, string argv[]) { // 检查是否传入密钥参数,且密钥长度为26 if (argc != 2 || strlen(argv[1]) != 26) { printf("Usage: ./substitution key\n"); printf("Key must contain 26 characters.\n"); return 1; } string key = argv[1]; // 验证密钥是否全为字母 for (int i = 0; i < 26; i++) { if (!isalpha(key[i])) { printf("Key must contain only alphabetic characters.\n"); return 1; } // 将密钥统一转为大写,方便后续处理 key[i] = toupper(key[i]); } // 获取明文 string plain = get_string("plaintext: "); // 为密文分配内存,长度为明文长度+1(存储结束符'\0') char *cypher = malloc(strlen(plain) + 1); if (cypher == NULL) { printf("Memory allocation failed.\n"); return 1; } // 加密逻辑 for (int i = 0; i < strlen(plain); i++) { char c = plain[i]; if (isupper(c)) { // 大写字母:计算索引(A=0),从密钥取对应字符,保持大写 int idx = c - 'A'; cypher[i] = key[idx]; } else if (islower(c)) { // 小写字母:计算索引,从密钥取对应字符后转小写 int idx = c - 'a'; cypher[i] = tolower(key[idx]); } else { // 非字母字符直接保留 cypher[i] = c; } } // 添加字符串结束符 cypher[strlen(plain)] = '\0'; // 输出密文 printf("cyphertext: %s\n", cypher); // 释放分配的内存 free(cypher); return 0; }
关键修正说明
- 内存分配:使用
malloc为密文分配足够内存,长度为明文长度加1(用于存储字符串结束符'\0'),避免越界访问;使用完后用free释放内存,防止内存泄漏。 - 正确的循环条件:遍历字符串时使用
i < strlen(plain),确保遍历每个字符直到字符串结束。 - 完善的参数检查:先验证
argc == 2,再检查密钥长度,同时验证密钥是否全为字母,提升程序健壮性。 - 保留大小写信息:加密时根据原字符的大小写,将密钥中的对应字符转换为相同大小写,符合常规加密需求。
- 处理非字母字符:直接保留明文里的非字母字符(如空格、标点),提升程序实用性。
内容的提问来源于stack exchange,提问作者Nick Suess
相关产品推荐
相关产品推荐

