【问题标题】:Splitting a command line argument in C在 C 中拆分命令行参数
【发布时间】:2018-11-09 16:25:03
【问题描述】:

我想将第一个命令行参数分成两个不同的数字。以这种方式运行程序时出现分段错误错误:

gcc -ansi main.c -o main
./main 6000V7000

这里是源代码:

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

int main(int argc, char *argv[]) {
    char *token;
    char arr[200];
    strcpy(arr, argv[1]);

    token = strtok(arr, "v,V");
    int firstNumber = atoi(token);
    token = strtok(NULL, "v,V");
    int secondNumber = atoi(token);

    return 0;
}

我该如何解决这个问题?

【问题讨论】:

  • 问题是什么?
  • 我没有收到分段错误错误。
  • 这段代码运行良好,应该如此。如果它不适合你,那么你的问题中没有包含足够的细节。
  • 您确定这是产生错误的相同代码,还是您“简化”了它并在过程中删除了错误?如果输入 包含分隔符,它将失败。在尝试atoi() 之前,您应该测试strtok 是否返回NULL。在 GDB 中运行它——它会准确地告诉你故障发生在哪一行以及所涉及的任何函数调用的参数——你可以检查任何其他变量。
  • 使用gcc -Wall -Wextra -g 编译。并阅读how to debug small programs

标签: c split command-line-arguments


【解决方案1】:

您不测试是否至少有一个命令行参数,也不测试该参数是否少于 200 个字符,也不测试 strtok 的返回值:如果给出命令,您将有未定义的行为没有参数,或者如果参数不包含任何字符 vV,

如果您使用gcc -ansi main.c -o main 有效地编译程序并使用发布的参数作为./main 6000V7000 运行它,您不应该遇到分段错误...有些事情您没有告诉我们;)

最好避免盲目的假设:测试意外情况以在所有情况下为您的程序定义行为。

这是使用sscanf() 解决您的问题的更简单方法:

#include <stdio.h>

int main(int argc, char *argv[]) {
    int a, b;
    if (argc > 1 && sscanf(argv[1], "%d%*1[vV,]%d", &a, &b) == 2)
        printf("a=%d, b=%d\n", a, b);
    return 0;
}

【讨论】:

  • 很好的解决方案 - 不需要缓冲。
【解决方案2】:

给出的代码和命令行参数没有段错误。但是,如果命令行参数省略分隔符、在第二个数字之前包含一个空格或完全省略任何参数,那么它将失败。

以下将防止错误输入导致运行时错误:

if( argc > 1 )
{
    strcpy( arr, argv[1]);

    int firstNumber = 0 ;
    int secondNumber = 0 ;
    token = strtok(arr, "v,V");
    if( token != NULL )
    {
        firstNumber = atoi(token) ;
        token = strtok(NULL, "v,V") ;
        if( token != NULL )
        {
            secondNumber= atoi(token); 
        }
    }
}

【讨论】:

    【解决方案3】:

    你必须在函数的开头定义 var :

    关注code 可以工作:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(int argc, char *argv[]){
    
        char *token;
        char arr[200];
        int firstNumber;
        int secondNumber;
    
        strcpy( arr, argv[1]);
    
        token = strtok(arr, "v,V");
        firstNumber = atoi(token);
        token = strtok(NULL, "v,V");
        secondNumber= atoi(token);
    
        return 0;
    
    }
    

    【讨论】:

    • 自 C99 以来你没有。在任何情况下,这都不会导致段错误。
    • 同意你的看法;也就是说,他似乎使用 C ansi(参见编译行)
    • GCC doc: “-ansi 选项不会导致非 ISO 程序被无偿拒绝。为此,除了 -ansi 之外,还需要 -Wpedantic。”。它是学术性的——这仍然不能解决它为什么会出现段错误的问题。
    • @Clifford 你能给我一个关于文档的链接吗?
    • GNU GCC 文档很容易找到:gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/…。我并不是说这就是为什么在使用 -ansi 时代码被接受的原因——我认为 -ansi 的使用可能在不同版本的 GCC 上发生了变化。然而,关键是编译器 did 接受此代码或问题中的构建命令不是实际用于编译它的命令 - 这是很有可能的,因为给出的代码和命令行也没有产生运行时错误。重点在于这是对不同问题的回答
    【解决方案4】:

    您的输入中只有一个"V"。对 strtok() 的第二次调用没有找到 V 并返回 NULL

    【讨论】:

    • strtok第一次 调用返回一个指向6000 的指针。对strtoksecond 调用返回一个指向7000 的指针。
    • strtok 不是这样工作的。它将在第三次调用时返回 NULL。
    猜你喜欢
    • 2020-04-28
    • 2023-03-21
    • 1970-01-01
    • 2014-09-18
    • 2012-03-03
    • 2016-12-12
    • 2013-05-19
    • 2014-06-23
    • 2017-02-07
    相关资源
    最近更新 更多