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

我想让用户输入由空格分隔的数字,然后将每个值存储为数组的元素。 目前我有:

while ((c = getchar()) != '\n') { if (c != ' ') arr[i++] = c - '0'; } 

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

如果用户要键入:

 10 567 92 3 

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

我应该以某种方式使用scanf吗?

有几种方法,取决于您希望代码的强大程度。

最简单的方法是使用带有%d转换说明符的scanf

 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分配给a[0]3分配a[1] ,然后它将在输入流中看到r ,返回0并退出而不保存任何内容到a[2] 。 这里是一个微妙的bug进入的地方 - 即使没有任何东西被分配给a[2] ,表达式i++仍然会被评估,所以你会认为a[2]分配了一些内容,即使它包含一个垃圾值。 因此,您可能希望延迟增加i直到您知道自己已成功阅读:

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

理想情况下,你想完全拒绝3r5 。 我们可以在数字后面立即读取字符,并确保它是空格; 如果不是,我们拒绝输入:

 #include  ... 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; } } 

如果我们得到两次成功的转换,我们确保follow是一个空格字符 - 如果不是,我们打印错误并退出循环。 如果我们获得1次成功转换,则表示输入数字后面没有字符(意味着我们在数字输入后点击了EOF)。

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

 #include  #include  ... 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)不会在这上面牦牛,并且最终会把东西存放到val ,但这又是你可能想要完全拒绝的输入。

如果每行只允许一个值,这就相对容易防范; 如果有空间, fgets会在目标缓冲区中存储换行符,所以如果我们在输入缓冲区中没有看到换行符,那么用户输入的内容比我们准备处理的时间长:

 #include  ... 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',那么这会变得有点困难。 我们可以回去从输入中读取单个字符,并对每个字符进行完整性检查(警告,未经测试):

 ... 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中令人惊叹的交互式输入世界。

对代码的小改动:只在读取空间时增加i

 while ((c = getchar()) != '\n') { if (c != ' ') arr[i] = arr[i] * 10 + c - '0'; else i++; } 

当然,最好使用scanf

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

假设您在arrays中有足够的空间。 另外,请注意上面的时间结束; ,一切都在循环条件下完成。

事实上,应检查每个返回值。

这将工作..

 #include void main() { int i=0,j,arr[100]; while(scanf("%d",&arr[i])!=-1) { i++; } for(j=0;j