如何检查字符串是否为数字?

How to check if a string is a number?

提问人:Astinog 提问时间:5/20/2013 更新时间:10/9/2023 访问量:203750

问:

我想检查字符串是否是带有此代码的数字。我必须检查字符串中的所有字符是否都是整数,但 while 返回始终是 isDigit = 1。我不知道为什么如果不起作用。

char tmp[16];
scanf("%s", tmp);

int isDigit = 0;
int j=0;
while(j<strlen(tmp) && isDigit == 0){
  if(tmp[j] > 57 && tmp[j] < 48)
    isDigit = 0;
  else
    isDigit = 1;
  j++;
}
c 字符串

评论

9赞 qwr 5/20/2013
你的范围是错误的,你想要大于 57 和小于 48,这是不可能的
1赞 jxh 7/23/2015
此处的使用很危险,因为输入可能会溢出缓冲区。scanf()tmp

答:

13赞 Arun 5/20/2013 #1
  if(tmp[j] >= '0' && tmp[j] <= '9') // should do the trick
46赞 zoul 5/20/2013 #2

忘记 ASCII 代码检查,使用 或(参见 man isnumber)。第一个函数检查字符是否为 0–9,第二个函数还接受各种其他数字字符,具体取决于当前区域设置。isdigitisnumber

甚至可能有更好的函数来执行检查——重要的教训是,这比看起来要复杂一些,因为“数字字符串”的精确定义取决于特定的语言环境和字符串编码。

评论

0赞 Moo-Juice 5/20/2013
+1.他们可能还需要考虑 and(当然,取决于语言环境)-.
6赞 Sani Huttunen 6/1/2013
isdigit并且是非常好的功能。但是,如果您想确切地学习如何将数字与其他字符区分开来,它们真的很糟糕。学习函数的基础知识,或者更准确地说,函数的工作原理,比学习如何使用函数更重要。对我来说,这个答案是正确的,但从长远来看对 OP 没有任何帮助。他仍然不知道如何区分其他语言中缺少 和 的数字。只有我的 2 美分。isnumberisdigitisnumber
1赞 Valerio 4/9/2023
isnumber() 不是标准的 C
4赞 jxh 5/20/2013 #3

在代码的这一部分中:

if(tmp[j] > 57 && tmp[j] < 48)
  isDigit = 0;
else
  isDigit = 1;

您的条件将始终为 false,导致始终设置为 。您可能想要:ifisDigit1

if(tmp[j] > '9' || tmp[j] < '0')
  isDigit = 0;
else
  isDigit = 1;

但是,这可以简化为:

isDigit = isdigit(tmp[j]);

但是,循环的逻辑似乎有点误导:

int isDigit = 0;
int j=0;
while(j<strlen(tmp) && isDigit == 0){
  isDigit = isdigit(tmp[j]);
  j++;
}

由于不是一个常量,因此不确定编译器是否会优化每次迭代的长度计算。tmp

正如@andlrc在评论中建议的那样,您可以只检查数字,因为终止的 NUL 无论如何都会无法通过检查。

while (isdigit(tmp[j])) ++j;

评论

0赞 Andreas Louv 6/9/2017
for (char *ptmp = tmp; isdigit(*ptmp); ptmp++);可能会更好。
0赞 jxh 10/28/2019
@andlrc:是的,这是利用返回 false for 的。isdigit()'\0'
0赞 Sani Huttunen 5/20/2013 #4

您的病情表明。 不能同时大于 57 和小于 48。if X is greater than 57 AND smaller than 48X

if(tmp[j] > 57 && tmp[j] < 48)

它应该是:if X is greater than 57 OR smaller than 48

if(tmp[j] > 57 || tmp[j] < 48)
2赞 Mitchell Griest 3/11/2016 #5

我需要为我目前正在从事的项目做同样的事情。以下是我解决问题的方法:

/* Prompt user for input */
printf("Enter a number: ");

/* Read user input */
char input[255]; //Of course, you can choose a different input size
fgets(input, sizeof(input), stdin);

/* Strip trailing newline */
size_t ln = strlen(input) - 1;
if( input[ln] == '\n' ) input[ln] = '\0';

/* Ensure that input is a number */
for( size_t i = 0; i < ln; i++){
    if( !isdigit(input[i]) ){
        fprintf(stderr, "%c is not a number. Try again.\n", input[i]);
        getInput(); //Assuming this is the name of the function you are using
        return;
    }
}

评论

0赞 chqrlie 10/8/2023
此方法不检测空字符串,并拒绝负数。
8赞 Dennis V 6/9/2017 #6

更明显和简单的线程安全示例:

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

int main(int argc, char **argv)
{
    if (argc < 2){
        printf ("Dont' forget to pass arguments!\n");
        return(-1);
    }

    printf ("You have executed the program : %s\n", argv[0]);

    for(int i = 1; i < argc; i++){
        if(strcmp(argv[i],"--some_definite_parameter") == 0){
            printf("You have passed some definite parameter as an argument. And it is \"%s\".\n",argv[i]);
        }
        else if(strspn(argv[i], "0123456789") == strlen(argv[i])) {
            size_t big_digit = 0;
            sscanf(argv[i], "%zu%*c",&big_digit);
            printf("Your %d'nd argument contains only digits, and it is a number \"%zu\".\n",i,big_digit);
        }
        else if(strspn(argv[i], "0123456789abcdefghijklmnopqrstuvwxyz./") == strlen(argv[i]))
        {
            printf("%s - this string might contain digits, small letters and path symbols. It could be used for passing a file name or a path, for example.\n",argv[i]);
        }
        else if(strspn(argv[i], "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(argv[i]))
        {
            printf("The string \"%s\" contains only capital letters.\n",argv[i]);
        }
    }
}

评论

1赞 Dennis V 10/15/2018
谢谢,@Gerhardh。你是对的。我的错 - 复制粘贴错误。
0赞 Param Siddharth 5/20/2020
我喜欢这种识别数字字符串的方法。布里兰特!
0赞 chqrlie 10/8/2023
此方法不适用于 或 。"-1"""
0赞 Dennis V 10/11/2023
@chqrlie 如何将“”作为CLI的参数传递?
1赞 chqrlie 10/11/2023
@DennisV:空字符串不能通过输入,但不是问题,因为命令行参数:在 shell 提示符下键入,两者都将是空字符串。scanf("%s",...)./myprogram "" ''argv[1]argv[2]
3赞 harvin 9/30/2019 #7
if ( strlen(str) == strlen( itoa(atoi(str)) ) ) {
    //its an integer
}

由于 atoi 将字符串转换为数字以外的数字跳跃字母,如果只有数字,则其字符串长度必须与原始字符串相同。 如果检查是针对整数的,则此解决方案比 innumber() 更好。

评论

0赞 TDiblik 3/6/2022
你好!刚刚遇到你的裤子,我正在学习 C,所以这可能是一个愚蠢的问题,但我有一个程序,我将数据 malloc 放入数组 () 中。然后我读值到这个分配的数组位置 () 中,然后我尝试像这样使用您的代码:(),但是我收到以下错误: .正如我之前所说,我是这个东西的新手,所以这可能很明显,但我不知道如何解决它:/。你能向我解释一下吗?char *array[4]; array[0] = (char*)malloc(10);scanf("%s", array[0]);strlen(array[0]) == strlen( itoa(atoi(array[0])) )error: too few arguments to function 'itoa'
1赞 Mehdi Charife 3/26/2023
或者,您可以改用。strcmp
0赞 Valerio 4/9/2023
itoa() 不是标准的 C,你可以改用 printf()
0赞 chqrlie 10/8/2023
这种方法不适用于 。"a"
4赞 Marcelo 10/28/2019 #8
#include "stdbool.h"
#include "stddef.h"
bool isNumber(char const* const text) {
    if (text == NULL || text[0] == '\0') {
        return false;
    }

    int dot_counter = 0;
    size_t length = 1;
    for (char character = text[1]; character != '\0';
         ++length, character = text[length]) {
        bool const is_valid_character =
            (character >= '0' && character <= '9') ||
            (character == '.' && ++dot_counter == 1);

        if (is_valid_character == false) {
            return false;
        }
    }

    char const first_character = text[0];
    bool is_character_sign = (first_character == '-' || first_character == '+');
    // verifications for first left character
    if ((is_character_sign || first_character == '.') && length == 1) {
        return false;
    }
    if (length == 2 && is_character_sign && text[1] == '.') {
        return false;
    }
    return (is_character_sign || first_character == '.') ||
           (first_character >= '0' && first_character <= '9');
}

#include <assert.h>
int main() {
    char tmp[16];
    assert(isNumber("a") == false);
    assert(isNumber("aa") == false);
    assert(isNumber("1"));
    assert(isNumber("11"));
    assert(isNumber("+1"));
    assert(isNumber("+1.") && +1. == 1.0);
    assert(isNumber("+.0") && +.0 == 0.0);
    assert(isNumber("-1"));
    assert(isNumber("-.0") && -.0 == -0.0);
    assert(isNumber("-1.") && -1. == -1.0);
    assert(isNumber("1.") && 1. == 1.0);
    assert(isNumber(".0") && .0 == 0.0);
    assert(isNumber(".") == false);
    assert(isNumber("-") == false);
    assert(isNumber("+") == false);
    assert(isNumber("+.") == false);
    assert(isNumber(".+") == false);
    assert(isNumber("-.") == false);
    assert(isNumber(".-") == false);
    assert(isNumber("") == false);
    assert(isNumber("1.1"));
    assert(isNumber("-1.1"));
    assert(isNumber("\0") == false);
    assert(isNumber(NULL) == false);

    return 0;
}

https://godbolt.org/z/YdnM6TKaz

评论

0赞 Observer 8/5/2021
检查“\n”和“\r”可能很有用
0赞 chqrlie 10/8/2023
一些问题:应该返回,应该返回isNumber("-1")trueisNumber("")false
0赞 chqrlie 10/9/2023
更多备注:并且应该有类型,但下循环必须写得更仔细。 如果为 ,则具有未定义的行为。lengthisize_tchar character = text[length - 1];length0
1赞 Marcelo 10/9/2023
@chqrlie,代码改进。
0赞 chqrlie 10/9/2023
代码似乎有效,但可以大大简化。查看 stackoverflow.com/a/77255444/4593267
0赞 LinconFive 9/27/2020 #9

重写整个函数,如下所示:

bool IsValidNumber(char * string)
{
   for(int i = 0; i < strlen( string ); i ++)
   {
      //ASCII value of 0 = 48, 9 = 57. So if value is outside of numeric range then fail
      //Checking for negative sign "-" could be added: ASCII value 45.
      if (string[i] < 48 || string[i] > 57)
         return FALSE;
   }

   return TRUE;
}

评论

3赞 Gerhardh 9/27/2020
切勿在代码中使用幻数。特别是如果它们完全没有必要。代替使用等。此外,在循环的每次迭代中调用都会导致额外的执行时间。您应该在循环之前移动该调用。48'0'strlen
0赞 chqrlie 10/8/2023
更多问题:应该返回并且应该返回IsValidNumber("-1")trueIsValidNumber("")false
0赞 Fabio Vaz 11/7/2020 #10

问题在于您的代码“isDigit”的结果仅反映最后一个数字测试。据我了解,只要字符串中有任何字符不是数字,您就希望返回 isDigit = 0。按照你的逻辑,你应该像这样编码它:

char tmp[16];
scanf("%s", tmp);

int isDigit = 0;
int j=0;
isDigit = 1;  /* Initialised it here */
while(j<strlen(tmp) && isDigit == 0){
  if(tmp[j] > 57 || tmp[j] < 48) /* changed it to OR || */
    isDigit = 0;
  j++;
}

为了获得更易于理解的代码,我还会更改测试:

if(tmp[j] > 57 || tmp[j] < 48) 

到以下内容:

if(tmp[j] > '9' || tmp[j] < '0')

评论

0赞 chqrlie 10/8/2023
要报告的更多问题: -> 和scanf("%s", tmp)scanf("%15s", tmp)&& isDigit == 0 -> && isDigit != 0
1赞 user15651507 11/17/2021 #11

这些都不能适当地处理负数或浮点数。

怎么样:

bool
is_realnumber(char *instring) {
  if (*instring != '-' && *instring != '.' && !isdigit(*instring)) return false;
  if (strspn(instring+1, "0123456789.") < strlen(instring+1)) return false;
  int c = 0;
  while (*instring) if (*instring++ == '.') if (++c > 1) return false;
  return true;
}

评论

0赞 chqrlie 10/8/2023
一些问题:应该返回。,并应返回is_realnumber("+1")trueis_realnumber(".")is_realnumber("-")is_realnumber("-.")false
1赞 user13305144 12/9/2021 #12

我还可以扩展 Marcelo 支持浮点数的答案,如下所示:

char isnumber(const char *str)
{
     int decpos = -1, pmpos = -1, engpos = strlen(str) - 1, epmpos = strlen(str) - 1;
  for (int i = 0; i < strlen(str); i++)
    /* check if it is integer */
    if (str[i] > 47 && str[i] < 58)
      continue;
    /* check if it is decimal seperator and used once*/
    else if (str[i] == 46 && decpos == -1)
    {
      decpos = i;
      continue;
    }
    /* check if it is +/-, at the begining*/
    else if ((str[i] == 43 || str[i] == 45) && i == 0)
    {
      pmpos = 1;
      continue;
    }
    /* check if it is engineering format e/E, used once, after decimal and before +/-*/
    else if ((str[i] == 69 || str[i] == 101) && engpos == strlen(str) - 1 && i > 0 && i > decpos && i < epmpos)
    {
      engpos = 1;
      continue;
    }
    /* check if it is engineering format +/-, used once, after decimal and after engineering e/E*/
    else if ((str[i] == 43 || str[i] == 45) && epmpos == strlen(str) - 1 && i > 0 && i > decpos && i > engpos)
    {
      epmpos = 1;
      continue;
    }
    else
      return 0;
  return 1;
}
1赞 Daniele Affinita 7/17/2022 #13

您可以按如下方式实现该函数:

bool isNumeric(const char* s){
    while(*s){
        if(*s < '0' || *s > '9')
            return false;
        ++s;
    }
    return true;
}

评论

1赞 Maf 7/21/2022
您也可以返回查看最佳实践。bool
1赞 Daniele Affinita 7/21/2022
@Maf你是对的!更新:)
0赞 chqrlie 10/8/2023
至少应该有一个数字:因为发布会错误地返回。也应该返回,但没有。isNumeric("")trueisNumeric("-1")true
0赞 david euler 9/12/2022 #14

可以通过 isdigit() 检查每个字符。

#include <string.h>
#include <ctype.h>

int is_digit_str(char* str){
    int digit_count = 0;
    for (int i = 0; i < strlen(str); i++) {
      if(isdigit(str[i]))
         digit_count++;
      else
         break;
    }

    return digit_count == strlen(str);
}

评论

0赞 chqrlie 10/8/2023
至少应该有一个数字:因为发布会错误地返回。也应该返回,但没有。is_digit_str("")1is_digit_str("-1")1
1赞 Simon Leary 11/7/2022 #15

如果您打算将来以整数/长格式使用该数字,您将调用或无论如何,在这种情况下,您可能只想检查返回值。atoiatol

char tmp[16];
scanf("%s", tmp); // unsafe!!!
long tmp_long = atol(&tmp);
if (tmp_long == 0){
    printf("%s: is not a number.\n", &tmp);
}

教程Point on atol

评论

1赞 chqrlie 10/8/2023
按照这个逻辑,不会被认为是一个数字。"0"
-1赞 Ali Hashemian 1/5/2023 #16
int being_number(char string[]){
int l=strlen(string);
for (int i = 0; i < l; i++)
{
    if(string[i] >= '0' && string[i] <= '9'){
        i=i; 
    }
    else{
        return(0);
    }
}
return(1);    

}

评论

3赞 Blastfurnace 1/6/2023
i=i;?真?当然,你可以想到比这更不古怪的东西。
0赞 chqrlie 10/8/2023
至少应该有一个数字:因为发布会错误地返回。也应该返回.being_number("")truebeing_number("-1")1
0赞 Pit 3/11/2023 #17

嗨,您可以使用此方法,它使用您从包含 ctype.h 库中获得的 isdigit() 函数。

这段代码检查 isdigit() 的返回值是否为零(这意味着我们正在分析的字符是非数字),如果是,则递增 j。

逻辑使用 j 变量作为“操作码”:如果不等于零,则它已递增,因此,函数会遇到非数字字符,否则字符串中存在的每个字符都是一个数字。

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

int main(int argc, char *argv[])
{
  int i = 0;
  int j = 0;
  char data[] = "1234t6789";
  int check;

  while(data[i] != '\0'){
    if((check = isdigit(data[i])) == 0)
      j++;
    i++;
  }

  if(j != 0)
    printf("The string doesn't contain just numbers.\n");
  else printf("The string contains only numbers.\n");
  
  return 0;
}
-1赞 Ifedayo Prince Oni 10/8/2023 #18

这是最简单的答案:

bool isnumber(char string[]) {
    int len = strlen(string);
    int i = 0;
    while (i < len)
    {
            if (isdigit(string[i]) == 0)
                    return false;

            i++;
    }

    return true; }

评论

1赞 chqrlie 10/8/2023
应将参数强制转换为 as,以避免在有符号类型的平台上对负值进行未定义的行为。charisdigit()(unsigned char)charchar
0赞 chqrlie 10/8/2023
您应该接受首字母或符号。'+''-'
0赞 chqrlie 10/8/2023
i并且应该有类型,参数应该定义为 或 。lensize_tstringconst char string[]const char *string
0赞 chqrlie 10/8/2023
至少应该有一个数字:因为发布会错误地返回。isnumber("")true
0赞 Toby Speight 10/13/2023
这不是最简单的答案。而且它不需要在字符串上做两次传递。并且您正在将可能签名传递给函数。char<ctype.h>
0赞 chqrlie 10/9/2023 #19

下面是一个简单的自包含函数,用于验证字符串是否表示带有可选符号、至少一位数字和可选小数点的数字:

int isNumber(const char *str) {
    size_t index = 0;
    int has_digits = 0, has_dot = 0;
    char cc;

    // reject null pointer
    if (!str) {
        return 0;
    }
    // skip optional sign
    if (*str == '+' || *str == '-') {
        index++;
    }
    // scan the string
    while ((cc = str[index++]) != '\0') {
        if (cc == '.') {
            // accept a single decimal point
            if (has_dot++)
                return 0;
        } else
        if (cc >= '0' && cc <= '9') {
            // we have at least one digit
            has_digits = 1;
        } else {
            // reject all other characters
            return 0;
        }
    }
    // must have at least one digit
    return has_digits;
}