C语言复习004_预处理、结构体、文件操作
一、预处理(#)
//常见的两类预处理
#include <stdio.h>
#define PI 3.1415926535897
//注意:预处理最后边不加分号“;”
在源程序中这些命令都放在函数之外,而且一般都放在源文件的前面,它们称为预处理部分。
(一)宏定义#define
宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对他不做任何检查,如有错误,只能在编译已被宏展开后的源程序时发现。
宏定义写在函数之外,作用域为从宏定义命令到原程序结束,如果要终止则使用**#undef**命令
#define PI 3.1415926
...
#undef PI
(二)类型定义typedef
在编译时处理的,对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。
小例题:不用嵌套和循环,打印出0~999数字
#include <stdio.h>
#define A(x) x;x;x;x;x;x;x;x;x;x;
void main()
{
int n = 0;
A(A(A(printf("%d", nn++))));
}
(三)带参数的宏定义
一般命名形式:
#define 宏名(形参表) 字符串
一般调用形式:
宏名(实参表);
宏定义中的形参时标识符,二宏调用中的实参可以是表达式
在宏定义中,字符串内的形参通常要用括号括起来避免出错
#include <stdio.h>
#define SQ(y) ((y) * (y)) //注意这地方的define定义的括号添加
void main()
{
int a, sq;
printf("Input a number:");
scanf("%d", &a);
sq = 160 / SQ(a+1);
printf("sq = %d\n", sq);
}
(四)文件包含
#include <stdio.h>
#include "stdio.h"
两种形式的不同之处:
1、使用尖括号表示在包含文件目录中取查询(包括文件目录是由用户在这设置环境设置的),而不再源文件目录去查找;
2、使用双引号则表示首先在当前的源文件目录中查找,若未找到才到半酣目录中取查找。用户编程时可以按照自己文件所在目录来选择某一种命令行形式。
(五)条件编译
第一种形式
如果标识符被#define命令定义过则编译程序段1,否则编译程序段2
#ifdef 标识符
程序段1
#else
程序段2
#endif
如果没有程序段2(他为空),本格式中的#else可以没有,可以写为:
#ifdef 标识符
chengxuduan 1
#endif
第二种形式
#ifndef 标识符
程序段1
#else
程序段2
#endif
第三种形式
#if 常量表达式
程序段1
#else
程序段2
#endif
二、结构体
(一)定义
定义一个结构体的一般形式
struct 结构体名称
{
//成员列表
类型说明符 成员名;
类型说明符 成员名;
。。。
};
例子:
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
定义结构以i变量的一般形式:
1、
struct 结构体名 变量名;
2、
struct 结构体名称
{
//成员列表
类型说明符 成员名;
类型说明符 成员名;
。。。
} 变量名1, 变量名2, …;
(二)引用
引用结构体变量中成员的方式:j结构体变量名.成员名
"."是成员(分量)运算符,它在所有的元素安抚中优先级最高,因此可以把student1.num作为一个整体来看待。
(三)指向结构体类型数据的指针
1、定义的一般形式:
struct 结构名 *结构指针变量名;
赋值是把结构变量的首地址赋予该指针变量,不是把结构名赋予该指针变量。例如:
struct stu
{
char name;
int age;
char sax;;
};
struct stu *pstu;
struct stu boy;
pstu = &boy; //这条语句是正确的
pstu = &stu; //这条语句是错误的
2、访问的一般形式:
(*结构体指针变量).成员名 //括号是必须带着的
或者为:
结构体指针变量->成员名
例如:
(*pstu).num;
或者
pstu->num;
(四)动态存储分配
C语言提供了一些内存管理函数,这些内存管理函数可以按照需要动态地非标配内存空间,也可以把不再使用的空间回收待用,为有效地使用内存资源提供了手段。
常用的内存管理函数:
分配内存空间函数:malloc,calloc
始放内存空间函数:free
(1)malloc
函数原型为void *malloc(unsigned int size);
其作用是在内存的动态存储区中分配一个长度为size的连续空间(size是一个无符号数)
此函数的返回值是一个指向分配域起始地址的指针
如果此函数未能成功执行(内存不足),则返回空指针NULL
(2)calloc
函数原型为void *calloc(unsigned n, unsigned size);
其作用是在内存的动态存储区中分配n个长度为size的连续空间。
函数返回一个指向分配域起始地址的指针。
如果分配不成功,则返回NULL
用calloc函数可以为一维数组开辟动态存储空间,n为数组元素的个数,每个元素长度为size。
(3)free
函数原型为void free(void *p);
其作用是始放由p指向的内存区,使这部分内存区能被其他变量使用。
p是最近依次调用calloc或malloc函数时返回的值
free函数没有返回值。
(五)链表
#include <stdio.h>
struct student
{
long num;
float score;
struct student *next;
}
void main()
{
struct student a, b, c, *head;
a.num = 10101;
a.score = 89.5;
b.num = 10102;
b.score = 90;
c.num = 10103;
c.score = 85;
head = &a;
a.next = &b;
b.next = &c;
c.next = NULL;
do
{
printf("%ld, %s.1f\n", head->num, head->score);
head = head->next;
}while(head != NULL);
}
(六)typedef的使用
用typedef生命新的类型名来代替已有的类型名。
比如生命INTEGER为整型:typedef int INTEGER;
用typedef来定义一个新的结构体类型能够大大简化代码的书写,在windows的头文件中使用了大量的结构体类型的重新定义。
#include <stdio.h>
typedef struct
{
int month;
int day;
int year;
} DATE;
void main()
{
DATE date_one;
date_one.year = 2021;
date_one.month = 03;
date_one.day = 12;
printf("%d-%d-%d \n", date_one.year, date_one.month, date_one.day);
}
三、文件操作
(一)文件的打开与关闭
文件型指针变量:
FLIE *fp;
fp是一个指向FLIE类型结构体的指针变量。
1、文件的打开函数(fopen)
函数调用:
FLIE *fp;
fp = fopen(文件名, 使用文件的方式)
注意:
(1)需要打开的文件名,也就额是准备访问的文件的名字(文件路径)
(2)使用文件的方式(“读”还是“写”等)
(3)让每一个指针变量指向被打开的文件
2、文件的关闭函数(fclose)
函数调用:
fclose(文件指针);
函数功能:
是文件指针变量指向该文件,也就是文件指针变量与文件“脱钩”,此后不能再通过该指针对原来与其联系的文件进行读写操作。
返回值:关闭成功返回值为0,否则返回值EOF(-1)
3、文件的读写
C语言中提供了很多的文件读写函数:
字符读写函数:fgetc和fputc
字符串读写函数:fgets和fputs
数据块读写函数:freed和fwrite
格式化读写函数:fscanf和fprintf
以上函数都要包含stdio.h头文件