C中整数检查的意外行为

时间:2016-07-19 10:24:40

标签: c string integer type-conversion

这是我写的,以检查输入是否为正整数

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

int isInt(char num[3]) {
    int l = strlen(num);
    int x;

    for ( x = 0; x < l; x++) {
        if ( ! isdigit(num[x]) )
            return 0;        
    }

    return 1;
}

int main(void) {
    int i;
    char str[3];

    printf("Enter a positive integer: ");
    scanf("%s", str);
    if ( isInt(str) == 1 ) {
        i = atoi(str);
        printf("%d \n", i);
    } else {
        printf("This is not a positive integer! \n");
    }

    return 0;
}

我发现了一些意想不到的行为,即使程序似乎有效:

  1. 无论我#include <ctype.h>与否,它都没有区别。 isdigit()如何在没有库的情况下运行? (我使用gcc 4.9.3在ubuntu 14.04上)

  2. 如果我将str强加为长度为3的字符串,当我运行./a.out时,它是否可以正确检查并打印大于999的数字?如果我输入5678不应str仅保存567?或者它可以保存前2 ^ 3位数?我很困惑

  3. 如果我想检查字符串是否为正整数但数字可能非常大,str应该有多大?难道没有办法让它变得如此大吗?

2 个答案:

答案 0 :(得分:2)

  1. 头文件不是库;它只说如何使用库。如果省略头文件,那么编译器将不得不猜测函数所采用的参数,但如果它猜对了(或者足够接近)那么所有参数都可以正常工作。 (实际上它没有&#34;猜测&#34 ;;当然有规则。)

  2. 你没有&#34;强加&#34;限制str的长度,保留3个字节的空间。如果您超出该预订,则程序可能(或可能不)继续正常工作,但您可能会发现其他数据已意外损坏。没有可靠的方法来预测哪些数据会被覆盖;它没有定义。

  3. 不,在用户输入数字之前无法知道数字的大小,但您可以使用%3s设置将读取的最大字符数,例如。但是,您需要确保为字符串末尾的'\0'空字符终止符保留足够的空间。您还可以使用scanf的替代方法来读取数据块中的数据,但您可能最安全的只是使用&#34; large&#34;缓冲区和最大字段宽度。请注意,scanf可以直接读取数字,而无需将其作为字符串读取,然后自行转换。

答案 1 :(得分:1)

关于第3点:

不,没有办法提前知道。

但是,很容易创建一个以较小的部分读取输入并将它们连接成一个大缓冲区的函数。大缓冲区将动态分配,以便在需要时增长。用户必须免费拨打电话。

这是一个实现:

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

#define INCREMENT_SIZE 20
#define SMALL_SIZE 10

char* read_long_string(void)
{
  char* all;
  char* tmp;
  int all_size;
  char some[SMALL_SIZE];

  all_size = INCREMENT_SIZE;
  all = malloc(all_size);
  if (!all)
  {
    // Out of mem
    return NULL;
  }
  all[0] = '\0';

  while(1)
  {
    // Make sure "all" has room for all bytes in "some"
    while(all_size - strlen(all) < sizeof(some))
    {
      all_size += INCREMENT_SIZE;
      tmp = realloc(all, all_size);  // Allocate more memory
      if (!tmp)
      {
        // Out of mem
        free(all);
        return NULL;
      }
      all = tmp;
    }

    // Read bytes into "some"
    if (!fgets(some, sizeof(some), stdin))
    {
      // Error
      free(all);
      return NULL;
    }

    if (strlen(some) > 0)
    {
      // Add the bytes to "all"
      strcat(all, some);

      // Check if newline has been pressed
      if (some[strlen(some)-1] == '\n')
      {
        // done
        return all;
      }

    }
  }
}


int main(int argc, char const *argv[])
{
  char* s;

  printf("Enter a positive integer:\n");
  s = read_long_string();
  if (s) printf("%s", s);

  free(s);

  return 0;
}