多文件编程时一个文件里可以包含多个函数,一个函数只能属于一个文件
/*
* 多文件编程演示
* */
#include
#include "01add.h"
int main() {
int num = 0, num1 = 0;
printf("请输入两个数字:");
scanf("%d%d", &num, &num1);
printf("结果是%d
", add(num, num1));
return 0;
}
/*
* 01add.h
*/
#ifndef __01ADD_H__
#define __01ADD_H__
int add(int, int);
#endif //__01ADD_H__
多文件编程基本步骤
1.把所有函数分散在多个不同的源文件里(主函数通常单独放在一个文件里)
2.为每个源文件编写以.h作为扩展名的配对头文件(主函数所在的源文件不需要配对头文件),只要不分配内存的内容都可以写在头文件里,头文件里至少要包含配对源文件里函数的声明语句
3.在每个源文件里使用#include预处理指令包含必要的头文件(配对头文件是必要头文件,如果源文件里使用了某个头文件里声明的函数,则这个头文件也是必要头文件)
在gcc命令里列出所有源文件的路径就可以编译多文件方式编写的程序
可以把多文件程序的编译过程记录在Makefile文件里,然后使用make工具进行编译
/*
*Makefile
*/
a.out : 01add.o 01main.o
gcc 01add.o 01main.o
01add.o : 01add.c
gcc -c 01add.c
01main.o : 01main.c
gcc -c 01main.c
头文件内容应该包含在条件编译的预处理指令中间,这样可以避免头文件内容被重复编译,第一个预处理指令必须是#ifndef
头文件里使用的宏名称应该根据文件名称变化得到,这样可以避免不同头文件使用同样的宏名称
如果想从一个源文件里使用另外一个源文件里声明的全局变量就需要使用extern关键字再次声明这个全局变量
使用extern关键字声明变量的语句通常写在头文件里,因为它不分配内存
不可以跨文件使用静态全局变量
结构体类型的存储区里可以存放多个不同类型的数字,结构体类型需要先创建出来然后才能使用,结构体类型的存储区里包含多个子存储区,每个子存储区可以用来记录一个数字.结构体类型存储区里各个子存储区的类型可以不同,甚至子存储区也可以是结构体类型的存储区.结构体声明语句可以用来创建结构体类型,结构体声明语句里需要使用struct关键字,结构体声明语句里包含多个变量声明语句,这些变量叫做结构体的成员变量,每个成员变量代表一个子存储区.成员变量的声明语句不会分配内存,它们只是用来表示子存储区的类型和名称.C语言里结构体不可以包含函数,结构体声明语句可以写在任何地方,包括头文件里可以把结构体作为类型声明变量,这种变量叫结构体变量,把结构体作为类型使用的时候需要把struct关键字和结构体名称一起作为类型名称使用,结构体变量被分配了内存,可以用来记录数字
typedef关键字可以用来给一个数据类型起别名,别名可以代替原有的类型名称使用,通常会给结构体类型起别名
/*
* 结构体演示
* */
#include
/*struct person {
int age;
float height;
char name[10];
};
typedef struct person sperson;*/
typedef struct /*person*/ {
int age;
float height;
char name[10];
} sperson;
int main() {
//struct person prsn; //结构体变量
sperson prsn1 = {20, 1.78f, "abc"}, prsn2 = {0};
sperson *p_person = NULL; //结构体指针
printf("请输入年龄:");
scanf("%d", &(prsn1.age));
printf("请输入身高:");
scanf("%g", &(prsn1.height));
scanf("%*[^
]");
scanf("%*c");
printf("请输入姓名:");
fgets(prsn1.name, 10, stdin);
printf("年龄是%d
", prsn1.age);
printf("身高是%g
", prsn1.height);
printf("姓名是%s
", prsn1.name);
prsn2 = prsn1;
printf("年龄是%d
", prsn2.age);
printf("身高是%g
", prsn2.height);
printf("姓名是%s
", prsn2.name);
p_person = &prsn1;
printf("年龄是%d
", p_person->age);
printf("身高是%g
", p_person->height);
printf("姓名是%s
", p_person->name);
return 0;
}
可以把声明结构体的语句和起别名的语句合并成一条语句,这个时候可以省略结构体本身的名称
结构体变量应该进行初始化,可以象初始化数组一样初始化结构体变量,这个初始化过程也遵守数组初始化的各种规则
结构体变量通常不会作为整体使用,一般一次只使用其中的某个子存储区,以下写法可以表示结构体变量的某个子存储区
prsn.age
其中prsn是一个结构体变量的名称,age是一个子存储区的名称
同类型的结构体变量之间可以直接赋值
结构体指针可以记录结构体存储区的地址,以下写法可以通过结构体指针表示结构体的子存储区
p_person->age
其中p_person是一个结构体指针的名称,age是一个成员变量的名称
/*
* 结构体练习
* */
#include
typedef struct {
int row;
int col;
} pt;
typedef struct {
pt pt1;
pt pt2;
} rect;
int main() {
pt mid = {0};
rect r = {0}, *p_r = &r;
/*printf("请输入水平长方形的位置:");
scanf("%d%d%d%d", &(r.pt1.row), &(r.pt1.col), &(r.pt2.row), &(r.pt2.col));
mid.row = (r.pt1.row + r.pt2.row) / 2;
mid.col = (r.pt1.col + r.pt2.col) / 2;
printf("中心点的位置是(%d, %d)
", mid.row, mid.col);*/
printf("请输入水平长方形的位置:");
scanf("%d%d%d%d", &(p_r->pt1.row), &(p_r->pt1.col), &(p_r->pt2.row), &(p_r->pt2.col));
mid.row = (p_r->pt1.row + p_r->pt2.row) / 2;
mid.col = (p_r->pt1.col + p_r->pt2.col) / 2;
printf("中心点的位置是(%d, %d)
", mid.row, mid.col);
return 0;
}
可以使用结构体类型的形式参数从调用函数向被调用函数传递结构体数据,直接使用结构体类型的形式参数会造成时间和内存的浪费,采用结构体指针做形式参数可以避免时间和内存的浪费,声明结构体指针形式参数的时候尽量使用const关键字
可以把整个结构体存储区的内容作为返回值使用,这个时候函数就需要提供一个结构体类型的存储区用来存放返回值,这样也会造成时间和内存的浪费,使用结构体存储区的地址做返回值可以避免这种浪费,这个时候就需要被调用函数提供一个结构体指针类型的存储区用来存放返回值,不可以把非静态局部结构体存储区的地址作为返回值使用