所以我尝试调试它,我知道它与 argv 有关,但我不确定what 发生了什么。
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
string replace();
int main(int argc, string argv[])
{
if (strlen(argv[2]) != 26)
{
printf("The cipher must be 26 characters\n");
return 0;
}
明确地说,调试说问题发生在说
的那一行if (strlen(argv[2]) !=26
给出的问题是“segmentation fault(core dumped)。只有在我执行程序后输入文本时才会出现这种情况。
所以后面的文字在这里:
string plaintext = get_string("Plaintext: ");
string word = plaintext;
string result = replace(word);
}
string replace(string word, int argc, string argv[])
{
string coded = NULL;
for(int i = 0; i < strlen(word); i++)
{
int c = tolower(word[i]);
int n = c - 97;
if (n < 0 || n > 26)
{
n = c;
}
coded[i] = argv[2][n];
}
printf("coded: %s", coded);
return 0;
}
我基本上想使用在命令行参数中输入的密码将明文字符串转换为代码。我知道我有一些错误(比如标点符号不会转换),因为我是新手,但我相信我可以自己解决这些问题。我只是想弄清楚为什么它会给我这个特定的错误。
在评论部分,你说你是这样调用你的程序的:
./substitution YTNSHKVEFXRBAUQZCLWDMIPGJO
这意味着
argc
将具有值 2
argv[0]
将引用(“点”)字符串 "./substitution"
argv[1]
将引用(“点”)字符串 "YTNSHKVEFXRBAUQZCLWDMIPGJO"
argv[2]
将具有值 NULL
(即它不会指向任何有效的字符串)因此,这条线
if (strlen(argv[2]) != 26)
未引用有效字符串,当您在该无效引用上使用
strlen
时可能会导致分段错误。这似乎正是这里发生的事情。
出于这个原因,你应该使用
argv[1]
而不是argv[2]
。
通常,在访问数组
argc
(“参数向量”)之前始终检查argv
(“参数计数”)的值是个好主意。否则,如果用户死后没有传递任何命令行参数(程序名称除外)并且您尝试读取argv[1]
,您将使用无效引用并且可能导致分段错误。
所以我建议你换台词
int main(int argc, string argv[])
{
if (strlen(argv[2]) != 26)
{
printf("The cipher must be 26 characters\n");
return 0;
}
以下内容:
int main(int argc, string argv[])
{
if ( argc < 2 )
{
printf( "You must specify at least one argument!\n" );
exit( EXIT_FAILURE );
}
if ( strlen(argv[1]) != 26 )
{
printf( "The cipher must be 26 characters\n" );
exit( EXIT_FAILURE );
}
请注意,您必须
#include <stdlib.h>
才能使用功能exit
。使用 exit
而不是 return
的优点是它可以用于在函数 main
之外立即终止您的程序。与 exit
相比,return
语句只能在函数 main
内部使用时执行此操作,因此通常最好使用 exit
来保持一致性,即使在这种情况下使用 return
就足够了。否则,如果您出于某种原因决定将代码移动到另一个函数中,它将停止工作。
代码有几个问题:
程序假定总会有至少两个参数传递给程序,但事实并非如此。 argc 参数指定命令行参数的数量,因此它可以是 1 个或更多。这意味着在不检查 argv[2] 是否存在的情况下访问它是一个可能导致分段错误的潜在问题。
替换函数只定义了一个参数(string replace();),但它应该有两个参数:string replace(string word, int argc, string argv[]).
replace函数中,编码字符串被初始化为NULL。这意味着程序正在尝试写入未初始化的指针,这是分段错误的另一个潜在原因。
替换函数返回一个int,但它应该返回一个字符串。
要解决这些问题,您可以进行以下更改:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
string replace(string word, int argc, string argv[]);
int main(int argc, string argv[])
{
if (argc != 2 || strlen(argv[1]) != 26)
{
printf("Usage: ./program_name key (must be 26 characters)\n");
return 1;
}
string plaintext = get_string("Plaintext: ");
string result = replace(plaintext, argc, argv);
printf("coded: %s\n", result);
}
string replace(string word, int argc, string argv[])
{
string coded = malloc(strlen(word) + 1);
for(int i = 0; i < strlen(word); i++)
{
int c = tolower(word[i]);
int n = c - 97;
if (n < 0 || n > 25)
{
coded[i] = c;
}
else
{
coded[i] = argv[1][n];
}
}
coded[strlen(word)] = '\0';
return coded;
}
这里有什么变化:
main 函数现在检查是否只有一个参数(键),以及该键是否有 26 个字符长。如果不是,它会打印一条用法消息并返回一个错误代码。
替换函数现在有两个参数:要编码的单词和包含密钥的 argv 数组。
编码后的字符串现在使用 malloc 初始化,它为字符串分配内存。字符串的大小是根据 word 参数的长度加上一个空终止符来计算的。这确保了字符串有足够的空间来容纳编码的文本。
编码字符串现在使用空终止符 (' ') 进行初始化,以确保它被正确终止。
循环内的 if 语句现在检查字符是否在 'a' 到 'z'(含)范围之外。如果是,则字符直接复制到编码字符串而不进行编码。否则,字符使用密钥进行编码。
替换函数现在返回字符串而不是整数。