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

實戰:從文本文件讀取整數並歸並排序輸出

     編輯:關於C語言

程序說明

本程序演示完整的文件讀取、動態內存管理、歸並排序與文件寫入流程。具備健壯的錯誤檢查機制,涵蓋文件操作、歸並排序、字符串安全讀取等核心技術。

  • 功能:讀取指定文本文件中的整數 → 動態數組存儲 → 歸並排序 → 按每行 10 個數字格式寫入目標文件。
  • 輸入要求:源文件僅包含數字與空白字符(空格、制表符、換行符),首字符必為數字,數據個數需與聲明一致。

完整代碼

代碼圖示

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

/*============================= 製作於:Aug 16, 2016 ===============================*/
#define ST 64  // 字符串緩衝區大小

void mergesort(int *, int);
void _mergesort(int *, int, int, int *);
void merge(int *, int, int, int, int *);
char *s_gets(char *, int);

int main(int argc, char *argv[]) {
    FILE *sor, *dest;       // 源文件、目標文件
    int *ptr;               // 動態數組指針
    int i, n;               // n 為元素個數
    char fname[ST];         // 文件名緩衝區

    /* 1. 獲取元素個數 */
    printf("請輸入元素個數: ");
    while (scanf("%d", &n) != 1 || n <= 0) {
        printf("輸入錯誤,請重新輸入!\n");
        while (getchar() != '\n') continue;  // 清空輸入緩衝區
    }
    while (getchar() != '\n') continue;

    /* 2. 分配動態數組 */
    ptr = (int *)malloc((size_t)n * sizeof(int));
    if (ptr == NULL) {
        fprintf(stderr, "FAIL TO ASK FOR MEMORY SPACE\n");
        exit(EXIT_FAILURE);
    }

    /* 3. 讀取源文件名並打開 */
    printf("請輸入原文件名: ");
    if (s_gets(fname, ST) == NULL) {
        fprintf(stderr, "Fail to get a string\n");
        exit(EXIT_FAILURE);
    }
    sor = fopen(fname, "r");
    if (sor == NULL) {
        fprintf(stderr, "Fail to open the source file\n");
        exit(EXIT_FAILURE);
    }

    /* 4. 讀取數據到動態數組 */
    for (i = 0; i < n; i++) {
        if (fscanf(sor, "%d", &ptr[i]) != 1) {
            fprintf(stderr, "Fail to get the data\n");
            exit(EXIT_FAILURE);
        }
    }

    /* 5. 歸並排序 */
    mergesort(ptr, n);

    /* 6. 寫入目標文件 */
    printf("請輸入要保存數據的文件名:");
    if (s_gets(fname, ST) == NULL) {
        fprintf(stderr, "Fail to get a string\n");
        exit(EXIT_FAILURE);
    }
    dest = fopen(fname, "w");
    if (dest == NULL) {
        fprintf(stderr, "Fail to open the destination file\n");
        exit(EXIT_FAILURE);
    }
    for (i = 0; i < n; i++) {
        if (fprintf(dest, "%d\t", ptr[i]) < 0) {
            fprintf(stderr, "Fail to save the data\n");
            exit(EXIT_FAILURE);
        }
        if (((i + 1) % 10) == 0) {  // 每 10 個換行
            if (fprintf(dest, "\n") < 0) {
                fprintf(stderr, "Fail to save the data\n");
                exit(EXIT_FAILURE);
            }
        }
    }

    /* 7. 關閉文件、釋放內存 */
    if (fclose(sor) != 0) {
        fprintf(stderr, "Fail to close the source file\n");
        exit(EXIT_FAILURE);
    }
    if (fclose(dest) != 0) {
        fprintf(stderr, "Fail to close the destination file\n");
        exit(EXIT_FAILURE);
    }
    free(ptr);
    printf("成功完成!\n請按任意鍵繼續^ ^\b\b");
    getch();
    return 0;
}

/* --- 歸並排序實現 --- */
void mergesort(int *ar, int size) {
    if (size > 0) {
        int *temp = (int *)malloc((size_t)size * sizeof(int));
        if (temp == NULL) {
            fprintf(stderr, "Fail to ask for MEMORY SPACE\n");
            exit(EXIT_FAILURE);
        }
        _mergesort(ar, 0, size - 1, temp);
        free(temp);
    }
}

void _mergesort(int *ar, int start, int end, int *temp) {
    if (start < end) {
        int mid = (start + end) / 2;
        _mergesort(ar, start, mid, temp);
        _mergesort(ar, mid + 1, end, temp);
        merge(ar, start, mid, end, temp);
    }
}

void merge(int *ar, int p, int q, int r, int *temp) {
    int i = p, j = q + 1, k = 0;
    while (i <= q && j <= r) {
        if (ar[i] < ar[j]) temp[k++] = ar[i++];
        else temp[k++] = ar[j++];
    }
    while (i <= q) temp[k++] = ar[i++];
    while (j <= r) temp[k++] = ar[j++];
    for (k = 0; k <= (r - p); k++) ar[p + k] = temp[k];
}

/* --- 安全字符串讀取:去除換行符並清空緩衝區 --- */
char *s_gets(char *st, int size) {
    char *ret = fgets(st, size, stdin);
    if (ret) {
        int i = 0;
        while (st[i] != '\n' && st[i] != '\0') i++;
        if (st[i] == '\n') st[i] = '\0';
        else while (getchar() != '\n') continue;
    }
    return ret;
}

運行結果展示

程序運行截圖

data.txt(輸入文件):

data.txt 內容

obj.txt(輸出文件):

obj.txt 內容

關鍵點總結

  • 動態內存分配必檢查返回值,用畢即釋放。
  • 文件操作每一步驗證返回值,防止靜默失敗。
  • s_gets 封裝 fgets,自動處理換行符與緩衝區殘留,避免後續輸入讀取異常。
  • 歸並排序採用遞歸分治,輔助數組在頂層分配一次,避免重複分配開銷。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved