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

使用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;
}

关键修改点

  1. 将sentences[i] = p;改为sentences[i] = strdup(p);,为每个句子独立分配内存并复制内容。
  2. 添加内存释放逻辑:循环结束后释放每个sentences元素的内存,以及getline分配的line内存。
  3. 将文件打开模式从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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 04:01:19