我正在研究CS50的第二个作业凯撒。除了上一个,我的大部分评论似乎都是正确的。我无法处理缺少argv[1]
的情况,这意味着如果我仅键入./caesar
,它将导致分段错误。为什么?
#include <stdio.h>
#include <string.h>
#include <cs50.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
bool check;
int key (int c, string v[]);
int main (int argc, string k[])
{
key (argc, k);
if ((check))
{
string p = get_string("plaintext: ");
int n = strlen (p);
char f[n];
printf ("ciphertext: ");
for (int i = 0; i < n; i++)
{
if (isalpha (p[i]))
{
if (p[i] >= 'A' && p[i] <= 'Z')
{
if ((p[i] + x) > 90)
{
f[i] = ((p[i] + x) % 91) + 65;
printf ("%c", f[i]);
}
else
{
f[i] = ((p[i] + x) % 91);
printf ("%c", f[i]);
}
}
else if (p[i] >= 'a' && p[i] <= 'z')
{
if ((p[i] + x) > 122)
{
f[i] = ((p[i] + x) % 123) + 97;
printf ("%c", f[i]);
}
else
{
f[i] = ((p[i] + x) % 123);
printf ("%c", f[i]);
}
}
}
else
{
printf ("%c", p[i]);
}
}
printf ("\n");
}
}
int key (int c, string v[])
{
int m = strlen (v[1]);
for (int i = 0; i <= m; i++)
{
if (v[1][0] == 0)
{
printf ("Usage: ./caesar key\n");
return 1;
}
else if (v[1][i] >= 32 && v[1][i] < 48)
{
printf ("Usage: ./caesar key\n");
return 1;
}
else if (v[1][i] >= 58 && v[1][i] <= 126)
{
printf ("Usage: ./caesar key\n");
return 1;
}
}
if (c != 2)
{
printf ("Usage: ./caesar key\n");
return 1;
}
else
{
int r = atoi (v[1]);
if (r < 1)
{
printf ("Usage: ./caesar key\n");
return 1;
}
else
{
check = true;
return r;
}
}
return 0;
}
答案 0 :(得分:1)
根据C标准(5.1.2.2.1程序启动)
2如果已声明,则应遵循main函数的参数 以下限制:
— argc的值应为非负。
— argv [argc]应为空指针....
因此,当您运行类似程序时
./caesar
在不指定命令行参数的情况下,argc
等于1,而argv[argc]
等于argv[1]
等于NULL
。
您的程序首先调用函数key
,该函数又立即为等于strlen
的指针v[1]
调用标准C函数NULL
。>
int key (int c, string v[])
{
int m = strlen (v[1]);
//...
此调用调用未定义的行为,导致您编写时出现分段错误。
在调用函数key
之前,您应该首先检查argc
等于2,或者在函数中检查if语句
if (c != 2)
{
printf ("Usage: ./caesar key\n");
return 1;
}
应该在处理v[1]
之前放置。
所有这些检查都带有许多魔术数字
for (int i = 0; i <= m; i++)
{
if (v[1][0] == 0)
{
printf ("Usage: ./caesar key\n");
return 1;
}
else if (v[1][i] >= 32 && v[1][i] < 48)
{
printf ("Usage: ./caesar key\n");
return 1;
}
else if (v[1][i] >= 58 && v[1][i] <= 126)
{
printf ("Usage: ./caesar key\n");
return 1;
}
}
是多余的。您可以立即调用函数strtol
并检查其执行是否成功。.