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

#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(輸入文件):

obj.txt(輸出文件):

s_gets 封裝 fgets,自動處理換行符與緩衝區殘留,避免後續輸入讀取異常。