使用strtok从文件读取字符串到数组时丢失首行内容的问题
问题分析:getline与strtok配合导致首句丢失
我尝试读取input.txt文件,将所有以.!?结尾的句子保存到数组中,使用getline和strtok实现。保存句子时输出看似正常,但后续通过索引检索数据时,首行内容丢失。
输入文件内容
The wandering earth! In 2058, the aging Sun? is about to turn into a red .giant and threatens to engulf the Earth's orbit!
原代码
#include <stdio.h> #include <string.h> #include <stdlib.h> int main() { FILE *fp = fopen("input.txt", "r+"); char *line = NULL; size_t len = 0; char *sentences[100]; if (fp == NULL) { perror("Cannot open file!"); exit(1); } char delimit[] = ".!?"; int i = 0; while (getline(&line, &len, fp) != -1) { char *p = strtok(line, delimit); while (p != NULL) { sentences[i] = p; printf("sentences [%d]=%s\n", i, sentences[i]); i++; p = strtok(NULL, delimit); } } for (int k = 0; k < i; k++) { printf("sentence is ----%s\n", sentences[k]); } return 0; }
程序输出
sentences [0]=The wandering earth sentences [1]= In 2058, the aging Sun sentences [2]= is about to turn into a red sentences [3]=giant and threatens to engulf the Earth's orbit sentence is ---- sentence is ---- In 2058, the aging Sun sentence is ---- is about to turn into a red sentence is ----giant and threatens to engulf the Earth's orbit
问题根源
strtok返回的是指向**原字符串(line指向的堆内存)**的指针,而非新分配的内存。你的sentences数组存储的都是指向同一块内存的指针,一旦line指向的内容被修改(比如getline后续调用的内存操作、堆内存意外覆盖等),所有sentences中的指针都会受到影响。
在你的场景中,虽然表面上只有一行数据,但getline在循环结束前的最后一次调用(返回-1)可能触发了内存管理操作,间接修改了line开头的内容;或者是栈/堆内存的意外覆盖,导致第一个指针指向的内容被清空。
解决方案
必须为每个分割出的句子独立分配内存并复制内容,避免依赖line的内存。可以使用strdup函数(内部封装了malloc和strcpy)来实现:
修正后的代码
#include <stdio.h> #include <string.h> #include <stdlib.h> int main() { FILE *fp = fopen("input.txt", "r"); // 只读模式足够,无需r+ char *line = NULL; size_t len = 0; char *sentences[100]; if (fp == NULL) { perror("Cannot open file!"); exit(1); } char delimit[] = ".!?"; int i = 0; while (getline(&line, &len, fp) != -1) { char *p = strtok(line, delimit); while (p != NULL) { // 复制字符串到新分配的内存 sentences[i] = strdup(p); if (sentences[i] == NULL) { perror("strdup failed"); exit(1); } printf("sentences [%d]=%s\n", i, sentences[i]); i++; p = strtok(NULL, delimit); } } for (int k = 0; k < i; k++) { printf("sentence is ----%s\n", sentences[k]); // 释放分配的内存,避免泄漏 free(sentences[k]); } // 释放getline分配的内存 free(line); fclose(fp); return 0; }
关键修改点
- 将
sentences[i] = p;改为sentences[i] = strdup(p);,为每个句子独立分配内存并复制内容。 - 添加内存释放逻辑:循环结束后释放每个
sentences元素的内存,以及getline分配的line内存。 - 将文件打开模式从
r+改为r,因为只需要读取操作,避免不必要的读写权限。
修正后输出
sentences [0]=The wandering earth sentences [1]= In 2058, the aging Sun sentences [2]= is about to turn into a red sentences [3]=giant and threatens to engulf the Earth's orbit sentence is ----The wandering earth sentence is ---- In 2058, the aging Sun sentence is ---- is about to turn into a red sentence is ----giant and threatens to engulf the Earth's orbit
内容的提问来源于stack exchange,提问作者Yadan Wei
相关产品推荐
相关产品推荐

