十.结构类型
枚举
enum 枚举类型名字 {名字0,1,2,3...};
- 枚举类型名字并不经常使用,要的是大括号里面的文字,大括号里面的就是常量符号,类型是int (无符号整形),值依次从0到n。并且枚举的值不可修改。
- 声明枚举量的时候可以指定值
- 枚举类型虽然可以当做类型使用,但是实际上很少用。不过比宏好用
#define red 1 #define yellow 2 #define blue 3 就相当于 enum color {red = 1,yellow,blue} ;
枚举是一种类型,通过它可以定义枚举变量:
enum week a, b, c;
也可以:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a, b, c;
结构类型
结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。在实际问题中有时候我们需要几种数据类型一起来修饰某个变量。这些数据类型都不同但是他们又是表示一个整体,要存在联系,那么我们就需要一个新的数据类型——结构体,它就将不同类型的数据存放在一起,作为一个整体进行处理。
声明结构类型
结构类型表示结构长什么样,结构变量都按照声明的样子。
形式1:
struct date{ int day; int month; int year; }; struct date today;
形式2:(一次性的)
struct { int day; int month; int year; }d1,d2;
形式3:
struct point{ int day; int month; int year; }d1,d2;
结构变量是本地变量,同样这也是具有作用域
- 这种声明如果放在任何函数的外面,,该声明的后面的所有函数都可以使用
- 如果这种声明在某个函数的内部,则它的标记只能在内部使用,并且在其声明之后
结构的初始化
给结构成员赋值,没赋值的都为0
struct date today ={1,2,3}; struct date today ={.day = 1,.month = 2}
结构运算
- 用结构变量名字访问结构,用.来访问结构成员
- 可以赋值取地址,传递参数,强制类型转换
- 和数组不同,结构变量的名字不是地址
结构与函数
整个结构可以作为函数参数,这个时候是在函数内新建了一个结构变量,并赋值调用者的结构的值。也可以返回结构。
* 输入结构
没有直接的办法可以一次scanf一个结构
如果利用函数读入结构,如下,但是并不会改变主函数的值
方法一:在函数中创建一个结构,函数返回结构,再把这个结构赋值给外面的结构
方法二:
结构数组
struct date testdate [10];
嵌套的结构
类型定义 typedef
声明新的类型的名字,即最后一个名字就是typedef和最后一个名字中间的东西的新名字。
typedef int Length; typedef struct { int day; int year; }Day; Length i = 1; Day d1 = {1,2000};
联合
union AnElt{ int i; char c; }elt1,elt2;
这些成员占据同一空间,sizeof(union)= sizeof(每个成员)的最大值
十一.全局变量,宏,头文件
全局变量
全局变量
- 在函数里面定义的变量称为局部变量,在函数外面定义的变量称为外部变量,也称为全局变量
- 没有初始化的全局变量会得到0;指针会得到NULL值。初始化在main函数前,只能用编译时已知的值初始化。不建议用一个全局变量初始另外一个全局变量。
- 若在函数的内部存在与全局变量同名的局部变量,则会覆盖全局变量。但是离开函数后,全局变量的值还是最开始定义的值。
静态本地变量
- 可以在离开函数后保留最后的值。
- 实际上是特殊的全局变量,位于相同的内存区域。
- 静态本地变量具有全局的生存期,函数内部的作用域。static意思就是局部作用域。
返回指针的函数
- 返回本地变量的地址是危险的。因为当本地变量使用完后,不能保证这个地址上的内容还是之前的本地变量。
- 返回全局变量或静态本地变量是安全的;
- 返回在函数内malloc的内存是安全的,容易造成问题;
- 最好是返回传入的指针
宏定义
#开头的是编译预处理指令
#define <名字> <值>用来定义一个宏
- 结尾没有分号,也不是c的语句。
- 名字是一个单词,值可以是任何东西。
- 在c语言的编译器开始编译之前,编译预处理程序(cpp)会把程序中的名字换成值。
注意:
- 如果一个宏的值中有其他的宏的名字,也是会被替换的
- 如果一个宏的值超过一行,最后一行之前的行末需要加\
- 宏的值后面出现的注释不会被当作宏的值的一部分
没有宏的值
#define <名字> 用于条件编译
预定义的宏
带参数的宏
#define cube(x) ((x)*(x)*(x)) 宏可以带参数
注意括号的问题(每一个参数和整个值都加括号)
多个源代码文件
新建一个项目,然后把几个源代码文件加进去。
编译单元 一个.c文件是一个编译单元。编译器每次编译只处理一个编译单元。
头文件
“” 还是<>?
“”要求编译器首先在当前目录(.c文件所在的目录)去找,没有就到编译器指定的地方去找;
<>让编译器只在指定的目录去找。
#include误区
#include 不是用来引入库的,而是把后面的东西原封不动地引入。
stdio.h里只有printf的原型。
现在的c语言编译器默认会引入所有的标准库。