CS50 习题集2代码运行触发Segmentation fault (core dumped)求助
凯撒密码代码段错误分析与修复
问题描述
编写的凯撒密码代码编译无报错,但运行时触发Segmentation fault (core dumped),原代码如下:
#include <cs50.h> #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, string argv[]) { int k=atoi(argv[1]); if (argc!=2) { printf("Usage: ./caesar key\n"); return 1; } else if (argv[1]<0) { printf("Usage: ./caesar key\n"); return 2; } else if (argv[1]== NULL) { printf("Usage: ./caesar key\n"); return 3; } string plaintext= get_string("plaintext: "); printf("ciphertext: "); for(int i=0; i<strlen(plaintext); i++) { if(plaintext[i]>='a' && plaintext[i]<='z') { printf("%c", ((plaintext[i]-97+k)%26)+97); } else if(plaintext[i]>='A' && plaintext[i]<='Z') { printf("%c", ((plaintext[i]-65+k)%26)+65); } } printf("\n"); }
错误点分析
- 参数访问顺序错误:代码一开始就执行
int k=atoi(argv[1]);,但此时还没校验argc是否等于2。如果用户运行程序时没有传入参数(即argc=1),argv[1]是不存在的野指针,访问它直接触发段错误。 - 无效的负数判断:
argv[1]<0是把字符串指针和整数0比较,判断的是指针地址是否小于0,完全不是判断密钥数值是否为负,逻辑错误。 - 多余的空指针判断:当
argc==2时,argv[1]必然指向传入的参数字符串,不可能为NULL,这个判断毫无意义。 - 非字母字符未处理:循环只处理大小写字母,空格、数字、符号等字符会被直接忽略,导致输出缺失内容(虽不触发段错误,但功能不完整)。
修正后的代码
#include <cs50.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> // 用于isalpha、islower、isupper函数,让判断更清晰 int main(int argc, string argv[]) { // 先校验参数数量 if (argc != 2) { printf("Usage: ./caesar key\n"); return 1; } // 转换密钥并校验是否为正整数 int k = atoi(argv[1]); if (k <= 0) { printf("Usage: ./caesar key\n"); return 2; } string plaintext = get_string("plaintext: "); printf("ciphertext: "); for (int i = 0; i < strlen(plaintext); i++) { char c = plaintext[i]; if (islower(c)) { printf("%c", ((c - 'a' + k) % 26) + 'a'); } else if (isupper(c)) { printf("%c", ((c - 'A' + k) % 26) + 'A'); } else { // 非字母字符直接输出 printf("%c", c); } } printf("\n"); return 0; }
修正说明
- 调整参数校验顺序:先判断
argc是否为2,再访问argv[1]转换密钥,避免野指针访问。 - 用转换后的
k判断是否为正整数,替代无效的指针地址比较。 - 移除多余的
argv[1]==NULL判断。 - 使用
ctype.h中的islower、isupper函数简化字符类型判断,同时处理非字母字符,保证输出完整。 - 用字符常量
'a'、'A'替代ASCII码值97、65,提升代码可读性。
内容的提问来源于stack exchange,提问作者fafottos
相关产品推荐
相关产品推荐

