编译与执行耗时过长咨询:fgetc是否为性能瓶颈?
问题分析与解决方案
编译慢和fgetc无关
编译耗时6秒和fgetc没有任何关系,标准库函数的编译开销可以忽略不计。可能的原因包括:
- 编译器未开启优化(默认
-O0会做大量调试检查,编译速度慢),可尝试添加-O2优化选项; - 系统资源不足(CPU、内存被其他程序占用);
- 杀毒软件实时扫描编译生成的可执行文件。
执行慢的核心原因:死循环
你的代码存在无限死循环风险,这才是执行耗时久的关键,和fgetc本身无关:get_data函数里的几个while(ch != ' ')循环,没有判断ch是否为EOF(文件结束符)。一旦读到文件末尾,ch会被设为EOF,而EOF != ' '永远成立,循环会无限执行,导致程序卡死。
比如处理最后一行时,如果文件末尾没有换行符,读取完内容后ch变为EOF,后续的while(ch != ' ')就会无限循环。
修复后的代码
先修复死循环问题,同时纠正变量名对应错误(原代码把姓氏存到first数组、名字存到surname数组,逻辑颠倒):
#include <stdio.h> #define LENGTH_FIRST_NAME 10 #define LENGTH_SUR_NAME 15 #define NUMBER_NAMES 2 void get_data(FILE *file_ptr, char first[][LENGTH_FIRST_NAME], char middle[][LENGTH_FIRST_NAME], char surname[][LENGTH_SUR_NAME], int number_items); int main() { char first[NUMBER_NAMES][LENGTH_FIRST_NAME] = {0}, middle[NUMBER_NAMES][LENGTH_FIRST_NAME] = {0}, surname[NUMBER_NAMES][LENGTH_SUR_NAME] = {0}; FILE *file_ptr; if((file_ptr = fopen("names.txt", "r")) != NULL) puts("--File Found--"); else { puts("--File not Found--"); return 1; // 文件打开失败直接退出,避免空指针操作 } get_data(file_ptr, first, middle, surname, NUMBER_NAMES); for(int i = 0; i < NUMBER_NAMES; i++) { printf("%-20s %-10s %s\n", surname[i], first[i], middle[i]); } fclose(file_ptr); return 0; } void get_data(FILE *file_ptr, char first[][LENGTH_FIRST_NAME], char middle[][LENGTH_FIRST_NAME], char surname[][LENGTH_SUR_NAME], int number_items) { int ch = 0, i = 0; for(int j = 0; j < number_items; j++) { // 读取姓氏 i = 0; while((ch = fgetc(file_ptr)) != ',' && ch != EOF && i < LENGTH_SUR_NAME - 1) surname[j][i++] = ch; surname[j][i] = '\0'; if(ch == EOF) break; // 提前结束,避免无效操作 // 跳过逗号后的空格 while(ch != ' ' && ch != EOF) ch = fgetc(file_ptr); if(ch == EOF) break; // 读取名字 i = 0; while((ch = fgetc(file_ptr)) != ' ' && ch != '\n' && ch != EOF && i < LENGTH_FIRST_NAME - 1) first[j][i++] = ch; first[j][i] = '\0'; if(ch == EOF) break; // 读取中间名(如果存在) if(ch != '\n') { while(ch != ' ' && ch != EOF) ch = fgetc(file_ptr); if(ch == EOF) break; i = 0; while((ch = fgetc(file_ptr)) != '\n' && ch != EOF && i < LENGTH_FIRST_NAME - 1) middle[j][i++] = ch; middle[j][i] = '\0'; } } }
额外优化建议
用fgetc逐字符解析容易出错且代码繁琐,建议改用整行读取+字符串解析的方式,代码更简洁高效:
#include <stdio.h> #include <string.h> #define LENGTH_FIRST_NAME 10 #define LENGTH_SUR_NAME 15 #define NUMBER_NAMES 2 #define LINE_BUFFER 100 void get_data(FILE *file_ptr, char first[][LENGTH_FIRST_NAME], char middle[][LENGTH_FIRST_NAME], char surname[][LENGTH_SUR_NAME], int number_items); int main() { char first[NUMBER_NAMES][LENGTH_FIRST_NAME] = {0}, middle[NUMBER_NAMES][LENGTH_FIRST_NAME] = {0}, surname[NUMBER_NAMES][LENGTH_SUR_NAME] = {0}; FILE *file_ptr; if((file_ptr = fopen("names.txt", "r")) != NULL) puts("--File Found--"); else { puts("--File not Found--"); return 1; } get_data(file_ptr, first, middle, surname, NUMBER_NAMES); for(int i = 0; i < NUMBER_NAMES; i++) { printf("%-20s %-10s %s\n", surname[i], first[i], middle[i]); } fclose(file_ptr); return 0; } void get_data(FILE *file_ptr, char first[][LENGTH_FIRST_NAME], char middle[][LENGTH_FIRST_NAME], char surname[][LENGTH_SUR_NAME], int number_items) { char line[LINE_BUFFER]; int j = 0; while(fgets(line, LINE_BUFFER, file_ptr) != NULL && j < number_items) { char temp_middle[LENGTH_FIRST_NAME] = {0}; // 解析带中间名的格式 if(sscanf(line, "%[^,], %s %s", surname[j], first[j], temp_middle) == 3) { strncpy(middle[j], temp_middle, LENGTH_FIRST_NAME - 1); middle[j][LENGTH_FIRST_NAME - 1] = '\0'; } // 解析无中间名的格式 else if(sscanf(line, "%[^,], %s", surname[j], first[j]) == 2) { strcpy(middle[j], ""); } j++; } }
这种方式依赖标准库的字符串处理,不仅代码更易读,还能避免逐字符读取时的死循环风险,执行效率也更高。
内容的提问来源于stack exchange,提问作者Peter Kirsch
相关产品推荐
相关产品推荐

