You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编译与执行耗时过长咨询: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 09:17:06