检查 C 中的标准输入管道是否为空
Check if stdin pipe is empty in C
我正在使用用户输入来填充二维数组。用户在一行中输入数字,然后我使用嵌套循环来填充数组,如下所示:
//User inputs: "1 2 3 4 5"
for(i = 0; i < r; i++){
for(j = 0; j < c; j++){
scanf("%d", &arr[i][j]);
}
}
但是,问题是如果用户在有 6 个整数的空间时输入 5 个整数,它只会等待另一个输入。如何检测数量不足?
我试过用这个但是没用:
for(i = 0; i < r; i++){
for(j = 0; j < c; j++){
if (!feof(stdin)){
scanf("%d", &arr[i][j]);
}
else{
printf("insufficient datapoints\n");
}
}
}
您可以在流中使用 peek ahead 并在实际使用字符之前测试字符。 (好吧,在 c 中)。
您可以使用它来忽略空格(您需要这样做)。
您还可以使用此查看值来指示输入的字符是否不足。
需要在实际读取 (scanf) 之前完成查看。
在下面添加了粗略的示例代码
#include <stdio.h>
#include <ctype.h>
int r=3;
int c=2;
int arr[100][100]; // FIX magic
int main(int argc, char** argv[]) {
for(int i=0; i<r; i++) {
for(int j=0; j<c; j++) {
if (feof(stdin)) {
// error check and error / normal exit etc.
printf("eof\n");
}
char c=getchar();
if (c=='\n') {
// error check and error / normal exit here
printf("newline\n");
} else if (isspace(c)) {
// advance and remove them - watch for end of stream when winding
printf("advance and discard whiitespace\n");
} else { // add check for isdigit
// push back
ungetc(c, stdin);
printf("ungetc\n");
}
scanf("%d", &arr[i][j]);
printf("got %d\n", arr[i][j]);
}
}
return 0;
}
实现目标的一种方法是使用 fgets()
而不是 scanf()
一次读取一行输入。然后可以用strtok()
把输入的行打断成token,用strtol()
把token解析成数字。与scanf()
相比,使用fgets
处理非结构化用户输入要容易得多。
下面的代码就是这样做的。如果输入行中的元素太多、元素太少,或者如果其中一个元素不是有效数字,则会打印一条消息并且必须重新输入该行。
由于每一行都是由用户输入的,因此strtok()
用于将行分成标记。令牌定界符列表存储在 delims[]
中。请注意,标记可以用空格或制表符分隔;分隔符本身不是标记的一部分,因此包含 \r
和 \n
可确保这些字符不会成为一行中最终标记的一部分。
找到标记后,如果可能,strtol()
用于将其转换为整数。在调用 strtol()
之后,指针 tail
指向令牌中不属于数字的第一个字符;如果 tail
指向 NUL
终止符,则整个字符串被解析为数字,否则输入被认为是错误的,必须重新输入该行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 1000
int main(void)
{
size_t r = 3;
size_t c = 5;
size_t i, j;
char buffer[BUF_SIZE];
char *token;
char *tail;
const char delims[] = " \t\r\n";
int arr[r][c];
int temp_val;
printf("Enter rows of %zu data elements:\n", c);
for(i = 0; i < r; i++){
j = 0;
if (fgets(buffer, BUF_SIZE, stdin) == NULL) {
perror("Error in fgets()");
exit(EXIT_FAILURE);
}
token = strtok(buffer, delims);
while (token != NULL) {
temp_val = strtol(token, &tail, 10);
if (*tail == '[=10=]') {
arr[i][j] = temp_val;
++j;
} else { // token not a valid number
j = 0;
break;
}
if (j > c) { // too many input values
break;
}
token = strtok(NULL, delims);
}
if (j != c) {
printf("insufficient datapoints\n");
--i; // enter row again
}
}
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
printf("%5d", arr[i][j]);
}
putchar('\n');
}
return 0;
}
交互示例:
Enter rows of 5 data elements:
1 2 3 4
insufficient datapoints
1 2 3 4 5 6
insufficient datapoints
1 x 2 3 4
insufficient datapoints
1 2 3 4 x
insufficient datapoints
1 2 3 4 5 x
insufficient datapoints
1 2x 3 4 5
insufficient datapoints
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
我正在使用用户输入来填充二维数组。用户在一行中输入数字,然后我使用嵌套循环来填充数组,如下所示:
//User inputs: "1 2 3 4 5"
for(i = 0; i < r; i++){
for(j = 0; j < c; j++){
scanf("%d", &arr[i][j]);
}
}
但是,问题是如果用户在有 6 个整数的空间时输入 5 个整数,它只会等待另一个输入。如何检测数量不足?
我试过用这个但是没用:
for(i = 0; i < r; i++){
for(j = 0; j < c; j++){
if (!feof(stdin)){
scanf("%d", &arr[i][j]);
}
else{
printf("insufficient datapoints\n");
}
}
}
您可以在流中使用 peek ahead 并在实际使用字符之前测试字符。 (好吧,在 c 中)。
您可以使用它来忽略空格(您需要这样做)。
您还可以使用此查看值来指示输入的字符是否不足。
需要在实际读取 (scanf) 之前完成查看。
在下面添加了粗略的示例代码
#include <stdio.h>
#include <ctype.h>
int r=3;
int c=2;
int arr[100][100]; // FIX magic
int main(int argc, char** argv[]) {
for(int i=0; i<r; i++) {
for(int j=0; j<c; j++) {
if (feof(stdin)) {
// error check and error / normal exit etc.
printf("eof\n");
}
char c=getchar();
if (c=='\n') {
// error check and error / normal exit here
printf("newline\n");
} else if (isspace(c)) {
// advance and remove them - watch for end of stream when winding
printf("advance and discard whiitespace\n");
} else { // add check for isdigit
// push back
ungetc(c, stdin);
printf("ungetc\n");
}
scanf("%d", &arr[i][j]);
printf("got %d\n", arr[i][j]);
}
}
return 0;
}
实现目标的一种方法是使用 fgets()
而不是 scanf()
一次读取一行输入。然后可以用strtok()
把输入的行打断成token,用strtol()
把token解析成数字。与scanf()
相比,使用fgets
处理非结构化用户输入要容易得多。
下面的代码就是这样做的。如果输入行中的元素太多、元素太少,或者如果其中一个元素不是有效数字,则会打印一条消息并且必须重新输入该行。
由于每一行都是由用户输入的,因此strtok()
用于将行分成标记。令牌定界符列表存储在 delims[]
中。请注意,标记可以用空格或制表符分隔;分隔符本身不是标记的一部分,因此包含 \r
和 \n
可确保这些字符不会成为一行中最终标记的一部分。
找到标记后,如果可能,strtol()
用于将其转换为整数。在调用 strtol()
之后,指针 tail
指向令牌中不属于数字的第一个字符;如果 tail
指向 NUL
终止符,则整个字符串被解析为数字,否则输入被认为是错误的,必须重新输入该行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 1000
int main(void)
{
size_t r = 3;
size_t c = 5;
size_t i, j;
char buffer[BUF_SIZE];
char *token;
char *tail;
const char delims[] = " \t\r\n";
int arr[r][c];
int temp_val;
printf("Enter rows of %zu data elements:\n", c);
for(i = 0; i < r; i++){
j = 0;
if (fgets(buffer, BUF_SIZE, stdin) == NULL) {
perror("Error in fgets()");
exit(EXIT_FAILURE);
}
token = strtok(buffer, delims);
while (token != NULL) {
temp_val = strtol(token, &tail, 10);
if (*tail == '[=10=]') {
arr[i][j] = temp_val;
++j;
} else { // token not a valid number
j = 0;
break;
}
if (j > c) { // too many input values
break;
}
token = strtok(NULL, delims);
}
if (j != c) {
printf("insufficient datapoints\n");
--i; // enter row again
}
}
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
printf("%5d", arr[i][j]);
}
putchar('\n');
}
return 0;
}
交互示例:
Enter rows of 5 data elements:
1 2 3 4
insufficient datapoints
1 2 3 4 5 6
insufficient datapoints
1 x 2 3 4
insufficient datapoints
1 2 3 4 x
insufficient datapoints
1 2 3 4 5 x
insufficient datapoints
1 2x 3 4 5
insufficient datapoints
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7