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

C语言:为何调用无关函数后未操作的字符串指针值改变?

字符串指针值意外变更的原因及修复

问题现象

使用程序提取文件中的姓与名时,出现指针内容意外被修改的情况:

  • 当f1文件内容为Martin、f2文件内容为Joseph时,调用GetPrenom(f2)能得到正确结果Joseph;
  • 但调用GetNom(f1)后,原本的prenom指针指向的内容变为Martin,最终打印结果不符合预期。

问题代码

#include<stdlib.h>
#include<string.h>
#include <stdarg.h>      

char* GetNom(FILE* f1) {
    
    char* nam = malloc(25 * sizeof(char));
    fseek (f1, 0, SEEK_END);
    int length = ftell (f1);
    fseek (f1, 0, SEEK_SET);
    char line1[length];
    fgets(line1, length, f1);
    nam = strtok(line1, " , ");
    rewind(f1);
    return nam ;
}
char* GetPrenom( FILE* f2) {
    
    char* lastname = malloc(25 * sizeof(char));
    fseek (f2, 0, SEEK_END);
    int length = ftell (f2);
    fseek (f2, 0, SEEK_SET);
    char line2[length];
    fgets(line2, length, f2);
    lastname  = strtok(line2, " ; ");
    rewind(f2);
    return lastname ;
}

int main() {
        FILE* f1 = ....; //openning the two files 
        FILE* f2 = ....;    

        char* prenom = GetPrenom(f2);
        char* nom = GetNom(f1);
        printf("%s \n", prenom);
        
    return 0;
}

原因分析

  1. 栈内存被复用覆盖:函数中的line1、line2是栈上的局部数组,函数执行完毕返回时,这块栈内存会被系统回收。strtok返回的指针指向的是这些栈数组的内存地址,后续调用GetNom时,新的栈局部变量会覆盖之前GetPrenom中line2占用的栈内存,导致prenom指针指向的内容被修改。
  2. 内存泄漏:函数开头用malloc分配的内存被直接赋值为strtok的返回值,原malloc指针被丢弃,造成内存泄漏。

修复方案

将strtok分割后的字符串复制到malloc分配的堆内存中,避免返回栈内存指针:

#include<stdlib.h>
#include<string.h>
#include <stdarg.h>      

char* GetNom(FILE* f1) {
    
    char* nam = malloc(25 * sizeof(char));
    if (nam == NULL) { // 检查内存分配是否成功
        return NULL;
    }
    fseek (f1, 0, SEEK_END);
    int length = ftell (f1);
    fseek (f1, 0, SEEK_SET);
    char line1[length + 1]; // 多留一个位置存储字符串结束符
    fgets(line1, sizeof(line1), f1);
    char* token = strtok(line1, " , ");
    if (token != NULL) {
        strncpy(nam, token, 24); // 复制到堆内存,预留结束符位置
        nam[24] = '\0'; // 确保字符串以结束符收尾
    } else {
        nam[0] = '\0'; // 处理无有效分割结果的情况
    }
    rewind(f1);
    return nam ;
}
char* GetPrenom( FILE* f2) {
    
    char* lastname = malloc(25 * sizeof(char));
    if (lastname == NULL) {
        return NULL;
    }
    fseek (f2, 0, SEEK_END);
    int length = ftell (f2);
    fseek (f2, 0, SEEK_SET);
    char line2[length + 1];
    fgets(line2, sizeof(line2), f2);
    char* token = strtok(line2, " ; ");
    if (token != NULL) {
        strncpy(lastname, token, 24);
        lastname[24] = '\0';
    } else {
        lastname[0] = '\0';
    }
    rewind(f2);
    return lastname ;
}

int main() {
        FILE* f1 = fopen("f1.txt", "r"); // 补充文件打开逻辑
        FILE* f2 = fopen("f2.txt", "r");    

        if (f1 == NULL || f2 == NULL) {
            perror("Failed to open file");
            return 1;
        }

        char* prenom = GetPrenom(f2);
        char* nom = GetNom(f1);
        printf("%s \n", prenom);
        
        // 释放堆内存,避免泄漏
        free(prenom);
        free(nom);
        // 关闭文件,释放资源
        fclose(f1);
        fclose(f2);
        
    return 0;
}

修复要点

  • 不再直接返回栈数组指针,而是将分割结果复制到堆内存中返回;
  • 增加malloc成功检查,避免空指针操作;
  • 使用strncpy控制复制长度,防止内存越界;
  • 在main函数中补充文件关闭和堆内存释放逻辑,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 23:35:27