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

C語言文件處理進階練習:交替輸出兩文件內容的實現與優化

     編輯:關於C語言

交替讀取兩文件並按行輸出:C語言文件操作進階練習

這是一個經典的C語言文件處理練習:同時打開兩個文本文件,交替輸出它們的第1行、第2行...直到較長文件讀完。這不僅考驗文件操作基礎,更涉及EOF處理、循環控制、邊界條件等核心技能。

原始代碼分析與問題

/* 原版核心邏輯 */
while(1) {
    /* 讀文件1的一行 */
    while((ch1=getc(wj1)) != '\n') {
        if (ch1 == EOF) break;
        putc(ch1, stdout);
    }
    if (ch1 != EOF) putchar('\n');
    
    /* 讀文件2的一行 */
    while((ch2=getc(wj2)) != '\n') {
        if (ch2 == EOF) break;
        putc(ch2, stdout);
    }
    if (ch2 != EOF) putchar('\n');
    
    if (ch1 == EOF && ch2 == EOF) return 0;
}

存在的隱患

  1. gets()不安全:無緩衝區保護,已被C11移除
  2. EOF判斷邏輯脆弱:若文件末尾無換行符,最後一行可能漏輸出
  3. 雙重EOF檢查冗餘:外層while(1)配合內部break不夠優雅
  4. 無法區分「讀到換行」vs「讀到EOF」:導致額外插入換行符

重構優化版:健壯、清晰、標準

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_PATH 4096

/* 安全讀取一行並輸出,返回值:1=正常行 0=EOF -1=錯誤 */
int read_and_print_line(FILE *fp) {
    int ch;
    int has_content = 0;
    
    while ((ch = getc(fp)) != EOF) {
        has_content = 1;
        if (ch == '\n') {
            putchar('\n');
            return 1;  // 完整行結束
        }
        putchar(ch);
    }
    
    /* 處理文件結束情況 */
    if (has_content) {
        /* 文件末尾無換行符的最後一行 */
        putchar('\n');
        return 1;
    }
    return 0;  // 純EOF,無內容
}

int main(void) {
    FILE *fp1 = NULL, *fp2 = NULL;
    char name1[MAX_PATH], name2[MAX_PATH];
    
    /* 安全獲取文件名 */
    printf("請輸入第一個文件名: ");
    if (!fgets(name1, sizeof(name1), stdin)) return EXIT_FAILURE;
    name1[strcspn(name1, "\n")] = '\0';
    
    printf("請輸入第二個文件名: ");
    if (!fgets(name2, sizeof(name2), stdin)) return EXIT_FAILURE;
    name2[strcspn(name2, "\n")] = '\0';
    
    /* 打開文件 */
    fp1 = fopen(name1, "r");
    if (!fp1) { perror(name1); return EXIT_FAILURE; }
    
    fp2 = fopen(name2, "r");
    if (!fp2) { perror(name2); fclose(fp1); return EXIT_FAILURE; }
    
    /* 交替讀取主循環 */
    int ret1 = 1, ret2 = 1;
    while (ret1 || ret2) {
        ret1 = read_and_print_line(fp1);
        ret2 = read_and_print_line(fp2);
        
        /* 任一文件出錯提前退出 */
        if (ret1 == -1 || ret2 == -1) break;
    }
    
    fclose(fp1);
    fclose(fp2);
    return 0;
}

關鍵改進點解析

1. 模塊化設計:單一職責原則

將「讀一行並輸出」封裝為獨立函數read_and_print_line,返回狀態碼清晰表達三種結果:正常行、末尾行、純EOF。主循環邏輯瞬間清晰。

2. 完美處理「無換行符結尾」場景

POSIX標準要求文本文件以換行符結尾,但現實中大量文件不符合。優化版通過has_content標記,確保最後一行內容即使無\n也能正確輸出並補上換行。

3. 安全的輸入處理

  • fgets替代gets,指定緩衝區上限
  • strcspn高效移除換行符,比手寫循環更標準
  • 路徑緩衝區擴大到4096適應現代文件系統

4. 資源管理嚴謹

錯誤路徑上正確關閉已打開的文件指針,避免洩漏。

進階擴展:通用化N文件交替輸出

/* 可變參數版本:支持任意數量文件交替輸出 */
#include <stdarg.h>

void alternate_print_files(int count, ...) {
    va_list ap;
    FILE **files = malloc(count * sizeof(FILE*));
    va_start(ap, count);
    for (int i = 0; i < count; i++) {
        const char *name = va_arg(ap, const char*);
        files[i] = fopen(name, "r");
        if (!files[i]) { perror(name); /* 清理已打開文件 */ }
    }
    va_end(ap);
    
    int active = count;
    while (active > 0) {
        active = 0;
        for (int i = 0; i < count; i++) {
            if (files[i] && read_and_print_line(files[i])) active++;
        }
    }
    /* 關閉所有文件並釋放內存 */
}

這個練習看似簡單,實則蘊含「邊界條件處理」、「資源安全管理」、「模塊化設計」等工程核心素養。從「能跑通」到「寫得穩、改得動、用得放心」,正是C程序員進階的必經之路。

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