将由空格分隔的数字放入数组

前端之家收集整理的这篇文章主要介绍了将由空格分隔的数字放入数组前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我想让用户输入由空格分隔的数字,然后将每个值作为数组的元素存储.目前我有:
while ((c = getchar()) != '\n')
{
    if (c != ' ')
        arr[i++] = c - '0'; 
}

但是,当然,这存储每个元素一个数字.

如果用户要输入:

10 567 92 3

我想要将值10存储在arr [0]中,然后在arr [1]等中存储567.

我应该使用scanf吗?

解决方法

有几种方法,具体取决于您希望代码的稳健性.

最直接的是使用scanf与%d转换说明符:

while (scanf("%d",&a[i++]) == 1)
  /* empty loop */ ;

%d转换说明符告诉scanf跳过任何前导的空格并读取到下一个非数字字符.返回值是转换和分配成功的次数.由于我们正在读取一个整数值,所以成功返回值应为1.

正如书面的,这有一些陷阱.首先,假设您的用户输入的数字大于数组的大小,以保持;如果你很幸运,你会立即获得访问冲突.如果不这样做,那么你会发现一些重要的东西会在以后引起问题(缓冲区溢出是常见的恶意软件漏洞).

所以你至少要添加代码,以确保不要超过数组的末尾:

while (i < ARRAY_SIZE && scanf("%d",&a[i++]) == 1)
  /* empty loop */;

目前很好.但现在假设您的用户在其输入中输入非数字字符,例如12 3r5 67.如所写,循环将分配12到[0],3到a [1],然后它将在输入中看到r流,返回0并退出而不保存任何东西到[2].这里是一个微妙的bug蠕虫 – 即使没有任何东西被分配到一个[2],表达式我仍然被评估,所以你会认为你分配了一个[2],即使它包含垃圾值.所以你可能希望在增加我的时候,直到你知道你读了一个成功:

while (i < ARRAY_SIZE && scanf("%d",&a[i]) == 1)
  i++;

理想情况下,您想完全拒绝3r5.我们可以在数字后面仔细阅读字符,并确保它是空格;如果不是,我们拒绝输入:

#include <ctype.h>
...
int tmp;
char follow;
int count;
...
while (i < ARRAY_SIZE && (count = scanf("%d%c",&tmp,&follow)) > 0)
{
  if (count == 2 && isspace(follow) || count == 1)
  {
    a[i++] = tmp;
  }
  else
  {
    printf ("Bad character detected: %c\n",follow);
    break;
  }
}

如果我们得到两个成功的转换,我们确保遵循一个空白字符 – 如果不是,我们打印错误退出循环.如果我们得到一个成功的转换,那意味着输入号后没有字符(意味着我们在数字输入后打到EOF).

或者,我们可以读取每个输入值作为文本,并使用strtol进行转换,这也允许您捕获同样的问题(我的首选方法):

#include <ctype.h>
#include <stdlib.h>
...
char buf[INT_DIGITS + 3]; // account for sign character,newline,and 0 terminator
...
while(i < ARRAY_SIZE && fgets(buf,sizeof buf,stdin) != NULL)
{
  char *follow; // note that follow is a pointer to char in this case
  int val = (int) strtol(buf,&follow,10);
  if (isspace(*follow) || *follow == 0)
  {
    a[i++] = val;
  }
  else
  {
    printf("%s is not a valid integer string; exiting...\n",buf);
    break;
  }
}

但等待更多!

假设你的用户是谁喜欢在代码中引发厌恶那些输入扭曲QA类型之一“只是为了看看会发生什么”,并进入了一些像123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890这显然是太大,以适应任何标准的整数类型.相信与否,scanf(“%d”,&val)将不会这样做,并且会将某些东西储存起来,但再次是您可能希望拒绝的输入.

如果你每行只允许一个值,这样就可以很容易地防范;如果有空格,则fgets将在目标缓冲区中存储一个换行字符,所以如果输入缓冲区中没有看到换行符,那么用户键入的内容比我们准备处理的更长一些:

#include <string.h>
...
while (i < ARRAY_SIZE && fgets(buf,stdin) != NULL)
{
  char *newline = strchr(buf,'\n');
  if (!newline)
  {
    printf("Input value too long\n");
    /**
     * Read until we see a newline or EOF to clear out the input stream
     */
    while (!newline && fgets(buf,stdin) != NULL)
      newline = strchr(buf,'\n');
    break;
  }
  ...
}

如果要允许每行多个值,例如’10 20 30′,那么这会变得更困难.我们可以返回从输入中读取单个角色,并对每个角色进行理智检查(警告,未经测试):

...
while (i < ARRAY_SIZE)
{
  size_t j = 0;
  int c;

  while (j < sizeof buf - 1 && (c = getchar()) != EOF) && isdigit(c))
    buf[j++] = c;
  buf[j] = 0;

  if (isdigit(c))
  { 
    printf("Input too long to handle\n");
    while ((c = getchar()) != EOF && c != '\n')   // clear out input stream
      /* empty loop */ ;
    break;
  }
  else if (!isspace(c))
  {
    if (isgraph(c)
      printf("Non-digit character %c seen in numeric input\n",c);
    else
      printf("Non-digit character %o seen in numeric input\n",c);

    while ((c = getchar()) != EOF && c != '\n')  // clear out input stream
      /* empty loop */
    break;
  }
  else
    a[i++] = (int) strtol(buffer,NULL,10); // no need for follow pointer,// since we've already checked
                                             // for non-digit characters.
}

欢迎来到C的奇妙的交互式输入世界

猜你在找的C&C++相关文章