C语言实现凯撒密码调用encrypt函数触发Segmentation Fault报错
问题描述
开发凯撒密码程序时,使用密钥1、明文输入hello.运行程序,触发Segmentation fault (core dumped)报错。已知该错误为程序访问非法内存位置导致,且触发于encrypt函数调用流程中,无法定位具体出错点。
调试过程中捕获的报错状态截图
原始代码
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> bool isValidKey(string); string encrypt(string, int); string c; int main(int argc, string argv[]) { if (argc != 2 || isValidKey(argv[1]) == 0) { printf("Useage: ./caesar key\n"); return 0; } string p = get_string("plaintext: "); c = encrypt(p, atoi(argv[1])); printf("%s", c); return 0; } bool isValidKey(string key) { for (int i = 0; i < strlen(key); i++) { if (isdigit(key[i]) == 0) { return false; } } return true; } string encrypt(string plain, int k) { for (int i = 0; i < strlen(plain); i++) { if (isalpha(plain[i]) != 0) { if (islower(plain[i]) != 0) { c[i] = ((plain[i] - 97 + k) % 26) + 97; } else { c[i] = ((plain[i] - 65 + k) % 26) + 65; } } } return c; }
故障原因
- 段错误直接诱因:全局变量
c是char*类型指针,声明后未分配任何有效可读写内存,属于野指针。在encrypt函数中直接对c[i]执行赋值操作,是向非法内存地址写入数据,必然触发段错误。 - 逻辑缺陷:加密流程未处理非字母字符,输入的
.、标点、空格等内容不会被写入密文,即使修复内存问题,也会因为密文字符串缺少结束符、内容不完整导致输出乱码或越界读取。 - 细节问题:参数校验失败时返回0不符合POSIX命令行规范,命令执行出错应返回非0退出码;提示信息存在拼写错误(
Useage应为Usage)。
修复后代码
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> bool isValidKey(string); string encrypt(string, int); int main(int argc, string argv[]) { if (argc != 2 || isValidKey(argv[1]) == 0) { printf("Usage: ./caesar key\n"); return 1; } string p = get_string("plaintext: "); string c = encrypt(p, atoi(argv[1])); printf("ciphertext: %s\n", c); free(c); return 0; } bool isValidKey(string key) { for (int i = 0, len = strlen(key); i < len; i++) { if (!isdigit(key[i])) { return false; } } return true; } string encrypt(string plain, int k) { int len = strlen(plain); // 申请与明文长度匹配的内存,额外1字节存字符串结束符 string cipher = malloc(len + 1); for (int i = 0; i < len; i++) { if (isalpha(plain[i])) { if (islower(plain[i])) { cipher[i] = ((plain[i] - 'a' + k) % 26) + 'a'; } else { cipher[i] = ((plain[i] - 'A' + k) % 26) + 'A'; } } else { // 非字母字符直接原样保留 cipher[i] = plain[i]; } } // 补字符串结束标记 cipher[len] = '\0'; return cipher; }
修复说明
- 移除无意义的全局密文指针,在
encrypt函数内通过malloc申请对应大小的堆内存,从根源解决野指针问题。 - 遍历明文时对非字母字符做原样复制,遍历结束后强制在密文末尾写入
\0结束符,保证字符串格式合法。 - 优化循环逻辑,提前计算字符串长度,避免循环每次执行都调用
strlen降低效率。 - 修正拼写错误与退出码问题,使用
'a'/'A'字符字面量替换硬编码的ASCII值,提升代码可读性。 - 密文使用完成后调用
free释放申请的堆内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

