如何检查以确保命令行参数的每个字符都是十进制数字(即 0、1、2 等)

how to check to make sure that each character of the command line argument is a decimal digit (i.e., 0, 1, 2, etc.)

我有点卡在 CS50 加密练习的一部分,我们必须在 C 语言中实现一个使用凯撒密码加密消息的程序。

特别是这部分:“修改 caesar.c 这样您的程序就不会打印出提供的命令行参数,而是检查以确保该命令行参数的每个字符都是十进制数字(即, 0, 1, 2, 等等),如果其中任何一个不是,则在打印消息后终止用法:./caesar key."

我的代码如下:

#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>

int main (int argc, string argv[])
{
    //checks if the user provides exactly one command-line argument
    if (argc != 2)
    {
        printf("Usage: ./caesar key\n");
        return 1;
    }
    else
    {
        printf("success\n");
    }


    for (int i = 0, n = strlen(argv[1]); i < n; i++)
    {
        // check if any of the characters of the command-line argument is not a decimal digit
        
        if (isdigit(argv[1][i]))
        {
            printf("success\n");
            return 0;
        }
        else
        {       
            printf("Usage: ./caesar key\n");
            return 1;
        }
    }
}

如您所见,第一部分有效(检查一个命令行参数),但是当我输入一串十进制数字作为该参数时,如 123c 或 1c23,它仍然打印成功。

显然这是因为循环检查字符串中的第一个字符是否为数字,如果是则立即打印成功。因此,我想在我的代码中找到一种简单的方法来检查参数的每个字符都是数字,然后才打印成功或用法:./caesar key.

感谢您的帮助,如果需要问题集的更多背景信息,请告诉我。

正在做

for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
   // check if any of the characters of the command-line argument is not a decimal digit
   
   if (isdigit(argv[1][i]))
   {
       printf("success\n");
       return 0;
   }
   else
   {       
       printf("Usage: ./caesar key\n");
       return 1;
   }
}

你只考虑 argv[1] 的第一个字符,因为你 return 在 if

的两个分支中

你可以做到

for (int i = 0; argv[1][i]; i++)
{
    // check if any of the characters of the command-line argument is not a decimal digit
    
    if (!isdigit((unsigned char) argv[1][i]))
    {
        printf("Usage: ./caesar key\n");
        return 1;
    }
}

printf("success\n");
return 0;

但是空参数被认为是可以接受的,很可能你也想得到数字,而不是像你那样循环,你可以使用 strtolscanf 来获取数字和检查你有一个号码,例如:

#include <stdio.h>

int main(int argc, char ** argv)
{
  //checks if the user provides exactly one command-line argument
  if (argc != 2)
  {
    printf("Usage: %s key\n", *argv);
    return 1;
  }
  
  int key;
  char c;
  
  // check argv[1] is only a number
  if (sscanf(argv[1], "%d %c", &key, &c) != 1)
  {
    printf("'%s' is not a valid key\n", argv[1]);
    return 1;
  }
  
  printf("valid key %d\n", key);
  
  return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall c.c
pi@raspberrypi:/tmp $ ./a.out
Usage: ./a.out key
pi@raspberrypi:/tmp $ ./a.out aze
'aze' is not a valid key
pi@raspberrypi:/tmp $ ./a.out 1a
'1a' is not a valid key
pi@raspberrypi:/tmp $ ./a.out a1
'a1' is not a valid key
pi@raspberrypi:/tmp $ ./a.out 1
valid key 1
pi@raspberrypi:/tmp $ ./a.out 123
valid key 123
pi@raspberrypi:/tmp $ ./a.out "123 "
valid key 123
pi@raspberrypi:/tmp $ ./a.out "123 a"
'123 a' is not a valid key
pi@raspberrypi:/tmp $ ./a.out " 123 "
valid key 123
pi@raspberrypi:/tmp $ ./a.out " "
' ' is not a valid key
pi@raspberrypi:/tmp $ ./a.out ""
'' is not a valid key
pi@raspberrypi:/tmp $ 

如您所见,空格是可以容忍的,这是读取数字的常见方式

当然如果你不想要负数就做

if ((sscanf(argv[1], "%d %c", &key, &c) != 1) || (key < 0))

[编辑您的评论]

For the first part even when I run if (!isdigit((unsigned char) argv[1][i])) the code still doesn't work correctly. F.e. if I run f.e. ./caesar 12p is still prints success (same problem as before).

这意味着你没有得到我所有的代码,如果我把我的第一个提案放在一个完整的程序中,你可能会继续在两个分支中使用你的 if :

#include <stdio.h>
#include <ctype.h>

int main(int argc, char ** argv)
{
  //checks if the user provides exactly one command-line argument
  if (argc != 2)
  {
    printf("Usage: %s key\n", *argv);
    return 1;
  }

  for (int i = 0; argv[1][i]; i++)
  {
    // check if any of the characters of the command-line argument is not a decimal digit
    
    if (!isdigit((unsigned char) argv[1][i]))
    {
      printf("Usage: ./caesar key\n");
      return 1;
    }
  }
  
  printf("success\n");
  return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall c.c
pi@raspberrypi:/tmp $ ./a.out 12p
Usage: ./caesar key
pi@raspberrypi:/tmp $ ./a.out 12
success
pi@raspberrypi:/tmp $