reading unknown number of integers from stdin (C)
I need to read an input file like :
1
19 20 41 23
2
41 52 43开发者_如何学Python
3
90 91 941
4
512
5
6
51 61
Each odd line is an integer. Each even line is unknown number of integers.
It is very easy in C++
while( cin >> k ){
............
}
I'm not so used to C, so I couldnt make it in C. Any ways to do it?
Running your input file through:
#include <stdio.h>
int main() {
int k;
while (scanf("%d", &k) == 1) {
printf("read number: %d\n", k);
}
return 0;
}
Results in:
read number: 1 read number: 19 read number: 20 read number: 41 read number: 23 read number: 2 read number: 41 read number: 52 read number: 43 read number: 3 read number: 90 read number: 91 read number: 941 read number: 4 read number: 512 read number: 5 read number: 6 read number: 51 read number: 61
This is the C analog of the code you reference in your original question.
The way I would do it is to break it down into two operations: read a line, then read the integers in that line. Here is a lazy implementation using the standard C library:
char line[1024], *p, *e;
long v;
while (fgets(line, sizeof(line), stdin)) {
p = line;
for (p = line; ; p = e) {
v = strtol(p, &e, 10);
if (p == e)
break;
// process v here
}
}
I would break the program in different tasks.
The first step is to be able to read a pair of lines, the first line which tells you the number of numbers to read, and then the second line to read the actual numbers. For this, a function called something like read_set
might be useful. It should be able to return the numbers read, and signal end of file as well as errors. For this, we can define a data structure such as:
struct numbers {
long *data; /* or choose a type depending upon your needs */
size_t len;
};
and then we can declare our function with the prototype:
int read_set(FILE *fp, struct numbers *num);
The function will allocate memory for num->data
, and set num->len
to the correct value. It returns 0 for success, and a set of error conditions otherwise. We might get fancy and use an enum
for return statuses later. For now, let's say that 0 = success, 1 = end of file, and everything else is an error.
The caller then calls read_set()
in a loop:
struct numbers numbers;
int status;
while ((status = read_set(fp, &numbers)) == 0) {
/* process numbers->data, and then free it */
}
if (status == 1) {
/* hit end of file, everything is OK */
} else {
/* handle error */
}
For implementing read_set()
: it has to read two lines. There are many implementations of reading a full line in C, so you can use any of them, and read a line first, then sscanf()
/strtoul()
it for one number (check its return value!). Once you have the number of numbers, n
, you can read the next line in memory, and do:
num->data = malloc(n * sizeof *num->data);
num->len = n;
You can then repeatedly call sscanf()
or strtol()
to store numbers in num->data
. You should put in checks to make sure exactly n
numbers are on that line.
Note that you can write read_set()
in other ways too: read a line character by character, and parse the numbers as you read them. This has the advantage of going over the data only once, and not needing a big buffer to store the whole input line in memory, but the disadvantage is doing low-level stuff yourself and reading data character-by-character may be slow.
I would do one of:
fgetc() to read individual characters and parse them yourself (accumulate digits until you hit whitespace and you have an integer to convert with atoi(); if the whitespace is a newline, then it terminates a list of integers)
fgets() to read a line at a time, and then parse the string (again, look for whitespace separating the values) that it returns.
I came up with a solution like this:
#include <stdio.h>
int main(void)
{
int index = 0;
char ch;
int arr[1024];
while(scanf("%d%c", &arr[index++], &ch)!=EOF)
{
if(ch=='\n')
{
// One line is read into arr
// number of integers in this line = index
// Rest of your code which can proces arr[]
// Example
int i;
for(i = 0; i < index; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
// Set the index back to 0 for the upcoming line
index = 0;
}
}
return 0;
}
have a look at getc(3) or scanf(3)
精彩评论