【问题标题】:How to sum all command line arguments in C?如何总结C中的所有命令行参数?
【发布时间】:2018-07-11 22:09:13
【问题描述】:

我有一个任务。该程序将打印 C 中所有命令行参数的总和。我尝试了它编译的这段代码,但在控制台中传递参数后抛出错误。下面是代码。

/* Printing sum of all command line arguments */
#include <stdio.h>

int main(int argc, char *argv[]) {
    int sum = 0, counter;

    for (counter = 1; counter <= argc; counter++) {
       sum = atoi(sum) + atoi(argv[counter]);
    }
    printf("Sum of %d command line arguments is: %d\n", argc, sum);
}

编译后会输出Segmentation fault (core dumped) 错误。您的经验可能会解决我的问题。

下面是我编辑的代码:

/* Printing sum of all command line arguments*/
#include <stdio.h>
#include <stdlib.h> // Added this library file

int main (int argc, char *argv[]) {
    int sum = 0, counter;

    for (counter = 1; counter < argc; counter++) {
        // Changed the arithmetic condition
        sum = sum + atoi(argv[counter]);
        // Removed the atoi from sum variable
    }
    printf("Sum of %d command line arguments is: %d\n", argc, sum);
}

【问题讨论】:

  • @AnudeepSyamPrasad 教你使用"stdio.h"atoi 的人不是“最好的”,而是江湖骗子。
  • @Mawg 在 CR 上发布的不正确建议是 meta 上的烫手山芋,例如,请参阅这个新鲜的讨论:meta.stackoverflow.com/questions/362417/…
  • @Lundin 当您的代码工作时,将其发布到我们的姊妹网站 codereview.stackexchange.com。不错的推荐
  • @BjornA。 C11 7.22.1 “如果结果的值无法表示,则行为未定义。”基本上,如果你给它任何不是 ASCII 数字的东西,这个函数肯定会出错。与 strtol 系列函数不同,它们具有 100% 等效的功能,但不会出错。
  • @Ian atoi 假设它得到了一个以空字符结尾的字符串,只包含有效数字。如果它得到其他任何东西,它就会出错。使用它没有任何意义,因为strtol 系列函数具有相同 功能(以及更多),以及正确的错误处理。它与多线程无关。

标签: c syntax-error command-line-arguments atoi


【解决方案1】:

指定argv[argc]始终为空指针。您循环了太多次,并将这个空指针传递给atoi,导致未定义的行为

将循环条件更改为counter &lt; argc

sum 已经一个整数,你不需要用atoi 将它转换成整数。 atoi(sum)会导致未定义的行为,因为第一次迭代会将零传递给atoi,这也可以看作是一个空指针。 p>

【讨论】:

    【解决方案2】:

    因为您一直迭代到counter == argc,所以您将NULL 指针传递给atoi(),这很简单,只依赖argv 数组有一个NULLsentinel 的事实,然后执行此操作

    /* Printing sum of all command line arguments*/
    #include <stdlib.h> /* For `atoi()' */
    #include <stdio.h>  /* For `printf()' */
    
    int main(int argc, char *argv[])
    {
        int sum;
        sum = 0;
        for (int counter = 1; argv[counter] != NULL; ++counter)     {
            sum += atoi(argv[counter]);
        }
        printf("Sum of %d command line arguments is: %d\n", argc, sum);
    }
    

    注意atoi(sum) 是未定义的行为,因为sumint 并且不是有效指针。而atoi() 将尝试取消引用它。此外,aoti() 代表 ascii 到整数sum 已经是整数,因此转换没有意义。

    最后,为atoi() 添加stdlib.h。我知道您没有包含它,因为我在编译器上启用了警告,它警告我 atoi() 是隐式定义的。它可能可以工作,但只是因为未定义的行为是未定义的。

    另外,请注意,无法知道传递的参数是否为整数,因为atoi() 无法执行错误检查。您可能想改用 strtol() 并检查所有值是否都是整数。

    所以...这就是您编写该程序更健壮版本的方式

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
        int sum;
        sum = 0;
        for (int counter = 1; argv[counter] != NULL; ++counter)     {
            char *endptr;
            sum += strtol(argv[counter], &endptr, 10);
            if (*endptr != '\0') {
                fprintf(stderr, "error: the `%d-th' argument `%s', is not a valid integer\n", counter, argv[counter]);
                return EXIT_FAILURE;
            }
        }
        printf("sum of %d command line arguments is: %d\n", argc, sum);
        return EXIT_SUCCESS;
    }
    

    编辑:致this comment

    argc == 0 有可能,例如,如果您通过 exec*() 函数之一执行程序。在这种情况下,您必须在开始循环之前检查,否则argv[counter] 将是最后一个元素之后的一个元素,即超出范围。

    【讨论】:

    • 解决所有错误的唯一完整答案 - 不错。
    • @Bathsheba 我以为你会说你更喜欢使用counter &lt; argc
    • 如果您希望它真正健壮,您可以检查潜在的int 溢出(UB 的潜力更大,此类影响可能在 +/- 32767 处显现) .但这现在变得愚蠢了吗?
    • @ChrisTurner:不,这很糟糕。
    • @Bathsheba Pah。我敢打赌,在有人写 *argv[counter] 并得到一个永恒的循环之前,你会更喜欢这样,而 *argv[counter] == NULL 在比较不兼容的类型时会给出编译器错误。它不是重言式,它是减少错误的坚固、专业的代码。 MISRA-C 禁止以前的危险风格是有原因的。
    【解决方案3】:

    argv 的最后一个元素定义NULL,第一个元素始终是程序名称。因此,您可以将代码减少到

    #include "stdio.h"
    
    int main(int argc, char *argv[])
    {
        int sum = 0;
        for (int i = 1; argv[i]; ++i){
            sum += atoi(argv[i]);
        }
        printf("Sum of %d command line arguments is: %d\n", argc, sum);
    }
    

    在您的代码中,atoi(sum) 的行为以及在最终迭代中归结为 argv[argc] 的行为将是未定义的。

    【讨论】:

      【解决方案4】:

      一个递归版本,只是为了它:)

      #include <stdio.h>
      #include <stdlib.h>
      
      int main(int argc, char **argv)
      {   
          static int sum;
      
          if (*++argv == NULL)
              return !printf("sum: %d argc %d\n", sum, argc - 1);
      
          sum += atoi(*argv);
          return main(argc, argv);
      }
      

      【讨论】:

      • 只是为了确认我的理解,静态 int sum 在所有迭代中保持它的价值?另外,很好:)
      • 谢谢 :) 是的,静态用于不断添加到同一个变量。
      • 您不能从main() 中调用main()main() 很特别。
      • 哎呀,我错过了,你是对的。把它扔进它自己的方法中并传递参数,你会很好的。
      • @IharobAlAsimi 您正在考虑 C++。 C 没有这样的限制。
      【解决方案5】:
      /* My example. Should work, though untested. */
      #include <stdio.h>
      
      int main(int argc, char *argv[])
      {
          int sum, index;    // Generally considered better form to put them on separate lines.
          sum = 0;
      
          if(argc > 1) {    
              for(index = 1; index < argc; index++) {
                  sum += atoi(argv[index]);
              }
              printf("%d Command-line args\nSum = %d\n", argc, sum);
          } 
          else {
              printf("Not enough command-line args\n");
          }
      }
      

      确保尽最大努力为您的代码遵守特定的格式样式。如果您想按名称定义您的样式指南,请搜索样式指南。 GNU C is a good starting point。它们将使您的代码更具可读性、更易于调试,并帮助其他人了解其中发生的情况。

      对上述代码的一些更正..

      /* Your code with corrections */
      #include "stdio.h"
      
      int main(int argc, char *argv[])
      {
         int sum=0,counter; 
         // 1. Normally you want to give each variable it's own line. Readability is important.
         // 2. Don't initialize on declaration either. Refer to my example.
         // 3. Always add spaces between operators and at the end of statements for better readability.
          for(counter=1;counter<=argc;counter++)
          {
             // 4. atoi(sum) is unneccessary as it interprets your int sum as a const char*, 
             // which as far as I can tell should just give you back it's ascii value. 
             // It might be undefined however, so I would remove it regardless.
             // 5. Your segfault issue is because you iterate over the end of the array.
             // You try to access the [argc] value of the array (remember 0-based
             // indexing means a size val is always 1 greater than the greatest index).
             // Make 'counter<=argc' into 'counter < argc'
      
             sum = atoi(sum) + atoi(argv[counter]);
          }
        printf("Sum of %d command line arguments is: %d\n", argc, sum);
      }
      

      atoi() documentation of a form.

      请注意,如果您在命令行中输入字符或字符串,您的代码仍然可以运行,但行为会很奇怪。 atoi() 会将字符转换为对应的ASCII decimal character index/value.

      您也可以使用空值(argv[] 总是在 argv[argc] 处以空值终止)来结束迭代。不过我更喜欢使用提供的 argc。

      希望这对您有所帮助。如果您不理解我在这里抛出的任何内容,请发表评论或在线搜索。

      干杯!

      【讨论】:

      • 你从来没有真正解释错误的原因。
      • @John3136 是的,我做到了。阅读他的代码中的 cmets。我在 #5 中进行了解释。
      猜你喜欢
      • 1970-01-01
      • 2021-08-26
      • 2011-03-23
      • 2012-06-09
      • 1970-01-01
      • 2022-09-28
      • 1970-01-01
      • 1970-01-01
      • 2013-01-13
      相关资源
      最近更新 更多