【问题标题】:Why am I getting errors?为什么我会收到错误?
【发布时间】:2020-11-05 22:03:23
【问题描述】:

我正在尝试创建一个接受命令行参数来加密明文的程序! 程序在制作时必须在其名称后接受一个 cmd 行参数,这将是由纯文本(仅)字母字符由该键旋转的键(例如,它的数字被添加到真实的字母 ASCII 数字中,导致另一个字母打印出来!

它应该在存在一个参数时打印一条错误消息(例如这里:/make encipher) 而不是在这里:/make encipher 12

在没有 key 参数的情况下运行程序时出现分段错误,为什么?

这是完整的代码。我发布它是因为我需要了解我的错误的确切位置在哪里 为什么会触发?!


#include <cs50.h>
#include <stdio.h>
#include <stdlib.h> //  To use atoi (converting a string to an int)
#include <ctype.h>
#include <string.h>

bool key_is_numb(string argv[]);
void encipher(string txt, int key);

int main(int argc, string argv[])
{
    if (key_is_numb(argv) == false)
        {
            printf("Usage: ./caesar key\n");
            return 1;
        }

    else
    {
    int key = atoi(argv[1]);
    string plaintext;

            if (argc == 2 && key > 0)
                {
                    plaintext = get_string("plaintext: ");
                    encipher(plaintext, key);  //  A function that prints the ciphered text
                    return 0;   //  returns Zero as main return value which means "All good"!
                }

            else if (argc == 1 || argc > 2 || key <= 0)
                {
                    printf("Usage: ./caesar key\n");
                    return 1;
                }

    }   //  End else.

}   // End main()å func.



bool key_is_numb(string argv[])
{
    int n = strlen(argv[1]);

    for (int i = 0; i < n; i++) //  checking element by element in the second string of the argv[] array of strings
    {
        if (isdigit(argv[1][i]) == 0)   //  if the entered string "key" contains chars other than digits.
        {
            return false;   //  break out of the if statement & the entire function key_is_numb()
                            //  and return false as soon as a letter is encountered.
        }

        else
        {
            continue;   //  go up & start the next iteration for the for loop.
        }
    //  if only digits encountered then this for loop will come to an end and exist from here.
    }   //  End for loop

    return true;   //  function exits and return boolean true from here.

}   // End key_is_numb() func.


void encipher(string txt, int key)
{
    printf("ciphertext: ");
    for (int i = 0, n = strlen(txt); i <= n; i++)    // strlen counts the number of elements in a string excluding '\0'
    {
        char c = txt[i];

        if (isalpha(c))
        {
            if (isupper(c))
            {
                char m = 'A';   //  This is a modifyer character equals to 'A' = 65 so that it is indexed @ ZERO!
                printf("%c", (c - m + key) % 26 + m );
                //c = ((((int)txt[i] - 65) + key) % 26) + 65; //  char c = 65 <-- 65 is an ASCII code equals 'A'
            }
            else if (islower(c))
            {
                char m = 'a';   //  This is a modifying character 'a' = 97
                printf("%c", (c - m + key) % 26 + m );
            }
        }//  End if(alpha).

        else
        {
            printf("%c", c);
        }

    }   //  End for().
        printf("\n");

}   //  End encipher() func.

【问题讨论】:

  • 你的代码假设总是有一个argv[1]。您应该检查argc,它告诉您参数的数量。
  • 我发布它是因为我需要了解我的错误的确切位置在哪里以及为什么会触发它?! -- 这就是调试器的目的,以及为什么它是学习如何使用的重要工具。
  • @PaulOgilvie 请在答案部分发布您的答案。谢谢。
  • stringchar* 的类型别名吗?如果是这样,为什么会做一些令人困惑的事情?
  • @TedLyngmo stringchar *cs50.h typedef 别名。它属于cs50.h

标签: c segmentation-fault cs50


【解决方案1】:
int n = strlen(argv[1]);

key_is_numb()

int key = atoi(argv[1]);

main().

如果您没有输入键参数,argv[1] 等于 argv[argc] 是 C17 §5.1.2.2.1/2 中所述的空指针。

任何访问其数据的尝试都是undefined behavior,并且可能导致分段错误。

【讨论】:

    【解决方案2】:

    您的代码假定始终存在argv[1]。您应该检查argc,它告诉您参数的数量。例如:

    int main(int argc, string argv[])
    {
        if (argc < 2) {
            printf("Key required\n");
            exit (1);
        }
    

    【讨论】:

      【解决方案3】:

      你假设 argv[1] 在key_is_numb 中定义。但是,在 C 和 C++ 中,主函数的第二个参数包含命令行参数。在您的情况下,将二进制文件的名称作为第一个元素,然后是任何其他参数。这就是为什么当你在没有参数的情况下运行程序时,它会出现段错误,因为没有参数可以放入 argv,也没有默认值。

      在尝试读取argv 中的任何内容之前,您应该始终使用argc 中存储的数字检查argv 的大小。

      您的分段错误来自这一行 int n = strlen(argv[1]);,但我强烈建议您学习使用调试器软件,如 valgrind,如果程序已使用调试标志编译,它将告诉您确切的行。

      其他调试器也非常有用,所以你应该学会使用它们,因为它们通常会报告这种错误。

      【讨论】: