Linux系统编程2标准IO - fopen

学习自李慧琴老师


实验1 fopen.c :在当前路径下打开一个不存在的文件 “tmp”

实验2:man手册中的头文件一定要全部加进去、

int *p = malloc(sizeof(int));

问题: FILE *fopen(const char *path, const char *mode); 返回的结构体指针所指向的空间是哪里??


一 概述

#include <stdio.h>
/*
参数 const char *path,文件名,可以相对路径或绝对路径
参数 const char *mode, 权限
返回值 FILE *
*/
FILE *fopen(const char *path, const char *mode);

1.1 权限mode说明

man fopen 可以查看关于 fopen() mode权限的说明:

The argument mode points to a string beginning with one of the following sequences (possibly followed by additional characters, as described below):

即指向一个以下列字符开头的字符串,只要开头是下列字符即可,后续字符不重要
rasdfghj == r
wsdfgh == w
r+fghjhj == r+

r 和 r+形式打开文件的时候,要求文件必须存在。

r : Open text file for reading. The stream is positioned at the beginning of the file.

只读方式打开文件,当前文件位置指针定位到文件起始位置


r+ :Open for reading and writing. The stream is positioned at the beginning of the file.

以读写方式打开文件,当前文件位置指针定位到文件起始位置


以下为无则创建方式:

w :Truncate(截断) file to zero length or create text file for writing. The stream is positioned at the beginning of the file.

有则清空文件,无则以只写方式创建文件,当前文件位置指针定位到文件起始位置


w+:Open for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file.

有则清空文件,无则以读写方式创建文件,当前文件位置指针定位到文件起始位置


a:Open for appending (writing at end of file). The file is created if it does not exist. The stream is positioned at the end of the file.

有则以追加只写的方式打开文件,写到文件的末尾处,无则创建文件,当前文件位置指针定位到文件末尾位置(文件的最后一个有效字节的下一个位置)


a+ :Open for reading and appending (writing at end of file). The file is created if it does not exist. The initial file position for reading is at the beginning of the file, but output is always appended to the end of the file.
有则以读写方式打开文件,读方式打开的时候,当前文件指针定位到文件起始位置,写方式打开的时候,当前文件位置指针定位到文件末尾位置,无则创建文件。


The mode string can also include the letter ‘b’ either as a last character or as a character between the characters in any of the two-character strings described above. This is strictly for compatibility with C89 and has no effect; the ‘b’ is ignored on all POSIX conforming systems, including Linux. (Other systems may treat text files and binary files differently, and adding
the ‘b’ may be a good idea if you do I/O to a binary file and expect that your program may be ported to non-UNIX environments.)

模式字符串还可以将字母“b”作为最后一个字符,或者作为上述任何两个字符字符串中的字符之间的字符。但是在所有与POSIX兼容的系统上(包括Linux),“b”都被忽略。(其他系统可能会以不同的方式对待文本文件和二进制文件,并进行添加,如果您对二进制文件执行I/O操作,并且希望将程序移植到非unix环境中,那么“b”可能是个好主意。

在Windows环境下其实是包含两种流的,一种是文本流,一种是二进制流,这这两种流在程序当中的控制是不一样的,所以在Windows环境下开发,要指定是以 r 方式打开 ,还是以rb方式打开,也就是把当前流作为哪种流的形式打开。
Linux 环境下只有一种流,即文本流 stream ,在Linux 环境下没有必要加b,但是如果程序后面可能移植到windows环境下跑,那么要加b


1.2 返回值

RETURN VALUE
Upon successful completion fopen(), fdopen() and freopen() return a FILE pointer. Otherwise, NULL is returned and errno is set to indicate the error.
成功返回 FILE pointer,失败返回对应errno(ionumber)

1.2.1 errno宏说明

errno说明:它是宏
/usr/include/asm-generic
errno-base.h
errno.h

errno-base.h 中就是我们常见的报错宏值与宏名
mhr@ubuntu:/usr/include/asm-generic$ cat errno-base.h

#ifndef _ASM_GENERIC_ERRNO_BASE_H
#define _ASM_GENERIC_ERRNO_BASE_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 */
#define	ENOEXEC		 8	/* Exec format error */
#define	EBADF		 9	/* Bad file number */
#define	ECHILD		10	/* No child processes */
#define	EAGAIN		11	/* Try again */
#define	ENOMEM		12	/* Out of memory */
#define	EACCES		13	/* Permission denied */
#define	EFAULT		14	/* Bad address */
#define	ENOTBLK		15	/* Block device required */
#define	EBUSY		16	/* Device or resource busy */
#define	EEXIST		17	/* File exists */
#define	EXDEV		18	/* Cross-device link */
#define	ENODEV		19	/* No such device */
#define	ENOTDIR		20	/* Not a directory */
#define	EISDIR		21	/* Is a directory */
#define	EINVAL		22	/* Invalid argument */
#define	ENFILE		23	/* File table overflow */
#define	EMFILE		24	/* Too many open files */
#define	ENOTTY		25	/* Not a typewriter */
#define	ETXTBSY		26	/* Text file busy */
#define	EFBIG		27	/* File too large */
#define	ENOSPC		28	/* No space left on device */
#define	ESPIPE		29	/* Illegal seek */
#define	EROFS		30	/* Read-only file system */
#define	EMLINK		31	/* Too many links */
#define	EPIPE		32	/* Broken pipe */
#define	EDOM		33	/* Math argument out of domain of func */
#define	ERANGE		34	/* Math result not representable */

注意:
man手册中的头文件一定要全部加进去。

实验1 fopen.c :在当前路径下打开一个不存在的文件 “tmp”

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	FILE *fp;
	//
	fp = fopen("tmp","r");
	if(fp == NULL)
	{
		fprintf(stderr,"fopen() failed! errno = %d\n",errno);
//更清楚的查看出错原因,两个很好用的函数perror,strerror
		perror("fopen()");
		fprintf(stderr,"fopen():%s\n",strerror(errno));
		exit(1);	
	}
	puts("OK!");
	exit(0);

}
mhr@ubuntu:~/work/linux/stdio$ ./a.out 
fopen() failed! errno = 2
fopen(): No such file or directory
fopen():No such file or directory
mhr@ubuntu:~/work/linux/stdio$ 

perror("fopen()");

NAME
       perror - print a system error message
perror()函数在标准错误上生成一条消息,描述在调用系统函数或库函数时遇到的最后一个错误。

SYNOPSIS
       #include <stdio.h>

       void perror(const char *s);
       #include <errno.h>

       const char * const sys_errlist[];
       int sys_nerr;
       int errno; /* perror()会主动关联到 errno, 即err number ,所以也要加头文件errno.h */

strerror()

NAME
       strerror, strerror_r, strerror_l - return string describing error number
       返回描述错误号的字符串
SYNOPSIS
       #include <string.h>

       char *strerror(int errnum);

实验2:man手册中的头文件一定要全部加进去。

如下语句:

int *p = malloc(sizeof(int));

int型指针指向一个大小为一个整形值大小的空间,这段代码会被警告 两边类型不匹配。
为什么?
malloc() 的返回值是 void* ,malloc()所在的头文件是 stdib.h标准库头文件,如果没有包含该头文件,会造成如下现象,gcc看到 int p = malloc(sizeof(int)); 的时候,由于没包含头文件,gcc会认为所有函数的返回值都是整型,把一个整幸值赋值给一个整型指针,当然会警告。加上文件,返回void 类型指针,void* 类型指针赋值给任何类型指针都是可以的,反之异常。


问题; FILE *fopen(const char *path, const char *mode); 返回的结构体指针所指向的空间是哪里??

三种情况之一。栈,静态区,堆

情况1,栈
不会是栈,栈空间数据会在函数调用结束后被清空
在这里插入图片描述

情况2,静态存储区
如果是静态区,静态区数据确实可以完整的保留,直到进程结束为止。但是 static 修饰的静态区变量有一个最大的特点,即不论该函数被调用多少次,该static 静态区变量声明只被一次,如
在这里插入图片描述
所以 不论调用多少次fopen(),如果 FILE 结构体位于静态区,那么该函数内部的 static FILE tmp 将只被执行一次,后面的无论调用多少次 fopen,都不会再被执行,也就是说除第一次调用fopen 之外,后面所有的fopen ,不论打开什么文件,返回的都是第一次开的文件信息,这样是不行的。
在这里插入图片描述

情况3,堆 ,可行的
所以 fclose()中会有一个 free(),

小技巧:如果一个函数的返回值是指针,会有一个与该函数对应的逆操作,此时基本可以确认该函数返回的指针执行的空间是堆空间。
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux老A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值