fopen函数

发布时间:2024年01月12日

目录

fopen函数

C 库函数 fopen 使用给定的模式 mode 打开 filename 所指向的文件。

FILE *fopen(const char *filename, const char *mode)
  • filename — 字符串,表示要打开的文件名称。
  • mode — 字符串,表示文件的访问模式,该指针指向以下面字符开头的字符串:
    在这里插入图片描述

mode也可以包含字母b,放在最后或者中间,表示二进制流。例如“rb”,“r+b”;(如果你的程序以后要移植到windows环境下可以加上b,在linux环境下则不需要,linux只有流的概念,没有二进制的概念)

  • 该函数返回一个 FILE 指针。否则返回 NULL,且设置全局变量 errno 来标识错误。该全局变量在头文件errno.h中声明:(只展示部分)
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */

代码示例

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>

int main(){
    FILE *fp;
    fp=fopen("temp","r");
    if(fp==NULL){
        fprintf(stderr,"fopen() failed! errno = %d\n",errno);
        exit(1);
    }
    puts("OK");
    exit(0);
}

编译执行后打印结果:
在这里插入图片描述

可知errno为2,为No such file or directory;

在C标准中定义了两个函数帮助打印输出errno的对应错误原因,一个是strerror,另一个是perror;


perror包含在stdio.h中:

//函数原型
/*
*功能:根据error打印对应的错误信息
*参数:s: 用户自定义信息字符串,一般是出错的函数名
*/
void perror(const char *s);

修改后的程序为:

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>

int main(){
    FILE *fp;
    fp=fopen("temp","r");
    if(fp==NULL){
        //fprintf(stderr,"fopen() failed! errno = %d\n",errno);
        perror("errno");
        exit(1);
    }
    puts("OK");
    exit(0);
}

打印结果:
在这里插入图片描述


strerror包含在<string.h>头文件中

//函数原型
/*
*功能:将某个错误代码转换成对应的错误信息
*/
char *strerror(int errnuum);

修改后的程序为:

fprintf(stderr, "fopen:%s\n", strerror(errno));

fopen函数解析:

由函数原型可知,fopen函数返回的是一个FILE类型的指针,FILE是一个结构体,由typedef进行了重命名,而指针实际上是指向结构体的指针。

问题:指针指向的内存空间是哪一块(或者说FILE结构体放在内存的哪一块)?是堆,是栈,还是静态区?

1、栈

// 简单的fopen源码分析
FILE *fopen(const char *filename, const char *mode) {
    FILE tmp;
    
    // 给结构体成员赋值初始化
    tmp.xxx = xxx;
    tmp.yyy = yyy;
    ...
        
    return &tmp;
}

分析:tmp变量的存储类别是自动类型(块作用域,自动存储期),当程序退出这个块时,释放刚才为变量tmp匹配的内存,因此,指针指向的地址实际上没有tmp,是一个没有被分配的内存;
2、静态区

// 简单的fopen源码分析
FILE *fopen(const char *filename, const char *mode) {
    static FILE tmp;
    
    // 给结构体成员赋值初始化
    tmp.xxx = xxx;
    tmp.yyy = yyy;
    ...
        
    return &tmp;
}

加上static,将tmp保存在静态区(静态无链接),但是只能存在一个FILE实例(因为只有这一个内存区供指针指向);调用10次fopen函数,内存还是只有这一块,打开第一个文件时,是正确的,但在打开第二个文件时,就会把第一个的结果覆盖掉,第一个文件就没法操作了,会出错。例如:

fp1 = fopen("a", "r");
fp2 = fopen("b", "r");
// 此时fp1实际指向了b,第二次的结果会把第一次的结果覆盖掉

3、堆(正解)

// 简单的fopen源码分析
FILE *fopen(const char *filename, const char *mode) {
    FILE *tmp = NULL;
    tmp = malloc(sizeof(FILE));
    
    // 给结构体成员赋值初始化
    tmp->xxx = xxx;
    tmp->yyy = yyy;
    ...
        
    return tmp;
}

此时变量tmp具有动态存储期,从调用malloc分配内存到调用free释放内存为止,而free就在fclose函数中被调用。

文章来源:https://blog.csdn.net/mhyasadj/article/details/135545681
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。