把用空格分隔的数字到一个数组 [英] Putting numbers separated by a space into an array
问题描述
我想有一个用户输入一个空格分隔的数字,然后每个值存储为一个数组的元素。目前,我有:
I want to have a user enter numbers separated by a space and then store each value as an element of an array. Currently I have:
while ((c = getchar()) != '\n')
{
if (c != ' ')
arr[i++] = c - '0';
}
不过,当然,这个存储一个每个元素的数字。
but, of course, this stores one digit per element.
如果用户是键入:
10 567 92 3
我想10存储在改编[0]
,然后567 改编[1] $ C $价值C>等。
我应该使用 scanf函数
而不是以某种方式?
Should I be using scanf
instead somehow?
推荐答案
有几种方法,这取决于您希望如何健壮的code是。
There are several approaches, depending on how robust you want the code to be.
最简单的就是使用 scanf函数
与%d个
转换说明:
The most straightforward is to use scanf
with the %d
conversion specifier:
while (scanf("%d", &a[i++]) == 1)
/* empty loop */ ;
的%d个
转换符告诉 scanf函数
来跳过任何前导空格和读取到下一个非数字字符。返回值是成功转换和分配的数量。由于我们正在阅读一个整数值,则返回值应该是1成功。
The %d
conversion specifier tells scanf
to skip over any leading whitespace and read up to the next non-digit character. The return value is the number of successful conversions and assignments. Since we're reading a single integer value, the return value should be 1 on success.
由于写的,这有一些陷阱。首先,假设你的用户输入更多的数字比你的数组的大小持有;如果你幸运的话,你会立即收到一条访问冲突。如果你没有,你会风重挫重要的事以后会引起问题(缓冲区溢出是一种常见的恶意软件攻击)。
As written, this has a number of pitfalls. First, suppose your user enters more numbers than your array is sized to hold; if you're lucky you'll get an access violation immediately. If you're not, you'll wind up clobbering something important that will cause problems later (buffer overflows are a common malware exploit).
所以,你至少要添加code,以确保你不走过去的数组的末尾:
So you at least want to add code to make sure you don't go past the end of your array:
while (i < ARRAY_SIZE && scanf("%d", &a[i++]) == 1)
/* empty loop */;
好为止。但现在假设您的用户fatfingers一个非数字字符在他们的输入,如 12 3r5 67
。按照规定,循环将分配 12
到 A [0]
, 3
为 A [1]
,那么将看到研究
输入流中,返回0,不保存任何退出A [2]
。这里就是一个微妙的错误毛骨悚然的 - 即使没有被分配到 A [2]
,前pression 我++
仍然得到评估,因此,您的认为的您分配东西<code> A [2] 即使它包含一个垃圾值。所以,你可能要推迟递增 I
,直到你知道你有一个成功读取:
Good so far. But now suppose your user fatfingers a non-numeric character in their input, like 12 3r5 67
. As written, the loop will assign 12
to a[0]
, 3
to a[1]
, then it will see the r
in the input stream, return 0 and exit without saving anything to a[2]
. Here's where a subtle bug creeps in -- even though nothing gets assigned to a[2]
, the expression i++
still gets evaluated, so you'll think you assigned something to a[2]
even though it contains a garbage value. So you might want to hold off on incrementing i
until you know you had a successful read:
while (i < ARRAY_SIZE && scanf("%d", &a[i]) == 1)
i++;
在理想情况下,你想拒绝 3r5
干脆。我们可以读出的字符立即数以下,并确保它是空白;如果它不是,我们拒绝输入:
Ideally, you'd like to reject 3r5
altogether. We can read the character immediately following the number and make sure it's whitespace; if it's not, we reject the input:
#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;
}
}
如果我们得到两个成功的转换,我们确保遵循
是一个空白字符 - 如果不是这样,我们打印错误,并退出循环。如果我们得到1成功转换,这意味着有下面输入的号码没有字符(这意味着我们的数字输入后打EOF)。
If we get two successful conversions, we make sure follow
is a whitespace character - if it isn't, we print an error and exit the loop. If we get 1 successful conversion, that means there were no characters following the input number (meaning we hit EOF after the numeric input).
另外,我们可以看到每个输入值的文本,并使用与strtol
来进行转换,这也可以让你赶上同一类问题(我的preferred法):
Alternately, we can read each input value as text and use strtol
to do the conversion, which also allows you to catch the same kind of problem (my preferred method):
#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;
}
}
的别急,还有更多!的
假设你的用户是谁喜欢在你的code只是为了看看会发生什么,进入一个像扔厌恶那些输入扭曲QA类型之一<$c$c>123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890$c$c>这是的显然的过大,以适应任何标准的整数类型。信不信由你, scanf函数(%d个,&放大器; VAL)
不会牦牛这一点,并且将结束存储的的东西到 VAL
,但同样是你可能想直接拒绝输入。
Suppose your user is one of those twisted QA types who likes to throw obnoxious input at your code "just to see what happens" and enters a number like 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
which is obviously too large to fit into any of the standard integer types. Believe it or not, scanf("%d", &val)
will not yak on this, and will wind up storing something to val
, but again it's an input you'd probably like to reject outright.
如果你只允许每行一个值,这成为比较容易防范; 与fgets
将换行符存储到目标缓冲区,如果有足够的空间,因此,如果我们看不到输入缓冲区换行符,那么用户输入的东西是超过我们再prepared处理:
If you only allow one value per line, this becomes relatively easy to guard against; fgets
will store a newline character in the target buffer if there's room, so if we don't see a newline character in the input buffer then the user typed something that's longer than we're prepared to handle:
#include <string.h>
...
while (i < ARRAY_SIZE && fgets(buf, sizeof 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, sizeof buf, stdin) != NULL)
newline = strchr(buf, '\n');
break;
}
...
}
如果你想允许每行多个值,如'10 20 30',那么这个有点难度。我们可以回到从输入读取单个字符,并在每一个(警告,未经测试)做一个全面的检查:
If you want to allow multiple values per line such as '10 20 30', then this gets a bit harder. We could go back to reading individual characters from the input, and doing a sanity check on each (warning, untested):
...
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.
Welcome to the wonderfully whacked-up world of interactive input in C.
这篇关于把用空格分隔的数字到一个数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!