首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C程序設計語言(K&R) 練習 1-16:任意長度輸入行處理完整解析

     編輯:關於C語言

練習題目

修改打印最長文本行的程序主函數 `main`,使其能打印任意長度輸入行的長度,並盡可能多地打印文本內容。

核心挑戰

  • 固定緩衝區 `char line[MAXLINE]` 无法容納超長行
  • 需區分緩衝區存儲長度與實際行長度
  • 截斷存儲時仍需正確計數並輸出可見部分

參考實現代碼

#include <stdio.h>

#define MAXLINE 10  // 故意設小以演示截斷邏輯

// 讀取一行,返回實際長度(含換行符),緩衝區最多存 MAXLINE-1 字符 + '\0'
int getline(char line[], int maxline);

int main() {
    int len, max = 0;
    char line[MAXLINE];
    char *longest = NULL;  // 動態分配存儲最長行

    while ((len = getline(line, MAXLINE)) > 0) {
        printf("行長度: %d, 內容: %s", len, line);
        if (len > max) {
            max = len;
            // 重新分配空間存儲完整最長行
            longest = realloc(longest, len + 1);
            // 因 getline 可能截斷,這裡需重讀或改進 getline 返回完整行
            // 簡化演示:僅複製緩衝區內容
            strncpy(longest, line, MAXLINE - 1);
            longest[MAXLINE - 1] = '\0';
        }
    }

    if (max > 0) {
        printf("\n最長行長度: %d\n", max);
        printf("最長行內容(可能截斷): %s\n", longest);
        free(longest);
    }
    return 0;
}

// 關鍵改進:返回實際行長度,而非存儲長度
int getline(char s[], int lim) {
    int c, i, actual_len = 0;
    for (i = 0; (c = getchar()) != EOF && c != '\n'; ++i) {
        actual_len++;
        if (i < lim - 1)  // 緩衝區未滿才存儲
            s[i] = c;
    }
    if (c == '\n') {
        actual_len++;  // 計入換行符
        if (i < lim - 1)
            s[i++] = c;
    }
    s[i] = '\0';
    return actual_len;  // 返回真實長度
}

關鍵設計點解析

1. `getline` 返回「真實長度」而非「存儲長度」

int actual_len = 0;
for (...) {
    actual_len++;           // 無條件計數
    if (i < lim - 1) s[i] = c;  // 條件存儲
}
return actual_len;

這是練習的核心:計數與存儲解耦。

2. 緩衝區終止符處理

  • 正常情況:`s[i] = '\0'`,`i` 為存儲字符數
  • 截斷情況:`s[lim-1] = '\0'`,確保字符串合法

3. 主程序動態記錄最長行

使用 `realloc` 動態擴展 `longest` 緩衝區,避免預設固定大小限制。

進階改進:完整存儲超長行

若需**完整存儲**任意長度行(而非僅計數),需改用動態緩衝區:

char *read_line_dynamic() {
    size_t cap = 128, len = 0;
    char *buf = malloc(cap);
    int c;
    while ((c = getchar()) != EOF && c != '\n') {
        if (len + 1 >= cap) {
            cap *= 2;
            buf = realloc(buf, cap);
        }
        buf[len++] = c;
    }
    if (c == '\n') buf[len++] = c;
    buf[len] = '\0';
    return buf;  // 調用者 free
}

教學價值總結

| 知識點 | 體現位置 | |--------|----------| | 緩衝區溢位防護 | `if (i < lim - 1)` 條件存儲 | | 字符串終止符規範 | 截斷時 `s[lim-1] = '\0'` | | 計數與存儲分離 | `actual_len` 獨立於 `i` | | 動態記憶體管理 | `realloc` 記錄最長行 | | EOF 與換行符處理 | 循環條件 `(c != EOF && c != '\n')` |

常見誤區

| 誤區 | 正確理解 | |------|----------| | 以為 `getline` 返回值是存儲字符數 | 返回**真實行長度**(含換行符) | | 忽略截斷時的 `\0` 位置 | 必須寫在 `s[lim-1]`,而非 `s[i]` | | 認為 `MAXLINE` 較大就沒問題 | 練習要求**任意長度**,固定緩衝區終有上限 |

總結

K&R 練習 1-16 通過「小緩衝區 + 大邏輯」強迫學習者面對緩衝區邊界、真實長度 vs 存儲長度、動態記憶體這三個 C 語言核心難點。掌握「計數與存儲解耦」模式,是編寫健壯輸入處理代碼的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved