使用strlen处理argv[1]时触发Segmentation Fault的问题求助
CS50 Substitution题调试问题:段错误与无限循环
正在学习CS50(首次接触C语言),完成Substitution题目时遇到问题:运行代码陷入无限循环,调试发现调用strlen获取argv[1]长度时触发段错误,调试显示key的值为0x0,怀疑argv[1]未以NULL结尾,但无法确定。
问题代码
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <string.h> int check(string str); int main(int argc, string argv[]) { if(argc < 1 || argc > 2) { printf("Usage: ./substitution key"); return 1; } string key = argv[1]; if(check(key) == 1) { return 1; } string plaintext = get_string("plaintext:"); int lenght = strlen(plaintext); char ciphertext[lenght + 1]; for(int i = 0; i <= lenght; i++) { if(islower(plaintext[i])) { plaintext[i] -= 97; ciphertext[i] = key[(int)plaintext[i]]; if(isupper(ciphertext[i])) { ciphertext[i] = tolower(ciphertext[i]); } } if(isupper(plaintext[i])) { plaintext[i] -= 65; ciphertext[i] = key[(int)plaintext[i]]; if(islower(ciphertext[i])) { ciphertext[i] = toupper(ciphertext[i]); } } } printf("ciphertext:%s", ciphertext); } int check(string str) { //检查字符数量、是否重复或包含数字 char alphabet[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; int count[26] = { 0 }; if(strlen(str) != 26) { printf("Key must contain 26 characters."); return 1; } for(int i = 0; i < 25; i++) { if(isalpha(str[i]) == 0) { return 1; } str[i] = (char)tolower(str[i]); for(int j = 0; j < 25; j++) { if(str[i] == alphabet[j]) { count[j] += 1; } } } for(int i = 0; i < 25; ) { if(count[i] != 1) { return 1; } } return 0; }
调试错误信息
程序收到信号SIGSEGV,段错误。__strlen_evex () 在 ../sysdeps/x86_64/multiarch/strlen-evex.S:77
问题分析与修复
1. 段错误的直接原因:参数判断错误
原代码中if(argc < 1 || argc > 2)的判断逻辑错误:C语言中argc最小值为1(程序自身路径),当用户未输入密钥时,argc=1,此时argv[1]为NULL,调用strlen(NULL)必然触发段错误。
修复:将参数判断改为:
if(argc != 2) { printf("Usage: ./substitution key\n"); return 1; }
2. check函数的循环错误
- 遍历密钥的循环
for(int i = 0; i < 25; i++)仅遍历前25个字符,遗漏第26个,应改为i < 26; - 内部匹配字母表的循环
for(int j = 0; j < 25; j++)同理,改为j < 26; - 最后检查
count数组的循环for(int i = 0; i < 25; )没有递增i,导致无限循环,且边界错误,应改为for(int i = 0; i < 26; i++)。
3. 加密逻辑的问题
- 循环条件
i <= lenght会越界访问字符串末尾的NULL字符,应改为i < lenght; - 修改了原
plaintext的内容(plaintext[i] -= 97),破坏输入数据,应使用临时变量存储索引; - 未处理非字母字符,导致
ciphertext对应位置未赋值,出现乱码; ciphertext未添加终止NULL字符,printf输出时会读取内存垃圾数据。
修正后的完整代码
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <string.h> int check(string str); int main(int argc, string argv[]) { if(argc != 2) { printf("Usage: ./substitution key\n"); return 1; } string key = argv[1]; if(check(key) == 1) { return 1; } string plaintext = get_string("plaintext: "); int length = strlen(plaintext); char ciphertext[length + 1]; for(int i = 0; i < length; i++) { if(islower(plaintext[i])) { int idx = plaintext[i] - 'a'; ciphertext[i] = tolower(key[idx]); } else if(isupper(plaintext[i])) { int idx = plaintext[i] - 'A'; ciphertext[i] = toupper(key[idx]); } else { // 非字母字符直接复制 ciphertext[i] = plaintext[i]; } } // 添加字符串终止符 ciphertext[length] = '\0'; printf("ciphertext: %s\n", ciphertext); return 0; } int check(string str) { int count[26] = {0}; if(strlen(str) != 26) { printf("Key must contain 26 characters.\n"); return 1; } for(int i = 0; i < 26; i++) { if(!isalpha(str[i])) { printf("Key must contain only alphabetic characters.\n"); return 1; } char lower_char = tolower(str[i]); int idx = lower_char - 'a'; // 检查字符是否重复 if(count[idx] != 0) { printf("Key must contain each letter exactly once.\n"); return 1; } count[idx]++; } return 0; }
内容的提问来源于stack exchange,提问作者gondola
相关产品推荐
相关产品推荐

