文件操作和程序预处理

文件操作和编译环境程序预处理


1.文件操作

1.打开和关闭文件

fopenfclose

//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

打开的方式

文件使用方式含义如果指定文件不存在
“r”(只读)为了输入数据,打开一个已经存在的文本文件出错
“w”(只写)为了输出数据,打开一个文本文件建立一个新的文件
“a”(追加)向文本文件尾添加数据建立一个新的文件
“rb”(只读)为了输入数据,打开一个二进制文件出错
“wb”(只写)为了输出数据,打开一个二进制文件建立一个新的文件
“ab”(追加)向一个二进制文件尾添加数据建立一个新的文件
“r+”(读写)为了读和写,打开一个文本文件出错
“w+”(读写)为了读和写,建议一个新的文件建立一个新的文件
“a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
“rb+”(读写)为了读和写打开一个二进制文件出错
“wb+”(读写)为了读和写,新建一个新的二进制文件建立一个新的文件
“ab+”(读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件

如果指定文件不存在,读操作会报错,其余的不会,会创建新的文件.如果之前存在,则写操作会生成新的文件覆盖之前的文件.

代码样例

#include<stdio.h>
//读文件操作
int main()
{
	int a = 10;
	double b = 100;
	int c = 0;
	double d = 0;
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	/*fprintf(pf,"%d %lf",a,b);*/
	fscanf(pf, "%d %lf",&c,&d);
	fclose(pf);
	pf = NULL;
	return 0;
}

2.文件的顺序读写

image-20220729154631152

声明一点:读文件是我读文件,对我而言就是输入,和我写文件,对我而言就是输出

image-20220729155439739

接下来对文件操作的函数进行解释说明

1.fgetc fputc fgets fputs

代码使用

int fgetc ( FILE * stream );//一次读一个字符
int fputc ( int character, FILE * stream );//一次放一个字符
char * fgets ( char * str, int num, FILE * stream );//一次取若干个字节的字符,n表示数量
int fputs ( const char * str, FILE * stream );//将str放入文件中
//FILE * stream表示文件指针

例子

#include<stdio.h>
#include<errno.h>
#include<string.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		//printf("%s", strerror(errno));
		return 1;
	}
	//写文件
	/*for(int i='a';i<='z';i++)
	fputc(i, pf);*/

	//int ch= fgetc(pf);
	//printf("%c\n",ch);
	// ch = fgetc(pf);
	//printf("%c\n", ch);
	// ch = fgetc(pf);
	//printf("%c\n", ch);
	// ch = fgetc(pf);
	//printf("%c\n", ch);
	// ch = fgetc(pf);
	//printf("%c\n", ch);
	// ch = fgetc(pf);
	//printf("%c\n", ch);
	//int ch;
	//while ((ch=fgetc(pf))!=EOF)
	//{
	//	printf("%c\n", ch);
	//}
	/*fputs("hello bit", pf);*/
	char arr[20];
	fgets(arr, 5, pf);
	printf("%s", arr);
	fclose(pf);
	pf = NULL;
	return 0;
}
2.fscanf fprintf fwrite freadc

代码使用

int fscanf ( FILE * stream, const char * format, ... );//格式化输入,与scanf相比就多了第一个文件指针
int fprintf ( FILE * stream, const char * format, ... );//格式化输出,与printf相比就多了第一个文件指针
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
//ptr目标指针 size类型解引用大小 count数量 stream文件指针

举例

//fscanf fprintf
#include<stdio.h>

int main()
{
	int a = 10;
	double b = 100;
	int c = 0;
	double d = 0;
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	/*fprintf(pf,"%d %lf",a,b);*/
	fscanf(pf, "%d %lf",&c,&d);
	fclose(pf);
	pf = NULL;
	return 0;
}
//fwrite fread
#include<stdio.h>
typedef struct add {
	char name[20];
	int age;
	int score;
}stu;
int main()
{
	/*stu s1 = { "zhangsan",20,100 };*/
	stu s2 = { 0 };
	FILE* pf = fopen("text.txt", "ab");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fwrite(&s2, sizeof(stu), 1, pf);
	/*fread(&s2, sizeof(stu), 1, pf);*/
	fclose(pf);
	pf = NULL;
	return 0;
}

3.补充知识 sscanf sprintf

代码使用

int sprintf ( char * str, const char * format, ... );//合并为字符串
int sscanf ( const char * s, const char * format, ...);//分解字符串
/* sscanf example */
#include <stdio.h>

int main ()
{
  char sentence []="Rudolph 12 years old";
  char str [20];
  int i;

  sscanf (sentence,"%s %d",str,&i);
  printf ("%s -> %d\n",str,i);
  
  return 0;
}

image-20220729162944999

/* sprintf example */
#include <stdio.h>

int main ()
{
  char buffer [50];
  int n, a=5, b=3;
  n=sprintf (buffer, "%d plus %d is %d", a, b, a+b);
  printf ("[%s] is a string %d chars long\n",buffer,n);
  return 0;
}

image-20220729163030834

2.编译环境程序预处理

1.编译环境和阶段

image-20220729170904314

image-20220729170923421

2.预处理详解

1.预定义符号
__FILE__      //进行编译的源文件
__LINE__     //文件当前的行号
__DATE__    //文件被编译的日期
__TIME__    //文件被编译的时间
__STDC__    //如果编译器遵循ANSI C,其值为1,否则未定义
    printf("file:%s line:%d\n", __FILE__, __LINE__);//打印所在源文件,第几行
2.#define定义

#define MAX 1000定义M为100, 定义时最好不加分号

3.#define 定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义 宏(define macro)。

#define SQUARE( x ) x * x

在定义宏时加上(),防止其他错误.

例如

int a = 5; printf("%d\n" ,SQUARE( a + 1) );

打印出来的是11,而不是36 因为是替换 ,则原式实际为 5+1*5+1,所以定义宏时加上括号,防止因运算符优先级导致的误差

  1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先 被替换
  2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
  3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上 述处理过程。
4.#和##

使用 # ,把一个宏参数变成对应的字符串。

首先,在没有#下

#include<stdio.h>
#define PRINT(N) printf("the value "N" is %d",N);
int main()
{
	int a = 10;
	PRINT(a);
	return 0;
}//报错

image-20220729172846659

//#的作用
#include<stdio.h>
#define PRINT(N) printf("the value "#N" is %d",N);
int main()
{
	int a = 10;
	PRINT(a);
	return 0;
}

image-20220729172930412

##可以把位于它两边的符号合成一个符号

#include<stdio.h>
#define NUM(name,NO) name##NO
int main()
{
	int name6 = 1000;
	printf("%d", NUM(name, 6));
	return 0;
}

image-20220729173312627

5.带有副作用的宏参数

举例

define MAX(a, b) ( (a) > (b) ? (a) : (b) )
...
x = 5;
y = 8;
z = MAX(x++, y++);
printf("x=%d y=%d z=%d\n", x, y, z);//按照宏的定义,则会操作不明确

所以尽量不要使用带副作用的参数

宏和函数对比

image-20220729173818273

#undef 取消#define定义

6.条件编译

#ifdef #endif如果什么定义则执行

#if 常量表达式
 //...
#endif
//常量表达式由预处理器求值。
如:
#define __DEBUG__ 1
#if __DEBUG__
 //..
#endif
    #if 常量表达式
 //...
#elif 常量表达式
 //...
#else
 //...
//判断是否定义
    #endif
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol//两个等价
//嵌套指令
#if defined(OS_UNIX)
 	#ifdef OPTION1
 	unix_version_option1();
 	#endif
 	#ifdef OPTION2
 	unix_version_option2();
 	#endif
#elif defined(OS_MSDOS)
 	#ifdef OPTION2
 	msdos_version_option2();
 	#endif
#endif
7.文件包含
//方案一
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif   //__TEST_H__
//方案二
#pragma once
//避免头文件的重复调用

#include "filename"

查找策略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标 准位置查找头文件。 如果找不到就提示编译错误。

#include <filename>

查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。

对于库文件也可以使用 “” 的形式包含,但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。

OPTION2
msdos_version_option2();
#endif
#endif


#### 7.文件包含

```c
//方案一
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif   //__TEST_H__
//方案二
#pragma once
//避免头文件的重复调用

#include "filename"

查找策略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标 准位置查找头文件。 如果找不到就提示编译错误。

#include <filename>

查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。

对于库文件也可以使用 “” 的形式包含,但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sleepymonstergod

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

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

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

打赏作者

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

抵扣说明:

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

余额充值