【问题标题】:Caesar segmentation fault in c language [closed]c语言中的凯撒分段错误[关闭]
【发布时间】:2020-10-20 03:03:57
【问题描述】:

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

【问题讨论】:

  • 这是学习如何使用调试器的最佳时机。使用调试器,您可以在崩溃发生时捕捉崩溃,并能够在代码中找到它发生的位置。然后,您还可以检查所有相关变量的值。
  • char f[n]; ==> char f[n+1]; 经典不允许为字符串终止符留出空间。
  • @Mahmoud Ferig 你期待这个声明 int m = strlen (v[1]);当 v[1] 等于 NULL 时会产生?编写一个只包含一条语句的简单程序 strlen( NULL );看看结果。
  • 你还需要学习一些其他的东西,首先你不应该真正使用magic numbers。另一个好消息是关于the standard character classification and manipulation functions。还要始终检查有效的参数计数器argc在尝试访问特定参数之前,例如,如果没有为您的程序提供参数,那么k[1] 将是NULL。事实上,k[argc]总是NULL(在 C 规范中定义)。
  • @WeatherVane,OP 没有使用f[] 作为字符串。不需要 +1 - 至少现在不需要。

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


【解决方案1】:

根据C标准(5.1.2.2.1程序启动)

2 如果声明了,主函数的参数应该服从 以下约束:

——argc 的值应为非负数。

——argv[argc] 应该是一个空指针......

所以当你像这样运行程序时

./caesar

如果不指定命令行参数,则 argc 等于 1,argv[argc] 即 argv[1] 等于 NULL。

您的程序从调用函数key 开始,然后立即调用标准C 函数strlen 用于等于v[1] 的指针v[1]。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2014-03-27
    • 2018-12-28
    • 2015-01-08
    • 2014-02-28
    • 2021-10-15
    相关资源
    最近更新 更多