使用fseek、fread与指针读取文件:为何fseek不改变指针地址?
关于fseek()和fread()的工作机制,以及你代码里的关键问题
嘿,我先直接点出你代码里的核心问题——你把char**类型的指针传给了需要FILE*的fread和fseek,这是完全错误的用法,会导致未定义行为(编译器大概率会报错或警告)。这也是你疑惑的根源之一,先理清这个,再解释fseek和fread的机制:
1. 先纠正你的用法错误
fread和fseek的第四个参数必须是**FILE*类型的文件流指针**,它指向标准库维护的一个文件流结构体,这个结构体里包含了文件的描述符、缓冲区、当前读取/写入的位置指示器等状态信息。而你代码里的point是char**,指向的是字符串数组,和文件流完全不是一回事,直接传递会让函数操作错误的内存区域,结果完全不可预测。
另外要注意:你定义的char *x[5]是指针数组,每个元素指向独立的字符串,这些字符串在内存中不一定是连续存储的,就算强制当成流处理,读取结果也会和预期不符。
2. 正确理解fseek()和fread()的工作逻辑
它们操作的是文件流内部的位置指示器,而不是你传入的FILE*指针本身:
- 当你调用
fread时,它会从流的当前位置指示器指向的位置读取数据,读取完成后自动把指示器向后移动对应字节数。 fseek的作用是修改这个流结构体里的位置指示器的值,比如你用SEEK_CUR偏移5字节,就是把当前位置加上5。但它不会改变你传入的FILE*指针的地址——因为FILE*只是指向流结构体的指针,函数修改的是结构体内部的数据,不是指针本身的地址。
举个适配你场景的正确示例(用内存流模拟文件操作,适合处理内存中连续的图像数据):
#include <stdio.h> #include <string.h> #include <stdlib.h> int main() { char *x[5]={"axxxx","aaaa","hxxx","rrrrr","xsdsdd"}; // 先把分散的字符串拷贝到连续内存块,模拟文件的连续内容 char* continuous_data = malloc(64); if (!continuous_data) { perror("malloc failed"); return 1; } int offset = 0; for (int i=0; i<5; i++) { strcpy(continuous_data + offset, x[i]); offset += strlen(x[i]); } char buffer[65]={0}; // 把连续内存包装成FILE*流 FILE* mem_stream = fmemopen(continuous_data, offset, "r"); if (!mem_stream) { perror("fmemopen failed"); free(continuous_data); return 1; } // 第一次读取6字节 fread(buffer, 6, 1, mem_stream); printf("First read result: %s\n", buffer); // 从当前位置偏移5字节 fseek(mem_stream, 5, SEEK_CUR); memset(buffer, 0, sizeof(buffer)); // 第二次读取6字节 fread(buffer, 6, 1, mem_stream); printf("Second read result: %s\n", buffer); fclose(mem_stream); free(continuous_data); return 0; }
3. 为什么fseek不会改变指针的地址或让它递增?
- 首先,你的
point不是FILE*,所以这个问题本身基于错误的用法。但假设是正确的FILE*指针: fseek接收的是FILE*的值传递(除非你传FILE**),函数内部修改的是流结构体里的位置指示器,而不是传入的指针变量本身。打个比方:你有一个结构体指针struct Person* p,你调用函数change_age(p, 20)修改结构体里的age成员,p的地址不会变,变的是p->age的值——fseek就是类似的逻辑,它修改的是FILE结构体里的位置成员,不是FILE*指针的地址。
总结一下:你混淆了内存数组指针和文件流指针的概念,fseek和fread只针对FILE*流操作,修改的是流内部的位置状态,而不是指针本身的地址。
内容的提问来源于stack exchange,提问作者IDEN
相关产品推荐
相关产品推荐

