c语言凯撒分割错误

时间:2020-06-29 21:15:47

标签: c command-line-arguments undefined-behavior cs50 argv

我正在研究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;
}

1 个答案:

答案 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并检查其执行是否成功。.