预处理和文件操作
预处理是在编译前所做的工作,编译器自动调用预处理程序对源码中以’#’开头的预处理部分进行处理,处理完毕 后,进入源码的编译阶段
预处理有:宏定义、条件编译、文件包含。
一、宏定义
宏定义,又称为宏替换,自定义一个宏(要符合标识符的命名规则),用于替换任意数据、标识符或者表达式。
1,无参宏定义
定义无参宏的基本格式:#define 宏名 宏替换 比如:
#define A 35 //宏A就代表整型数据35.
#define TEST "abddgdsfdlfj" //宏TEST就代表字符串"abddgdsfdlfj"
#define TEST abddgdsfdlfj //宏TEST就代表abddgdsfdlfj
#define I int //宏I就代表int(相当于给数据类型取别名)
注意:①宏名不可以被赋值②定义宏,通常会给宏替换打括号,避免出现优先级的问题
2,有参宏定义
定义带参宏的基本格式: #define 宏名(参数表) 宏替换 带参宏可以像函数一样调用
3,特点
一改全改
4、常量的定义
除了宏定义以外,还可以通过const关键字定义常量: 普通常量: < const> = ; 如:
const int a = 30; //定义一个常量a,其值等于30
注意:定义成常量后,值不可被改变 。
二、条件编译
条件编译也就是根据不同的条件编译不同代码段。
作用:适当减轻编译器的负担 (提高编译的效率)
1、#if……#else的使用
#if 表达式 //判断表达式的逻辑值(真或假),若逻辑值为真,则编译代码段1,否则编译代码段2.
代码段1;
#else
代码段2;
#endif
#define FLAG 1
#include<stdio.h>
#include<string.h>
//#include<stdlib.h>
//#include<time.h>
int main() {
char str[1024] ="\0";
int i = 0;
gets_s(str);
while (str[i] != '\0') {
#if FLAG
if(str[i]>='a'&&str[i]<='z')//小写转大写
{
str[i] = str[i] - ('a' - 'A');
}
#else
if(str[i]>='A'&&str[i]<='Z')//大写转小写
{
str[i] = str[i] + ('a' - 'A');
}
#endif
i++;//这条语句是while循环里的遍历:应该养成良好的敲代码习惯,在写while时就早早得将这条遍历语句添上,防止遗忘
}
puts(str);
}
2、#ifdef……#endif的使用
第一种应用场景
#ifdef 宏名
//如果定义了宏"宏名",则编译代码段.
代码段;
#endif
第二种应用场景
#if 表达式
//判断表达式的逻辑值(真或假),若逻辑值为真,则编译代码段1,否则编译代码段2.
代码段1;
#else
代码段2;
#endif
3、#ifndef……#endif的使用
#ifdef 宏名
//如果定义了宏"宏名",则编译代码段.
代码段;
#endif
#ifndef 宏名
//如果没有定义宏"宏名",则编译代码段1,否则编译代码段2;
代码段1;
#else 代码段2;
#endif
因此宏名只会被定义一次
三、文件包含
1、包含库函数头文件
我们想要用库函数就需要包含头文件,也就是文件包含,当然也可以编写自定义头文件,包含自己编写的头文件。 如:
#include <stdio.h>
//包含系统头文件用<>,只会在系统头文件中找
#include "name.h"
//包含自定义头文件用””,先在自定义头文件中找,找不到就会在系统头文件中找
文件包含允许嵌套,即在一个被包含文件中可以包含其它文件。
2、头文件的重复包含
头文件的嵌套包含可能会引起头文件的重复包含,从而出现函数和变量的重定义问题 所以需要避免头文件重复包 含,某些宏定义语句可以防止头文件重复包含,如:
#pragma once //防止头文件重复包含,不让文件的内容被包含两次,在头文件最前面添加
(#pragma once是vs独有的,有使用平台的限制,其他平台可能不存在)
3、C程序的分文件编写
多文件编程就是把多个头文件(.h文件)和源文件(.c文件)组合在一起构成一个程序,这是C语言的重点,也是C 语言的难点。 C语言头文件的编写是其中的重点内容,有很多细节需要注意,文件编程既涉及到了内存,也涉及到 了编译原理,有的甚至会让你感觉奇怪。 学会了多文件编程,你就可以使用C语言来开发中大型项目了,对初学者 来说,这简直是跨域了一大步。 在开发中大型项目中,一般用头文件封装函数的声明,在源文件里完成函数功能 的定义。
四、文件操作
1.文件的概念
什么是文件?
文件有不同的类型,在程序设计中,主要用到两种文件:
(1)程序文件。包括源程序文件(后缀名为.c)、目标 文件(后缀名为.obj)、可执行文件(后缀名为.exe)等。这一类型的文件主要用于存储程序代码。
(2)数据文件。此文件的内容不是程序,而是程序运行时读写的数据,比如程序运行过程中输出到磁盘或其他设备上的数据, 或在程序运行过程中供程序读取的数据。
这里C语言的文件操作主要是对数据文件的操作。
在之前程序中所处理 的数据的输入和输出都是以终端为对象的,都是从键盘输入数据,然后运行结果输出到终端显示器上。
实际上,我 们有时候需要将一些数据(程序运行的最终结果或者中间数据)保存起来,方便以后需要时再调用,而这就需要用 到磁盘文件了。
(1)文件名 每一个文件都需要一个唯一的文件标识,以便用户使用,就像我们的变量名一样,同一程序中不能有相同的变量 名。 文件标识也称为文件名,它由3部分组成:
①文件路径:表示文件在外存设备中的存储位置; ②文件名主 干:表示文件的名字,可由用户自定义,命名规则应遵循标识符的命名规则。 ③文件后缀:表示文件的性质,也 称为文件的格式,用于描述文件的类型(如txt、ppt等)。
文件路径能唯一标识文件在外存中的位置。 如:D:\C++\VSproject\TEXT\text.c
(2)文件的分类 根据数据的组织形式,数据文件可分为ASCII文件和二进制文件。
数据在内存中是以二进制形式存储的,如果不加 转换的输出到外存,就是二进制文件,可以认为它是存储在内存的数据的映像,所以称之为映像文件。如果要求在 外存上以ASCII码形式存储,就需要在存储前进行转换。
ASCII文件又称为文本文件,每一个字节存放一个字符的 ACSII码。
(3)文件存储方法的区别 一个数据在磁盘上存储,字符一律以ASCII形式存储,数值型既可以用ASCII形式存储也可以用二进制形式存储。
如 整数10000,用ASCII码形式存储在磁盘上占5个字节(每个字符占一个字节),而用二进制形式存储在磁盘上只占4 个字节(00000000 00000000 00100111 00010000)。
用ASCII形式存储时字符与字节一一对应,一个字节代表一个 字符,便于逐个处理,但占的存储空间较多,而且处理的时候要花费转换时间(二进制与ASCII码之间的转换)。二 进制形式存储就相当于直接把内存中的内容原封不动存储在磁盘上,由于不需要转换,所以二进制文件更加方便计 算机处理。
2、文件的基本操作
(1)文件指针的定义
由于文件类型已经在stdio.h头文件中有声明了,所以我们不需要另外声明,直接使用就行了。 文件类型变量的定 义格式为:FILE 文件变量名;
(2)文件的打开
①使用fopen函数打开文件
C语言规定用文件标准输入输出函数fopen来实现打开文件。 fopen函数的调用方式为: fopen(文件名,使用文件的 方式); 例如:fopen(“text1.txt”,”r”); 意思是以只读的方式打开名为“text1.txt”文件。 此时fopen函数返回的 是“text1.txt”文件的起始地址,我们通常将fopen函数的返回值赋值给一个文件指针,用文件指针指向此文件的地 址。例如:
FILE *fp;//定义一个文件指针fp
fp=fopen(“text1.txt”,”r”);
//使fp指向文件“text1.txt”的首地址 这样fp就 与文件“text1.txt”有联系了。
②文件的打开方式
文件打开方式及含义如下表所示
(3)文件操作函数


修改后:(①fopen函数里的第一个参数是图片文件的属性 ②要细心,不要弄错文件操作的顺序)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
FILE* fp1;//创建文件指针
fp1 = fopen("D.data", "w+");//打开文件
char a = 'a';
putc(a, fp1);
fclose(fp1);//关闭文件
FILE* fp2;
fp2 = fopen("小怪兽.png", "rb");
fseek(fp2, 0, 2);
int size = ftell(fp2);
printf("图片大小:%d\n", size);
fclose(fp2);
return 0;
/*真难受,已经连续两天卡在这里了*/
}
运行如下


(4)文件的关闭
在使用完一个文件之后,为了防止它被误用,应该关闭它。“关闭”就是撤销文件信息区和文件缓冲区,使指针不再 指向此文件了,也无法操作此文件了,除非重新打开此文件,使指针指向此文件。 关闭文件用fclose函数。 fclose 函数的一般形式为: fclose(文件指针);
在每次程序终止之前都要养成习惯关闭所有的文件。 当fclose函数成功关闭文件时,返回0;否则返回EOF(-1)。