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

C语言保留字统计程序问题求助:计数异常与匹配范围受限

修复C语言关键字统计程序的两个问题

嘿,我来帮你搞定这两个问题!咱们先拆解下代码里的核心问题,然后给你修复后的完整代码,再逐一解释改动点~

你的代码里的核心问题

  1. 字符串未正确终止:你把文件内容读入str数组后,没有手动添加'\0'终止符,导致str不是合法的C字符串,后续strtok、strlen这类函数的行为完全不可预测,这是导致只有首个单词被识别的关键原因。
  2. 手动分割单词逻辑漏洞:你虽然定义了strtok但根本没用到,反而自己写的分割逻辑只处理空格,没考虑制表符、换行符等其他分隔符,而且遍历逻辑有缺陷,没法正确提取所有位置的单词。
  3. gets函数不安全:gets完全没有缓冲区溢出保护,很容易导致程序崩溃或被攻击,必须替换成安全的fgets。
  4. 缓冲区过小:str数组只有100字节,输入内容稍长就会溢出,导致数据错乱。

修复后的完整代码

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#define KEYMAX 32
#define BUFFER_SIZE 1024  // 增大缓冲区,避免溢出

struct keyword {
    char word[10];
    int occur;
};

// 清晰初始化关键字数组,每个元素对应一个保留字和计数
struct keyword key[KEYMAX] = {
    {"auto", 0}, {"break", 0}, {"case", 0}, {"char", 0},
    {"const", 0}, {"continue", 0}, {"default", 0}, {"do", 0},
    {"double", 0}, {"else", 0}, {"enum", 0}, {"extern", 0},
    {"float", 0}, {"for", 0}, {"goto", 0}, {"if", 0},
    {"int", 0}, {"long", 0}, {"register", 0}, {"return", 0},
    {"short", 0}, {"signed", 0}, {"sizeof", 0}, {"static", 0},
    {"struct", 0}, {"switch", 0}, {"typedef", 0}, {"union", 0},
    {"unsigned", 0}, {"void", 0}, {"volatile", 0}, {"while", 0}
};

int takeinput();
int theresult();
int binarysearch(char *word, struct keyword key[]);

int main() {
    takeinput();
    system("CLS");
    theresult();
    return 0;
}

int takeinput() {
    printf("**********Welcome*************\n");
    FILE *fp = fopen("test.c", "w");
    if (fp == NULL) {
        printf("Could not open file test.c\n");
        return 1;
    }

    printf("Please enter some text from keyboard to write in the file test.c\n");
    printf("(Press Ctrl+D on Unix or Ctrl+Z on Windows to stop input)\n");

    char data[BUFFER_SIZE];
    // 用fgets替代不安全的gets,避免缓冲区溢出
    while (fgets(data, sizeof(data), stdin) != NULL && strlen(data) > 1) {
        fputs(data, fp);  // fgets会读取换行符,直接写入即可
    }

    fclose(fp);
    return 0;
}

int theresult() {
    FILE *fp = fopen("test.c", "r");
    if (fp == NULL) {
        perror("Error while opening the file.\n");
        return 1;
    }

    printf("The contents of test.c file are:\n");
    char str[BUFFER_SIZE];
    int i = 0;
    int ch;  // 用int接收fgetc,因为EOF是int类型

    // 读取文件到缓冲区,同时防止溢出
    while ((ch = fgetc(fp)) != EOF && i < BUFFER_SIZE - 1) {
        str[i] = (char)ch;
        i++;
    }
    str[i] = '\0';  // 必须添加字符串终止符,确保str是合法C字符串
    printf("%s\n", str);

    // 扩展分隔符,包含常见非字母字符,比如-和.
    char delimiters[] = " \t\n\v\f\r-.";
    char *token;

    // 用strtok正确遍历所有分割后的单词
    for (token = strtok(str, delimiters); token != NULL; token = strtok(NULL, delimiters)) {
        // 把单词转为小写,实现大小写不敏感匹配
        char lower_token[20];
        for (int k = 0; token[k] != '\0'; k++) {
            lower_token[k] = tolower(token[k]);
        }
        lower_token[strlen(token)] = '\0';

        // 二分查找关键字,匹配成功则计数+1
        int pos = binarysearch(lower_token, key);
        if (pos != -1) {
            key[pos].occur++;
        }
    }

    // 打印统计结果
    printf("***********************\n");
    printf(" Keyword\tCount\n");
    printf("***********************\n");
    for (i = 0; i < KEYMAX; i++) {
        if (key[i].occur > 0) {
            printf(" %s\t\t%d\n", key[i].word, key[i].occur);
        }
    }

    fclose(fp);
    return 0;
}

int binarysearch(char *word, struct keyword key[]) {
    int low = 0, high = KEYMAX - 1, mid;
    while (low <= high) {
        mid = (low + high) / 2;
        int cmp = strcmp(word, key[mid].word);
        if (cmp < 0) {
            high = mid - 1;
        } else if (cmp > 0) {
            low = mid + 1;
        } else {
            return mid;
        }
    }
    return -1;
}

关键改动说明

  1. 替换gets为fgets:彻底解决缓冲区溢出问题,同时调整输入逻辑,利用fgets自带的换行符处理,无需额外添加换行。
  2. 添加字符串终止符:在读取文件到str后,手动添加'\0',确保后续字符串操作都能正常工作。
  3. 用strtok处理所有单词:真正利用strtok遍历所有分割后的单词,扩展了分隔符列表,能正确处理带-、.的文本。
  4. 大小写不敏感匹配:把每个单词转为小写后再匹配关键字,不管输入是Float还是float都能正确统计。
  5. 增大缓冲区:定义BUFFER_SIZE为1024,避免输入内容过长导致溢出。
  6. 清晰化关键字初始化:用结构体初始化语法逐个定义关键字,更易读且不易出错。

测试效果

输入你提供的内容:

if i break please re-join it. float float

输出会是:

The contents of test.c file are:
if i break please re-join it. float float

***********************
 Keyword	Count
***********************
 if		1
 break		1
 float		2

这样就完美解决了你提到的两个问题:所有位置的关键字都能被识别,且准确统计每个关键字的实际使用次数~

内容的提问来源于stack exchange,提问作者Saujanya Prasoon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:38:54