C 如何逐行从标准输入中读取未定义数量的整数?
我需要使用C从标准输入中读取并存储整数,接收格式如下:35:27,5,10每行上有未定义的整数数和未定义的行数。理想情况下,我希望有一个循环,在其中我可以使用最近扫描的行中的值来执行其他任务。如何扫描并存储数组中的整数,然后在扫描下一行时覆盖数组,依此类推,直到达到EOF 我想我必须使用scanf和strtok的组合,但我似乎不知道如何使用。我也尝试过使用getchar,但这只会让事情变得更复杂 我想我必须使用scanf和strtok的组合 使用fgets读取行,使用sscanf扫描读取的行以查找整数:C 如何逐行从标准输入中读取未定义数量的整数?,c,int,scanf,stdin,C,Int,Scanf,Stdin,我需要使用C从标准输入中读取并存储整数,接收格式如下:35:27,5,10每行上有未定义的整数数和未定义的行数。理想情况下,我希望有一个循环,在其中我可以使用最近扫描的行中的值来执行其他任务。如何扫描并存储数组中的整数,然后在扫描下一行时覆盖数组,依此类推,直到达到EOF 我想我必须使用scanf和strtok的组合,但我似乎不知道如何使用。我也尝试过使用getchar,但这只会让事情变得更复杂 我想我必须使用scanf和strtok的组合 使用fgets读取行,使用sscanf扫描读取的行以查
#include <stddef.h> // size_t
#include <stdlib.h> // realloc(), free()
#include <stdio.h> // fgets(), sscanf(), printf(), puts(), fputs()
int main(void)
{
char line_buffer[100]; // a buffer for the current line
int *values_buffer = NULL; // pointer to memory to store the values in
size_t values_buffer_size = 0; // actual size of the value buffer
// while a line can be read from stdin ...
while (fgets(line_buffer, sizeof line_buffer / sizeof *line_buffer, stdin)) {
size_t num_values = 0; // to count the values we're able to extract
char *pos = line_buffer; // the current read-position inside line_buffer
// try to extract integers from the line_buffer at position pos:
for (int consumed = 0, value;
sscanf(pos, "%d%*[^0123456789]%n", &value, &consumed) >= 1;
pos += consumed)
{
// %*[^0123456789] discards a string not containing any digit
// %n yields the number of characters consumed
// if the value_buffer isn't big enough ...
if (num_values >= values_buffer_size) {
// resize it
int *tmp = realloc(values_buffer, (num_values + 1) * sizeof *tmp);
if (!tmp) {
fputs("Not enough memory. :(", stderr);
free(values_buffer);
return EXIT_FAILURE;
}
// ... and update it's size
values_buffer_size = num_values + 1;
values_buffer = tmp;
}
// save the current value in value_buffer
values_buffer[num_values++] = value;
}
// have fun with the values of the current line:
if (num_values) {
printf("Values: ");
for (size_t i = 0; i < num_values; ++i)
printf("%d ", values_buffer[i]);
putchar('\n');
} else puts("No values. :(\n");
}
// clean-up:
free(values_buffer);
if (ferror(stdin)) {
fputs("An input error occured. :(\n", stderr);
return EXIT_FAILURE;
}
else if (feof(stdin))
puts("EOF reached.\n");
}
如果发现意外情况,此程序将在stdin上读取该格式的文件,并发出错误
//sumline.c sum integers on each line.
#include <stdio.h>
int main(){
int sum=0;
int rowcount=0;
char buf[30]="";
while(! feof(stdin) )
{
int in;
char sep[2];
if((scanf("%1[^0-9-+]",sep)) && !feof(stdin))
{
fgets(buf,30,stdin);
printf("unexpected %d char (%c,%30s)\n",sep[0],sep[0],buf);
return 1;
}
if( ! scanf("%d",&in))
{
printf("malformed int\n");
return 1;
}
if( feof(stdin) && rowcount == 0 )
{
return 0;
}
sum += in;
if( ! scanf("%1[,:.\n]",sep) && !feof(stdin))
{
fgets(buf,30,stdin);
printf("inexpected char %30s\n",buf);
return 1;
}
else
{
++rowcount;
}
if( sep[0]=='\n' && rowcount )
{
printf("sum=%d\n",sum);
sum=0;
rowcount=0;
}
if( feof(stdin) && rowcount == 0 )
{
return 0;
}
}
return 0;
}
我想我必须使用scanf和strtok的组合
我不这么认为:
用户可以在任何数字之前输入几乎无限量的零,或输入大量空白,或在小数点后输入大量零,或。。。。这意味着您不能期望一个数字的所有数字同时出现在RAM中;这意味着C提供的函数都不可用
错误时有发生。解析文本时,无论文本来自需要了解其文本不受欢迎原因的用户,还是来自开发人员需要能够发现/修复问题的文件或其他计算机,都应将明确的描述性反馈视为强制性反馈
最好是避免这两个问题,即在循环中使用状态机;比如:
int state = NEWLINE;
unsigned int lineNumber = 0;
unsigned int dataNumber;
while( ((c = getChar()) != EOF)) && (state != ERROR) ) {
switch(state) {
case NEWLINE:
lineNumber++;
if(isDigit(c) {
number = c - '0';
state = FIRST_NUMBER_STARTED;
dataNumber = 1;
} else {
printf("ERROR: Character at start of line is not a valid decimal digit\n");
state = ERROR;
}
break;
case FIRST_NUMBER_STARTED:
if(isDigit(c) {
digit = c - '0';
if(number > UINT_MAX/10) {
printf("ERROR: First number on line %u is too large\n", lineNumber);
state = ERROR;
} else {
number *= 10;
if(number > UINT_MAX - digit) {
printf("ERROR: First number on line %u is too large\n", lineNumber);
state = ERROR;
} else {
number += digit;
}
}
} else if(c == ';') {
state = COLON_FOUND;
} else {
printf("ERROR: Invalid character after first number on line\n");
state = ERROR;
}
break;
case COLON_FOUND:
if(isDigit(c) {
number = c - '0';
state = DATA_NUMBER_STARTED;
} else {
printf("ERROR: Character at start of data not a valid decimal digit\n");
state = ERROR;
}
break;
case DATA_NUMBER_STARTED:
if(isDigit(c) {
digit = c - '0';
if(number > UINT_MAX/10) {
printf("ERROR: Data number %u on line %u is too large\n", dataNumber, lineNumber);
state = ERROR;
} else {
number *= 10;
if(number > UINT_MAX - digit) {
printf("ERROR: Data number %u on line %u is too large\n", dataNumber, lineNumber);
state = ERROR;
} else {
number += digit;
}
}
} else if(c == ',') {
state = COMMA_FOUND;
} else if(c == '\n') {
state = NEW_LINE;
} else {
printf("ERROR: Invalid character after data number %u on line %u\n", dataNumber, lineNumber);
state = ERROR;
}
break;
case COMMA_FOUND:
dataNumber++;
if(isDigit(c) {
number = c - '0';
state = FIRST_NUMBER_STARTED;
} else if(c == '\n') {
printf("ERROR: Missing number after comma at end of line %u\n", lineNumber);
state = ERROR;
} else {
printf("ERROR: Invalid character after comma (after data number %u) on line %u\n", dataNumber-1, lineNumber);
}
break;
}
}
注意:示例代码不存储任何数据,也不处理空格或小数点,或者。。。你可以添加更多的代码和新的状态,等等;这是一段未经测试的代码,仅作为示例。只需使用scanf,但要注意每个整数后面的内容,如果“\n”是行的结尾,那么它可能会很有用。因此,您实际上并不关心未定义的行数,因为您将单独处理每一行。您只需要知道每行上有多少个整数以及它们是什么。据推测,32位有符号int值足够大,可以容纳一行中的整数数量,或者您需要在一行中容纳多个千兆字节的数据吗?值是否也在int 32位带符号整数的范围内?有负值吗?除了冒号、逗号和换行符之外,还有其他分隔符吗?您还没有展示您尝试过的内容。嗯-前导的非“\n”空格会导致。似乎很严格,但符合OP的目标。有人抱怨scanf%d没有检查“\n”,因此我更改了循环的顺序。如果一个文件被要求有这样或那样的格式,如果我输入'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001'作为第一个整数,这是一个好主意。会发生什么?scanf不是由这么长的整数混合而成的,您正在使用FGET将队列切分为多个块。