2015-10-23 13 views
6

Tôi đang nghiên cứu cuốn sách R & R. Hiện tại tôi đang đọc hàm getop() tại trang p.78. Tôi hiểu mã nhưng tôi cần giải thích về 2 điều.getop() chức năng K & R book p 78

Mã của getop() như sau:

int getch(void); 
void ungetch(int); 

/* getop: get next character or numeric operand */ 
int getop(char s[]) 
{ 
    int i, c; 
    while ((s[0] = c = getch()) == ' ' || c == '\t') 
     ; 
    s[1] = '\0'; 

    if (!isdigit(c) && c != '.') 
     return c; /* not a number */ 

    i = 0; 
    if (isdigit(c)) /* collect integer part */ 
     while (isdigit(s[++i] = c = getch())) 
      ; 
    if (c == '.') /* collect fraction part */ 
     while (isdigit(s[++i] = c = getch())) 
      ; 
    s[i] = '\0'; 

    if (c != EOF) 
     ungetch(c); 

    return NUMBER; 
} 

Câu hỏi của tôi là về: s[0] trong:

while ((s[0] = c = getch()) == ' ' || c == '\t') 

Ý tưởng đằng sau vòng lặp while là bỏ qua không gian và tab ngang, vậy tại sao chúng ta tiết kiệm 'c' trong s [0]? Tại sao tác giả không chỉ đơn giản viết:

while (c= getch() == ' ' || c == '\t') 

Chúng tôi sẽ không sử dụng không gian và các tab sau này, tại sao chúng ta cần phải lưu c trong s[0] cho? Nhu cầu cho s[0] ở đây là gì?

câu hỏi thứ hai của tôi là về:

s[1] = '\0'; 

Tại sao chúng ta gán '\ 0' (kết thúc chuỗi) để s[1] đây?

Tôi đã đọc một số câu trả lời trước đây được đăng trên stackoverflow.com về nó nhưng tôi không hoàn toàn thuyết phục!

Câu trả lời được chấp nhận về câu hỏi trên là: "Vì hàm có thể trả về trước khi đầu vào còn lại được đọc, và sau đó s cần phải là chuỗi hoàn chỉnh (và đã kết thúc)".

Ok. Nhưng nếu đầu vào có một khoảng trắng ở đầu và sau đó là toán hạng hoặc toán tử thì sao? Trong trường hợp này, s[1] = '\0' sẽ đóng chuỗi quá sớm? phải không?

Trả lời

5

Trong câu trả lời cho câu hỏi đầu tiên của bạn, việc gán cho s[0] trong trường hợp này là lối tắt mã hóa tiện lợi. Giá trị của c được sao chép thành s[0] cho mỗi ký tự được đọc bởi getch(), bất kể nó sẽ được sử dụng hay bị hủy. Nếu nó bị loại bỏ, không có vấn đề lớn; nó sẽ được ghi đè lên lần lặp tiếp theo của vòng lặp while(). Nếu nó được sử dụng, thì nó đã được sao chép vào vị trí cần thiết của nó trong mảng đích s[].

Trong câu trả lời cho câu hỏi thứ hai của bạn,

Nhưng nếu đầu vào có một khoảng trắng ở đầu và tiếp theo một toán hạng hoặc nhà điều hành?

Lưu ý rằng vòng lặp while() trước đó ngăn không cho ký tự khoảng trắng (dấu cách và tab) xuất hiện trong s[0] sau khi thoát khỏi vòng lặp. Vì vậy, sau khi thực hiện

s[1] = '\0'; 

chuỗi s[] sẽ bao gồm một nhân vật duy nhất không phải là một không gian hay một tab, tiếp theo là một terminator chuỗi.

Trong báo cáo kết quả tiếp theo

if (!isdigit(c) && c != '.') 
    return c; /* not a number */ 

hàm sẽ trả về nếu nhân vật là bất cứ điều gì nhưng một chữ số hoặc một dấu thập phân. Đây là lý do tại sao nó là cần thiết để chấm dứt chuỗi.

+0

Giải thích tốt, mặc dù tôi sẽ loại bỏ các tính từ tích cực như "thuận tiện", vì điều đó gợi ý rằng mã K & R lộn xộn này tuân theo một số loại thực hành mã hóa C tốt, trong khi nó thực sự được lấp đầy với điều ngược lại. – Lundin

+0

@Lundin: Tôi đồng ý hoàn toàn rằng mã K & R được đề cập là khủng khiếp từ quan điểm "thực hành mã hóa tốt", nhưng mã minh họa một số tính mới nhất của ngôn ngữ C quan trọng cho người mới học. Từ quan điểm của thiết kế thuật toán, và tôi tin từ quan điểm của tác giả ban đầu của mã (trước khi "thực hành mã hóa tốt" ngày nay được hình thành), việc gán cho s [0] vào thời điểm này trong mã là tiện lợi, vì nó sẽ không cần phải được thực hiện sau này. – sifferman

2

Nhưng điều gì xảy ra nếu đầu vào có một khoảng trắng ở đầu và sau đó là toán hạng hoặc toán tử? Trong trường hợp này, s [1] = '\ 0' sẽ đóng chuỗi quá sớm? phải không?

Nope,

i = 0; 
if (isdigit(c)) /* collect integer part */ 
    while (isdigit(s[++i] = c = getch())) 

Điều này làm cho chắc chắn, rằng nếu có cái gì đó để được đọc, nó sẽ bị ghi đè trên \0, như i=0s[++i] có nghĩa là, lưu trữ trong s[1], chứa các \0

+0

thx cho trả lời câu hỏi thứ hai của tôi! Bất kỳ bình luận nào về câu hỏi đầu tiên của tôi? –

0

cho câu hỏi đầu tiên của bạn về: s [0] trong:

while ((s[0] = c = getch()) == ' ' || c == '\t') 

vì tiết kiệm 'c' trong s [0] giúp lưu trữ số đầu tiên trong tiên tiến để chúng tôi có thể bắt đầu mã tiếp theo của chúng tôi từ chỉ đơn giản là tôi bằng để 1.

i = 0; 
if (isdigit(c)) /* collect integer part */ 
    while (isdigit(s[++i] = c = getch())) 

đoạn mã trên được sử dụng để lưu trữ các chuỗi ký tự tiếp theo là bắt đầu từ chỉ số i = 1

Về câu hỏi thứ hai của bạn:

0.123.

chúng tôi không thể làm

s[0] = '\0'; 

vì tại thời điểm đó chúng tôi đã được lưu trữ số đầu tiên trong chuỗi tại s [0]

thấy

(s[0] = c = getch())