2012-12-21 14 views
19

Chúng tôi biết rằng, theo mặc định, stdin là một đầu vào được lưu vào bộ đệm; bằng chứng đó là trong việc sử dụng của bất kỳ của các cơ chế đó "lại dữ liệu" trên stdin, chẳng hạn như scanf():Có anyway để peek tại bộ đệm stdin?

int main() 
{ 
    char c[10] = {'\0'}; 
    scanf("%9s", c); 
    printf("%s, and left is: %d\n", c, getchar()); 
    return 0; 
} 

./a.out
chào
hello, và bên trái là 10

10 là newline tất nhiên ...

tôi luôn tò mò, là có anyway để "ú" ở stdin bộ đệm mà không xóa bất kỳ thứ gì có thể nằm ở đó?

EDIT
Một ví dụ tốt hơn có thể là:

scanf("%9[^.]", c); 

Với một đầu vào của "at.ct", bây giờ tôi có "dữ liệu" (ct\n) còn lại trên stdin, không chỉ là một dòng mới.

+1

Bạn có thể 'ungetc()' sau khi nhìn trộm. Đủ tốt? –

+0

@DanielFischer - Tôi đoán nó không phải là xấu ... Điều gì nếu có một bó toàn bộ các ký tự còn lại? Tôi có thể biết độ dài của dữ liệu còn lại trên stdin? hoặc tôi có thể 'ungetc()' nhiều hơn thì một nhân vật? – Mike

+0

"Một nhân vật của pushback được đảm bảo. Nếu hàm' ungetc' được gọi quá nhiều lần trên cùng một luồng mà không có thao tác đọc hoặc định vị tập tin trên luồng đó, thao tác có thể thất bại ". Thông thường, bạn có thể 'ungetc' nhiều hơn một, nhưng chỉ có một cái được đảm bảo. –

Trả lời

11

Có thể, bạn có thể lấy ký tự tiếp theo trong luồng đầu vào với getchar() và sau đó đẩy nó trở lại với ungetc(), dẫn đến trạng thái như thể ký tự không bị xóa khỏi luồng.

Các ungetc chức năng đẩy nhân vật theo quy định của c (chuyển đổi thành một unsigned char) trở lại vào input stream trỏ đến bởi dòng. Các ký tự được đẩy lùi sẽ được trả về bởi lần đọc tiếp theo trên luồng đó theo thứ tự ngược lại của việc đẩy chúng.

Chỉ có một nhân vật phản hồi được đảm bảo theo tiêu chuẩn, nhưng thông thường, bạn có thể đẩy lại nhiều hơn.

Như đã đề cập trong phần trả lời khác. những ý kiến ​​đó, trong thực tế, bạn có thể gần như chắc chắn peek tại bộ đệm nếu bạn cung cấp đệm của riêng bạn với setvbuf, mặc dù đó không phải là không có vấn đề:

Nếu buf không phải là một con trỏ null, mảng nó trỏ tới có thể được sử dụng thay vì bộ đệm được phân bổ bởi hàm setvbuf

để không thể sử dụng bộ đệm được cung cấp.

Nội dung của mảng bất kỳ lúc nào không xác định.

điều đó có nghĩa là bạn không đảm bảo rằng nội dung của bộ đệm phản ánh đầu vào thực tế (và sử dụng bộ đệm không xác định hành vi nếu nó có thời gian lưu trữ tự động, nếu chúng tôi cầu kỳ).

Tuy nhiên, trong thực tế, vấn đề chính sẽ tìm ra nơi trong bộ đệm phần không được tiêu thụ của đầu vào được đệm bắt đầu và kết thúc ở đâu.

+1

Sẽ không làm 'getchar' khi bộ đệm đầu vào là khối trống cho đến khi có gì đó để đọc? –

+0

Thật vậy, nó sẽ. Tôi không nhận thức được một cách di động để kiểm tra xem bộ đệm có trống không, tuy nhiên. –

5

Bạn có thể đặt bộ đệm của riêng mình bằng setvbuf trên stdin và xem nhanh bất cứ khi nào bạn muốn.

+0

Điều đó tương tác với 'ungetc' như thế nào? Tôi nghĩ rằng ký tự 'ungetc'ed được lưu trữ trong một số biến khác. Ngoài ra, làm thế nào bạn sẽ biết những gì một phần của bộ đệm được đọc và những gì còn lại? – Shahbaz

+0

'Hàm setvbuf() không ảnh hưởng đến stdout, stdin, hoặc stderr.' Là những gì tôi đã đọc. Bạn có một ví dụ hoạt động? – Mike

+0

@Mike Nó dường như hoạt động trên các cửa sổ. 'ungetc' hoạt động như mong đợi. Không hoàn toàn chắc chắn về cách theo dõi vị trí đọc/trái. Nhưng nếu buff được lót mới, thì nó sẽ dễ dàng. – nullpotent

3

Nếu bạn muốn nhìn vào bộ đệm stdin mà không thay đổi nó, bạn có thể nói nó sử dụng một bộ đệm khác với setbuf, sử dụng một mảng, bạn có thể truy cập vào:

char buffer[BUFSIZ]; 

if (setbuf(stdin, buffer) != 0) 
    // error 

getchar(); 

printf("%15s\n", buffer); 

này cho phép bạn xem một cái gì đó nhiều hơn ungetc, nhưng tôi không nghĩ rằng bạn có thể tiến xa hơn theo cách di động.

Thực ra đây là hợp pháp nhưng không phải là chính xác cho tiêu chuẩn, trích dẫn từ nó về setvbuf (setbuf có hành vi tương tự):

Nội dung của mảng bất cứ lúc nào là không xác định.

Vì vậy, đây không phải là những gì bạn cần nếu bạn đang tìm kiếm tính di động hoàn chỉnh và tuân thủ tiêu chuẩn, nhưng tôi không thể tưởng tượng tại sao bộ đệm không chứa những gì được mong đợi. Tuy nhiên, có vẻ như nó hoạt động trên máy tính của tôi.

Hãy coi chừng rằng bạn phải cung cấp một mảng ít nhất BUFSIZ ký tự cho setbuf và bạn không được thực hiện bất kỳ hoạt động I/O nào trên luồng trước đó. Nếu bạn cần linh hoạt hơn, hãy xem setvbuf.

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