如何在C语言中检查输入是否为数字?

20

C语言中的主函数:

void main(int argc, char **argv)
{
   // do something here
}

在命令行中,我们将输入任何数字例如12,但它将被视为参数argv的char数组,但如何确保输入是数字,以防用户键入helloc


使用getopt()处理参数。http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html#Example-of-Getopt - Kyslik
使用sscanf函数并检查返回值是否正确。请参考man手册获取详细信息。 - Shahbaz
3
题外话:你应该使用int main() { return 0; } - squiguy
1
@squiguy return 0; 是隐式的(来自C99),而且留空参数列表也是不好的。 - effeffe
10个回答

27

使用 isdigit 函数也可以实现。以下是代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define MAXINPUT 100
int main()
{
    char input[MAXINPUT] = "";
    int length,i; 

    scanf ("%s", input);
    length = strlen (input);
    for (i=0;i<length; i++)
        if (!isdigit(input[i]))
        {
            printf ("Entered input is not a number\n");
            exit(1);
        }
    printf ("Given input is a number\n");
}

如果输入中有任何浮点数或双精度数字,则其输出将是错误的。 - Aashish Kumar
1
在这种情况下,输入为“-45”,这个程序会发生什么?它能正常工作吗? - Shiva Sai
如果给定一个floatisdigit()会返回true吗? - Voldemort's Wrath
1
如果某些难以驯服的用户(或攻击者)输入超过99个数字,则此代码可能会遇到缓冲区溢出问题。 理想情况下,您应该使用scanf("% 99s",input)来确保这种情况不会发生。 还要测试scanf()返回的EOF; 目前,如果指示EOF(或从/dev/null重定向输入),程序将报告给定的输入是一个数字。 在大多数计算机上,您无法使用标准C类型表示99位数字。 - Jonathan Leffler
在for循环中,我们是否需要使用length-1而不是length? - incompetent

17

您可以使用像 strtol() 这样的函数,它将字符数组转换为长整型。

该函数有一个参数,用于检测无法成功转换的第一个字符。如果这个字符不是字符串的末尾,那么就会出现问题。

请参考以下示例程序:

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

int main( int argc, char *argv[]) {
    int i;
    long val;
    char *next;

    // Process each argument given.

    for (i = 1; i < argc; i++) {
        // Get value with failure detection.

        val = strtol (argv[i], &next, 10);

        // Check for empty string and characters left after conversion.

        if ((next == argv[i]) || (*next != '\0')) {
            printf ("'%s' is not valid\n", argv[i]);
        } else {
            printf ("'%s' gives %ld\n", argv[i], val);
        }
    }

    return 0;
}

运行这个,你可以看到它的操作:

pax> testprog hello "" 42 12.2 77x

'hello' is not valid
'' is not valid
'42' gives 42
'12.2' is not valid
'77x' is not valid

5
@user2131316 你看过 strtol 的文档吗?你知道 C 语言文档的存在吗?在 SO 上询问关于 C 语言的问题之前,你应该对 C 语言有基本的了解。 - Jim Balter
示例:@user2131316 - paxdiablo
1
@Jim,ISO C11 7.21.1.4/7会有不同的看法:如果主题序列为空或不具有预期形式,则不执行转换;只要endptr不是空指针,就将nptr的值存储在所指向的对象中。/3详细说明了此答案中给出的格式要求,数字是必需的。 - paxdiablo
1
如果基数的值在2到36之间(包括2和36),则主题序列的预期形式是一个字母和数字序列,表示具有由基数指定的基数的整数,可选地以加号或减号开头,但不包括整数后缀。 - paxdiablo
没问题,吉姆,我必须进行彻底的检查,因为你的质量通常是无可挑剔的。我会把这归结为 C 语言中稍微晦涩的行为特征之一。 - paxdiablo
显示剩余14条评论

7
使用scanf很容易,以下是一个示例 :
if (scanf("%d", &val_a_tester) == 1) {
    ... // it's an integer
}

3
使用 sscanf 会更好,但这种特定的解决方案无法捕获像 77x 这样的内容。 - paxdiablo
@paxdiablo 是的,它会 http://ideone.com/ObOAVJ ,嗯,我猜这取决于你想要什么结果... - user1944441
1
@paxdiablo 将 char ch; if (sscanf(argv[i], "%d%c", &val_a_tester, &ch) == 1)) { 改为这样会捕获像 77x 这样的东西。 - chux - Reinstate Monica

5
一个自制的解决方案:
bool isNumeric(const char *str) 
{
    while(*str != '\0')
    {
        if(*str < '0' || *str > '9')
            return false;
        str++;
    }
    return true;
}

请注意,此解决方案不应用于生产代码,因为它有严重的局限性。但我喜欢它来理解C-Strings和ASCII


除非您添加一些str++增量,否则它将永远循环。它看起来像C ++,而问题要求使用C。 - Axel Kemper
当我看到自己的帖子时,意识到这一点。while(*(str++) != '\0')也可以工作,对吗? - Marius
我在这里看不到严重的限制,这段代码完全按照广告所述工作。你可以添加一个检查空字符串的条件,但那只是一个微不足道的补充。 - paxdiablo
我猜作者想要检查用户输入。如果我不小心在程序中输入了“5”(注意前导空格),我希望它会忽略空格。此外,这个函数对于“-5”、“+5”和“5.0”也不起作用。 - Marius

2

使用相对简单的代码:

int i;
int value;
int n;
char ch;

/* Skip i==0 because that will be the program name */
for (i=1; i<argc; i++) {
    n = sscanf(argv[i], "%d%c", &value, &ch);

    if (n != 1) {
        /* sscanf didn't find a number to convert, so it wasn't a number */
    }
    else {
        /* It was */
    }
}

2
如果您输入类似于“12ab”的参数,此代码将将其视为数字(11)并忽略尾随的非数字字符“ab”。 - Axel Kemper
@Axel Kemper 和 OP。更改为 char ch; n = sscanf(argv[i], "%d%c", &value, &ch); 可以解决尾随非数字问题。 - chux - Reinstate Monica

0
C库函数int isdigit(int c)用于检查传递的字符是否为十进制数字字符。
#include <stdio.h>
#include <ctype.h>

int main () {
   int var1 = 'h';
   int var2 = '2';
    
   if( isdigit(var1) ) {
      printf("var1 = |%c| is a digit\n", var1 );
   } else {
      printf("var1 = |%c| is not a digit\n", var1 );
   }
   
   if( isdigit(var2) ) {
      printf("var2 = |%c| is a digit\n", var2 );
   } else {
      printf("var2 = |%c| is not a digit\n", var2 );
   }
   
   return(0);
}

结果是:

var1 = |h| is not a digit
var2 = |2| is a digit

0
if (sscanf(command_level[2], "%f%c", &check_f, &check_c)!=1)
{
        is_num=false;
}
else
{
        is_num=true;
}   

if(sscanf(command_level[2],"%f",&check_f) != 1) 
{
    is_num=false;
}

这个怎么样?


0

这对我有效

#include <string.h>

int isNumber(char *n) {

  int i = strlen(n);
  int isnum = (i>0);
  while (i-- && isnum) {
    if (!(n[i] >= '0' && n[i] <= '9')) {
      isnum = 0;
    }
  }
  return isnum;
}

e.g.:

printf("%i\n", isNumber("12"));   // 1
printf("%i\n", isNumber("033"));  // 1
printf("%i\n", isNumber("0"));    // 1
printf("%i\n", isNumber(""));     // 0
printf("%i\n", isNumber("aaa"));  // 0
printf("%i\n", isNumber("\n"));   // 0
printf("%i\n", isNumber("a0\n")); // 0

0

我曾经为此苦苦挣扎,所以我想我应该贡献一下我的意见:

1)创建一个单独的函数来检查 fgets 输入是否完全由数字组成:

int integerCheck(){
char myInput[4];
fgets(myInput, sizeof(myInput), stdin);
    int counter = 0;
    int i;
    for (i=0; myInput[i]!= '\0'; i++){
        if (isalpha(myInput[i]) != 0){
            counter++;
            if(counter > 0){
                printf("Input error: Please try again. \n ");
                return main();
            }
        }

    }
    return atoi(myInput); 
}

上述代码通过循环读取fgets输入的每个单位,直到结束的NULL值。如果它遇到一个字母或操作符,它会将 int“counter”增加1(最初设置为0)。一旦计数器大于0,嵌套的if语句指示循环打印错误消息,然后重新启动程序。当循环完成时,如果int 'counter'仍为0,则返回最初输入的整数以在主函数中使用...

2)主函数应为:

int main(void){
unsigned int numberOne;
unsigned int numberTwo;
numberOne = integerCheck();
numberTwo = integerCheck();
return numberOne*numberTwo;

}

假设两个整数都被正确输入,所提供的示例将产生 int "numberOne" 乘以 int "numberTwo" 的结果。程序将重复执行,直到获得两个正确输入的整数为止。

当调用return main();时,您会不会出现递归? - user9869932

-1

从代码行的角度来看,sscanf()解决方案更好。我在这里的答案是一个用户构建的函数,几乎与sscanf()相同。它将转换后的数字存储在指针中,并返回一个名为“val”的值。如果val为零,则输入格式不受支持,因此转换失败。因此,仅在val为非零时使用指针值。

它仅适用于输入以十进制形式表示的情况。

#include <stdio.h>
#include <string.h>
int CONVERT_3(double* Amt){

    char number[100];

    // Input the Data
    printf("\nPlease enter the amount (integer only)...");
    fgets(number,sizeof(number),stdin);

    // Detection-Conversion begins
    int iters = strlen(number)-2;
    int val = 1;
    int pos;
    double Amount = 0;
    *Amt = 0;
    for(int i = 0 ; i <= iters ; i++ ){
        switch(i){
            case 0:
                if(number[i]=='+'){break;}
                if(number[i]=='-'){val = 2; break;}
                if(number[i]=='.'){val = val + 10; pos = 0; break;}
                if(number[i]=='0'){Amount = 0; break;}
                if(number[i]=='1'){Amount = 1; break;}
                if(number[i]=='2'){Amount = 2; break;}
                if(number[i]=='3'){Amount = 3; break;}
                if(number[i]=='4'){Amount = 4; break;}
                if(number[i]=='5'){Amount = 5; break;}
                if(number[i]=='6'){Amount = 6; break;}
                if(number[i]=='7'){Amount = 7; break;}
                if(number[i]=='8'){Amount = 8; break;}
                if(number[i]=='9'){Amount = 9; break;}
            default:
                switch(number[i]){
                    case '.':
                        val = val + 10;
                        pos = i;
                        break;
                    case '0':
                        Amount = (Amount)*10;
                        break;
                    case '1':
                        Amount = (Amount)*10 + 1;
                        break;
                    case '2':
                        Amount = (Amount)*10 + 2;
                        break;
                    case '3':
                        Amount = (Amount)*10 + 3;
                        break;
                    case '4':
                        Amount = (Amount)*10 + 4;
                        break;
                    case '5':
                        Amount = (Amount)*10 + 5;
                        break;
                    case '6':
                        Amount = (Amount)*10 + 6;
                        break;
                    case '7':
                        Amount = (Amount)*10 + 7;
                        break;
                    case '8':
                        Amount = (Amount)*10 + 8;
                        break;
                    case '9':
                        Amount = (Amount)*10 + 9;
                        break;
                    default:
                        val = 0;
                }
        }
        if( (!val) | (val>20) ){val = 0; break;}// val == 0
    }

    if(val==1){*Amt = Amount;}
    if(val==2){*Amt = 0 - Amount;}
    if(val==11){
        int exp = iters - pos;
        long den = 1;
        for( ; exp-- ; ){
            den = den*10;
        }
        *Amt = Amount/den;
    }
    if(val==12){
        int exp = iters - pos;
        long den = 1;
        for( ; exp-- ; ){
            den = den*10;
        }
        *Amt = 0 - (Amount/den);
    }

    return val;
}


int main(void) {
    double AM = 0;
    int c = CONVERT_3(&AM);
    printf("\n\n%d    %lf\n",c,AM);

    return(0);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接