統計文件字符數是C語言文件操作的經典入門練習。本文展示兩種不同的輸入方式:命令行參數傳遞文件名,以及運行時交互式輸入文件名,幫助初學者理解main函數參數與標準輸入的區別應用場景。
適用於腳本調用、管道處理、批量處理場景:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
/* 參數校驗:程序名 + 1個文件名 = 2個參數 */
if (argc != 2) {
fprintf(stderr, "用法: %s <文件名>\n", argv[0]);
exit(EXIT_FAILURE);
}
FILE *fp = fopen(argv[1], "r"); // 只讀模式即可,無需"r+"
if (!fp) {
perror("fopen");
exit(EXIT_FAILURE);
}
long count = 0;
int ch; /* 必須用int接收getc返回值,以便判斷EOF(-1) */
while ((ch = getc(fp)) != EOF) {
putc(ch, stdout); // 同步輸出到屏幕,驗證讀取內容
count++;
}
fclose(fp);
printf("\nFile %s has %ld characters\n", argv[1], count);
return 0;
}
argc包含程序名本身,實際參數從argv[1]開始getc/putc是fgetc/fputc的宏版本,性能略優ch聲明為int而非char,因為EOF通常是-1,超出char範圍stderr輸出錯誤信息,便於重定向分離正常輸出與錯誤輸出適用於用戶直接運行程序、文件名不固定的場景:
#include <stdio.h>
#include <stdlib.h>
#define MAX_FILENAME 256
int main(void) {
FILE *fp;
char filename[MAX_FILENAME];
long count = 0;
int ch;
printf("請輸入文件名: ");
/* 安全讀取:fgets替代危險的gets */
if (fgets(filename, sizeof(filename), stdin) == NULL) {
fprintf(stderr, "讀取輸入失敗\n");
return EXIT_FAILURE;
}
/* 移除fgets保留的換行符 */
filename[strcspn(filename, "\n")] = '\0';
fp = fopen(filename, "r");
if (!fp) {
perror("fopen");
return EXIT_FAILURE;
}
while ((ch = getc(fp)) != EOF) {
putc(ch, stdout);
count++;
}
fclose(fp);
printf("\nFile %s has %ld characters\n", filename, count);
return 0;
}
gets:原代碼使用gets極其危險,無緩衝區長度檢查,已被C11標準移除。改用fgets指定最大長度fgets會保留\n,需手動截斷MAX 80過小,現代文件系統路徑常超過260字符,建議256或PATH_MAX"r"比"r+"更安全if (ch == '\n') lines++;邏輯off_t/fseeko支持64位偏移量argv[1]~argv[argc-1]處理多個文件這兩個版本展示了C程序獲取輸入參數的兩種基本模式。實際開發中,命令行參數版本更符合Unix哲學「做一件事並做好」,便於腳本組合;交互版本適合最終用戶直接使用的小工具。根據使用場景選擇合適的交互方式,是編寫優質命令行工具的關鍵。