在C中进行整数检查时出现意外行为



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

#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()函数在没有库的情况下如何工作?(我在ubuntu 14.04上使用gcc 4.9.3)

  2. 如果我强制str是一个长度为3的字符串,那么当我运行./a.out时,它怎么可能正确检查并打印大于999的数字?如果我输入5678,str不应该只保存567吗?或者它可以保存前2^3个数字?我很困惑

  3. 如果我想检查一个字符串是否是正整数,但数字可能很大,那么str应该有多大?难道没有办法把它做成需要的那么大吗?

  1. 头文件不是库;它只说明如何使用图书馆。如果省略了头文件,那么编译器将不得不猜测函数的参数,但如果猜测正确(或足够接近),那么所有函数都可能正常工作。(事实上,这并不是"猜测";当然,这是有规则的。)

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

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

关于第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] = '';
  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;
}

相关内容

  • 没有找到相关文章

最新更新