2010-02-03 47 views
6

tôi cần phải đọc một tập tin đầu vào như:đọc số không rõ các số nguyên từ stdin (C)

1 
19 20 41 23 
2 
41 52 43 
3 
90 91 941 
4 
512 
5 

6 
51 61 

Mỗi dòng lẻ là một số nguyên. Mỗi dòng đều là số nguyên không xác định.

Nó là rất dễ dàng trong C++

while(cin >> k){ 
............ 
} 

Tôi không quá quen với C, vì vậy tôi couldnt làm cho nó trong C. Bất kỳ cách để làm điều đó?

+1

Bạn phải chú ý đến dòng, hoặc là này chỉ là một loạt các số nguyên sắp tới trong? Trong ví dụ của bạn, có vẻ như các dòng lẻ là số thứ tự và các dòng chẵn đại diện cho một số thứ khác. –

+0

david Tôi cần chú ý đến các dòng. đó là lý do tại sao tôi không thể làm điều đó. Tôi cần ngừng nhận các giá trị mới ở cuối mỗi dòng chẵn. Vì tôi có cấu trúc với id và danh sách thuộc tính. mỗi dòng lẻ là một id và mỗi dòng đều là một danh sách. Tôi muốn điền vào một cấu trúc với 2 dòng dữ liệu và di chuyển đến cấu trúc khác và điền nó với 2 dòng dữ liệu khác ... – huhuhuuu

+0

Đọc toàn bộ dòng tại một thời điểm và sau đó phân tích cú pháp như một chuỗi –

Trả lời

9

Con đường tôi sẽ làm điều đó là để phá vỡ nó xuống thành hai hoạt động: đọc một dòng, sau đó đọc các số nguyên trong dòng đó. Đây là một thực hiện lười biếng bằng cách sử dụng tiêu chuẩn thư viện C:

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 
    } 
} 
+2

Cảm ơn rất nhiều. Tôi sẽ thử nó ngay bây giờ. Nhưng nếu tôi không thể giả định độ dài tối đa cố định? – huhuhuuu

+2

Điều gì sẽ xảy ra nếu luồng đầu vào chứa nhiều hơn 1024 - 2 ký tự và 'fgets()' tách luồng đầu vào ở dạng chữ số? Bạn sẽ kết thúc với hai giá trị số thay vì một. Ví dụ, từ 12345 bạn có thể nhận được 123 trong lần lặp cuối cùng của vòng lặp for và 45 trong lần lặp đầu tiên của vòng lặp for sau cuộc gọi tiếp theo của 'fgets()'. Do đó, tôi thích 'scanf()' và 'fscanf()' cho nhiệm vụ này, như được hiển thị bởi Sean. –

+1

@RobinKlose: Giải pháp 'scanf()' được đăng bởi Sean không giải quyết được vấn đề, vì nó không phân biệt các ngắt dòng từ các khoảng trắng khác. –

11

Chạy tập tin đầu vào của bạn thông qua:

#include <stdio.h> 

int main() { 
     int k; 
     while (scanf("%d", &k) == 1) { 
       printf("read number: %d\n", k); 
     } 
     return 0; 
} 

Kết quả trong:

 
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 

Đây là analog C của mã bạn tham khảo trong câu hỏi ban đầu của bạn.

+0

Tôi có thể đọc dòng một cách chính xác nhưng vòng lặp scanf vô cùng in số đầu tiên cho tôi. – tarabyte

0

có một cái nhìn tại getc (3) hoặc scanf (3)

1

tôi sẽ làm một trong số:

  • fgetc() để đọc kí tự độc lập và phân tích chúng mình (tích lũy chữ số cho đến khi bạn nhấn khoảng trắng và bạn có số nguyên để chuyển đổi với atoi(); nếu khoảng trắng là một dòng mới, thì nó sẽ kết thúc một danh sách các số nguyên). tìm khoảng trắng tách các giá trị) mà nó trả về.

3

Tôi sẽ phá vỡ chương trình trong các tác vụ khác nhau.

Bước đầu tiên là có thể đọc một cặp dòng, dòng đầu tiên cho bạn biết số lượng số để đọc và sau đó là dòng thứ hai để đọc các số thực. Đối với điều này, một chức năng được gọi là một cái gì đó như read_set có thể hữu ích. Nó sẽ có thể trả về các số đã đọc và kết thúc tín hiệu của tệp cũng như các lỗi. Đối với điều này, chúng ta có thể định nghĩa một cấu trúc dữ liệu như:

struct numbers { 
    long *data; /* or choose a type depending upon your needs */ 
    size_t len; 
}; 

và sau đó chúng ta có thể khai báo các chức năng của chúng tôi với nguyên mẫu:

int read_set(FILE *fp, struct numbers *num); 

Chức năng sẽ phân bổ bộ nhớ cho num->data, và thiết lập num->len đến giá trị chính xác. Nó trả về 0 cho thành công, và một tập hợp các điều kiện lỗi khác. Chúng tôi có thể ưa thích và sử dụng enum cho trạng thái trả lại sau. Bây giờ, giả sử 0 = thành công, 1 = kết thúc tệp và mọi thứ khác là lỗi.

Người gọi sau đó gọi read_set() trong một vòng lặp:

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 */ 
} 

Đối với việc thực hiện read_set(): nó phải đọc hai dòng. Có rất nhiều implementations of reading a full line in C, vì vậy bạn có thể sử dụng bất kỳ trong số họ, và đọc một dòng đầu tiên, sau đó sscanf()/strtoul() nó cho một số (kiểm tra giá trị trả lại của nó!). Một khi bạn có số lượng các số, n, bạn có thể đọc dòng tiếp theo trong bộ nhớ, và làm:

num->data = malloc(n * sizeof *num->data); 
num->len = n; 

Bạn có thể sau đó liên tục gọi sscanf() hoặc strtol() để lưu trữ các số trong num->data. Bạn nên đặt trong séc để đảm bảo chính xác số n nằm trên dòng đó.

Lưu ý rằng bạn cũng có thể viết read_set() theo các cách khác: đọc ký tự dòng theo ký tự và phân tích cú pháp các số khi bạn đọc chúng. Điều này có lợi thế là đi qua các dữ liệu chỉ một lần, và không cần một bộ đệm lớn để lưu trữ toàn bộ dòng đầu vào trong bộ nhớ, nhưng bất lợi là làm công cụ cấp thấp bản thân và đọc dữ liệu character-by-ký tự có thể được làm chậm.

0

tôi đã đưa ra một giải pháp như thế này:

while(scanf("%d%c", &n, &ch)!=EOF) 
{ 
    if(ch=='\n') break; 
    /* rest of your code */ 
} 
+0

/* phần còn lại của mã yout */phải sau vòng lặp. –

Các vấn đề liên quan