C语言使用fgets和strtok()读取stdin文本仅运行几行就终止的问题求解
问题原因与修复方案
核心问题梳理
- 内存申请逻辑错误:
malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE)写法错误,WORD_BUFFER_SIZE是整型常量,sizeof(WORD_BUFFER_SIZE)实际得到的是整型的字节数(通常为4),而非预期的50字节,导致申请的内存远小于实际需要,写入越界触发程序崩溃。 text内存未初始化:strcat要求目标字符串必须以\0结尾,malloc申请的内存是未初始化的随机值,无法确定\0位置,直接调用strcat会发生非法内存访问。- 输入缓冲区残留换行符:前面
scanf("%s", word)读取到====后,输入流中还残留了换行符,会被后续fgets当做第一行内容读取。 strtok分隔符设置不全:仅设置空格为分隔符,没有包含fgets读取的每行末尾自带的换行符,会导致单词粘连换行符,也可能出现拆分异常。- 缺少边界校验:停用词数组、输入缓冲区都没有做写入边界判断,极端输入下容易触发溢出。
修正后代码
#define WORD_BUFFER_SIZE 50 #define TEXT_SIZE 200 // 计算实际需要的文本缓冲区大小 #define TEXT_BUFFER_SIZE (WORD_BUFFER_SIZE * TEXT_SIZE) int main(void) { char stopWords[TEXT_SIZE][WORD_BUFFER_SIZE]; char word[WORD_BUFFER_SIZE]; int numberOfWords = 0; while(scanf("%s", word) == 1){ // 停用词数量边界校验 if (numberOfWords >= TEXT_SIZE) { break; } if (strcmp(word, "====") == 0){ break; } // 单词长度校验,避免溢出 if (strlen(word) < WORD_BUFFER_SIZE) { strcpy(stopWords[numberOfWords], word); numberOfWords++; } } // 消耗掉scanf残留的换行符 while(getchar() != '\n'); char *buffer = malloc(TEXT_BUFFER_SIZE); char *text = malloc(TEXT_BUFFER_SIZE); // 内存分配失败判断 + text初始化 if (!buffer || !text) { perror("内存分配失败"); return 1; } text[0] = '\0'; // 初始化text为空白字符串,保证strcat正常工作 while(fgets(buffer, TEXT_BUFFER_SIZE, stdin) != NULL){ // 避免text缓冲区溢出 if (strlen(text) + strlen(buffer) >= TEXT_BUFFER_SIZE) { break; } strcat(text, buffer); } char *k; // 分隔符增加换行、制表符等常见空白符 k = strtok(text, " \n\t\r"); while (k != NULL) { printf("%s\n", k); k = strtok(NULL, " \n\t\r"); } // 释放申请的内存 free(buffer); free(text); return 0; }
内容的提问来源于stack exchange,提问作者RandomDev
相关产品推荐
相关产品推荐

