2011-12-14 39 views
5

Mã này đến từ K & R. Tôi đã đọc nó nhiều lần, nhưng nó vẫn có vẻ để thoát khỏi sự nắm bắt của tôi.Hãy giải thích ví dụ này Mã C

#define BUFSIZE 100 

char buf[BUFSIZE]; 
int bufp = 0; 

int getch(void) 
{ 
     return(bufp>0)?buf[--bufp]:getchar(); 
} 

int ungetch(int c) 
{ 
     if(bufp>=BUFSIZE) 
      printf("too many characters"); 
     else buf[bufp++]=c; 
} 

Mục đích của hai chức năng này, vì vậy K & R cho biết, là ngăn chương trình đọc quá nhiều đầu vào. tức là không có mã này, một hàm có thể không xác định được nó đã đọc đủ dữ liệu mà không đọc quá nhiều lần. Nhưng tôi không hiểu nó hoạt động ra sao.

Ví dụ: hãy xem xét getch(). Theo như tôi có thể thấy đây là các bước cần:

  1. kiểm tra nếu bufp lớn hơn 0.
  2. nếu như vậy thì trả về giá trị char của buf [- bufp].
  3. khác trả về getchar().

Tôi muốn đặt câu hỏi cụ thể hơn, nhưng tôi không biết mã này đạt được mục đích như thế nào, vì vậy câu hỏi của tôi là: (a) mục đích và (b) lý luận là gì của mã này?

Xin cảm ơn trước.

LƯU Ý: Đối với bất kỳ fan R K &, mã này có thể được tìm thấy trên trang 79 (tùy thuộc vào phiên bản của bạn, tôi giả sử)

+0

Phép thử bên trong 'ungetch' có thể liên quan đến' bufp' không phải 'printf' trong điều kiện của nó. Tôi đoán nó là một lỗi đánh máy. –

+0

Tôi hiện không có K & R, nhưng tôi nghĩ rằng trong trường hợp không có, điều kiện if phải là 'bufp> = BUFSIZE' – kol

+0

Xin lỗi, có lẽ là lỗi của tôi. SOmeone đã sửa nó ngay bây giờ, vì vậy tôi không thể nhớ những gì tôi đã nhập orginally. –

Trả lời

9

(a) Mục đích của mã này là để có thể đọc một ký tự và sau đó "bỏ đọc" nó nếu nó chỉ ra bạn vô tình đọc một nhân vật quá nhiều (với tối đa là 100 ký tự được "un-đọc"). Điều này rất hữu ích trong các trình phân tích cú pháp với lookahead.

(b) getch đọc từ buf nếu có nội dung, được biểu thị bằng bufp>0. Nếu buf trống, nó sẽ gọi số getchar. Lưu ý rằng nó sử dụng buf làm ngăn xếp: nó đọc từ phải sang trái.

ungetch đẩy ký tự vào ngăn xếp buf sau khi kiểm tra xem ngăn xếp chưa đầy chưa.

+0

Nhưng giả sử ungetch không được gọi là, sau đó getch sẽ luôn trả về getchar(), vì bufp sẽ là số vô thời hạn. Tôi không hiểu phần này. –

+0

@JJG: đúng vậy, nếu bạn không bao giờ gọi 'ungetch', thì bạn sẽ không cần bộ đệm và sẽ luôn nhận được đầu vào mới từ' getchar'. –

1

Mã không thực sự cho "đọc quá nhiều đầu vào", thay vào đó là mã để bạn có thể đặt lại các ký tự đã đọc.

Ví dụ: bạn đọc một ký tự với getch, xem đó có phải là chữ cái không, đặt nó trở lại với ungetch và đọc tất cả các chữ cái trong một vòng lặp. Đây là một cách để dự đoán nhân vật tiếp theo sẽ là gì.

1

Khối mã này được sử dụng cho các chương trình đưa ra quyết định dựa trên những gì họ đọc từ luồng. Đôi khi các chương trình như vậy cần xem xét một vài ký tự từ luồng mà không thực sự tiêu thụ đầu vào. Ví dụ: nếu đầu vào của bạn trông giống như abcde12xy789 và bạn phải tách nó thành abcde, 12, xy, 789 (tức là các nhóm riêng biệt của các chữ cái liên tiếp từ nhóm chữ số liên tiếp) bạn không biết rằng bạn đã đến cuối nhóm chữ cái cho đến khi bạn nhìn thấy một chữ số. Tuy nhiên, bạn không muốn tiêu thụ con số đó tại thời điểm bạn thấy nó: tất cả những gì bạn cần là biết rằng nhóm các chữ cái kết thúc; bạn cần một cách để "đặt lại" chữ số đó.An ungetch có ích trong trường hợp này: khi bạn thấy chữ số sau một nhóm chữ cái, bạn đặt lại chữ số bằng cách gọi ungetch. Lặp đi lặp lại tiếp theo của bạn sẽ chọn chữ số đó sao lưu thông qua cùng một cơ chế getch, tiết kiệm cho bạn sự cần thiết phải bảo toàn nhân vật mà bạn đọc nhưng không tiêu thụ.

0
    1. Ý tưởng khác cũng được hiển thị ở đây cũng có thể được gọi là hệ thống lưu trữ ngăn xếp I/O rất nguyên thủy và cho phép thực hiện hàm getch() và ungetch().
    2. Để tiến thêm một bước, giả sử bạn muốn thiết kế Hệ điều hành, bạn có thể xử lý bộ nhớ lưu trữ tất cả các lần nhấn phím như thế nào?

Điều này được giải quyết bằng đoạn mã trên. Phần mở rộng của khái niệm này được sử dụng trong xử lý tệp, đặc biệt là trong chỉnh sửa tệp. Trong trường hợp đó thay vì sử dụng getchar() được sử dụng để lấy đầu vào từ đầu vào Chuẩn, tệp được sử dụng làm nguồn đầu vào.

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