【问题标题】:Taking arguments as input from terminal将参数作为终端的输入
【发布时间】:2016-10-18 04:13:51
【问题描述】:

这是一个函数的一部分,它从终端获取输入并根据输入的内容对它们进行排序(排序类型、要使用的排序方法的版本/变体以及数组的大小)。这是我目前所拥有的:

int main(int argc, char * argv[]) { //will have 3 arguments not including function name: sortingtype, version and arr size
    int * arr = make_arr(argv[2], argv[3]); //[2]

    if (strcmp(argv[1], "sortingtype1") == 0) {
        SortingType1(arr, argv[3]); //[2][3]
    }
    else if (strcmp(argv[1], "sortingtype2") == 0) {
        SortingType2(arr, argv[3]); //[2][3]
    }
    else {
        return 0;
    }
}

void test(){ //[1]
    main("sortingtype1", "a", 10); //sortingtype, version and arr size
}

[1] 我有一个函数 test() 来模拟来自终端的输入,但我不知道它是否可以这样工作。我收到一条错误消息,提示 main 参数太多。

[2] 无论我是否删除该测试函数,我仍然会收到有关“传递参数 (带有 argv[X] 的参数) 从指针中生成整数而不进行强制转换”的警告。

[3] 这些也需要是int类型而不是char*类型,如何更改?

关于如何解决这个问题有什么建议吗?我已经看到了使用 sscanf 的解决方案,但我希望首先了解一个围绕我的技能水平的更基本的解决方案。

编辑:分段错误来自

int * SortingType2(int * arr, int len) {
    for (int i=1; i < len; i++) {
        int x = arr[i];
        int j = i;
        while ((j > 0) && (x < arr[j-1])) {
            arr[j] = arr[j-1];
            j--;
        }
        arr[j] = x;
    }
    return arr;
}

int main(int argc, char * argv[]) {
    int size;
    if (argc > 3) size = atoi(argv[3]);

    int * arr = make_arr(argv[2][0], size);

    if (strcmp(argv[1], "sortingtype1") == 0) {
        SortingType1(arr, size);
    }
    else if (strcmp(argv[1], "sortingtype2") == 0) {
        SortingType2(arr, size);
    }
    else {
        return 0;
    }
}

【问题讨论】:

  • 您不应该直接致电main。这是在任何教程或教科书的第一课中教授的基本 C。请咨询这些。
  • sscanf 是将字符串转换为int 的不错选择。其他选项是strtolatoistrtol 在处理错误检查的方式上有点迟钝。 atoi 根本不会打扰。 sscanf 是中间地带,具有易于使用的良好错误检查功能。
  • @kaylum——一个小问题。 C 标准当然允许递归调用 main()
  • @kaylum:你对 C++ 和 C 感到困惑吗?在 C++ 中,不允许调用main()(详见What should main() return in C and C++)。在C语言中,没有禁止调用main()——它是一个普通的函数,可以被用户代码调用,唯一特别的是在托管环境中,它是启动代码调用的函数.
  • @JonathanLeffler 我知道有人会指出这一点 :-) 我只是懒得深入细节。我的意思是说没有必要像那样显式调用main,并且无论如何都不会调用test 函数。

标签: c segmentation-fault arguments


【解决方案1】:

argv[] 是一个字符串数组,因此如果需要整数,则需要对其进行转换。最简单的方法是使用atoi()sscanf()atoi()stdlib.h 中,sscanf()stdio.h 中。使用atoi(),你只需给它一个字符串,它就会返回一个int。使用sscanf(),您可以提供字符串、转换说明符和变量地址,就像在scanf() 函数中一样,不同之处在于您在这里扫描的是字符串而不是标准输入。这是一个例子:

#include <stdio.h>   // needed for atoi()
#include <stdlib.h>  // needed for sscanf()

int main(int argc, char *argv[])
{
    int i = 0;
    int j = 0;

    /* if argv[1] exists, convert to int */
    if (argc > 1)
        i = atoi(argv[1]);

    /* if argv[2] exists, convert to int */
    if (argc > 2)
        sscanf(argv[2], "%d", &j);

    printf("%d -- %d\n", i, j);

    return 0;
}

如果你编译这段代码并执行它,你会得到,例如:

david scratch λ> ./a.out 123 456
123 -- 456

使用您的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char * argv[])
{
    int size;

    if (argc < 4) {
        printf("Usage: %s sortingType state size\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    size = atoi(argv[3]);

    int * arr = make_arr(argv[2], size);

    if (strcmp(argv[1], "sortingtype1") == 0) {
        SortingType1(arr, size);
    }
    else if (strcmp(argv[1], "sortingtype2") == 0) {
        SortingType2(arr, size);
    }

    return 0;
}

【讨论】:

  • 谢谢,我使用了 atoi,但现在执行时出现分段错误。尝试声明变量并使用它们代替 argv[X] 并尝试简单地将它们包装在 atoi() 中。
  • 你能用一个对你来说失败的代码的好例子来更新你的问题吗?
  • 好吧,这似乎是参数的问题(我使用了 Jonathan Leffer 的第一个代码):Usage: sortingtype sortingType state size
  • 如果我在上面刚刚显示的代码中注释掉您对make_arr()SortingType1()SortingType2() 的函数调用,没有问题。我认为您的麻烦在于这些功能之一。我会先看看make_arr()
  • 嗯,真奇怪!实际上,我早先这样做是为了确保它不涉及这些功能,并再次将它们注释掉,并且仍然遇到段错误。早上不那么累的时候再好好看看。谢谢。
【解决方案2】:

如果你想从一个函数中调用main(),那么你必须传递一个参数计数和一个指向以空结尾的字符串数组的指针(有关详细信息,请参阅What should main() return in C and C++?)。

因此,你可以写:

void test(void)
{
    char *argv[] = { "sortingtype", "a", "10", 0 };
    main(3, argv);
}

这样做并不常见。您的代码中没有证据表明调用了 test() 函数。

请注意,上述代码中的参数不是可修改的字符串;通常,参数是可修改的。如果这很重要,你必须更加努力:

void test(void)
{
    char arg0[] = "sortingtype";
    char arg1[] = "a";
    char arg2[] = "10";
    char *argv[] = { arg0, arg1, arg2, 0 };
    main(3, argv);
}

还要注意argv 中的所有参数都应该是字符串。您的原始代码似乎试图通过 10 而不是 "10" 但这在参数向量中是不允许的(尽管 10 当然可以作为参数计数有效)。


请注意,递归调用main() 充其量是一件古怪的事情。实际上很少有必要或可取。然而,它在 C 中是合法的——但在 C++ 中是不合法的。

【讨论】:

  • 要完整,这个答案需要为这个简单的难题提供解决方案:由于启动代码调用maintest 可以调用main 的唯一方法是main致电test。但是,如果 test 正在调用 main 来调用 test,那么您一定不是在测试您打算测试的 main
  • 您说:test 可以调用main 的唯一方法是main 调用test 该语句不完整;完整的语句应该是:test() 可以调用main() 的唯一方法是如果main() 调用test(),或者由(由...调用的函数)调用的函数main() 又调用@ 987654350@。 当然,您需要在某处使用条件代码来防止无限递归。我在一个测试程序中使用了一次对main() 的递归调用。这不是每天都在使用。
  • 请注意,从应用程序本身调用 main 是非常糟糕的做法。大多数时候,递归也是如此。
  • @Lundin:中肯的评论——我添加了或多或少合适的注释。
猜你喜欢
  • 2014-12-21
  • 2019-12-11
  • 1970-01-01
  • 2020-09-27
  • 2021-12-27
  • 1970-01-01
  • 2016-06-28
  • 2014-12-31
相关资源
最近更新 更多