C其它数据类型
一、全局变量和局部变量
根据变量的作用域可分为全局变量和局部变量
1.局部变量
1>定义:在函数内部定义的变量
2>作用域:从定义变量的那一行开始,一直到代码块结束
3>生命周期:从定义变量的那一行开始分配存储空间,代码块结束后,就会被回收
4>没有固定的初始值
2.全局变量
1>定义:在函数外面定义的变量
2>作用域:从定义变量的那一行开始,一直到文件结尾(能被后面的所有函数共享)
3>生命周期:程序一启动就会分配存储空间,程序退出时才会被回收。
4>默认的初始值是0
举个例子,加深理解
代码如下
输出如下
二.结构体
结构体是一种数据类型,属于构造类型。构造类型是由多个基本数据类型组成。因此,前面我们说的数组也是一种构造类型,但它只能存储一种数据类型,如果要存储一个人的信息,数组是满足不了我们的要求的,一个人的信息包括姓名(char)、年龄(int)、身高(double)等等。这个时候我们可以用结构体来解决我们的问题。
1.简介
结构体:由多个不同类型的数据构成。
格式
struct 类型名
{
变量
}
根据这个结构体类型,我们可以定义结构体变量。
所以如果我们想存储一个人的信息,可以定义一个结构体如
struct Person
{
int age;
double height;
char *name;
}
struct Person p={20,1.75,”Jack’},也可以这样定义
P.age=30;
P.name=“Rose”;
把这个写个程序验证一下代码如下
输出如下
注意:struct Person p={20,1.75,”Jack’},这种写法只能在定义变量的时候一次性赋值,在其它情况下是不能一次性赋值的
struct Person p;
P={20,1.75,”Jack’};
这种写法是错误的。
2.内存分析
定义结构体类型时不会分配存储空间,定义结构体变量才会分配存储空间。举个例子并画图加深一下理解
struct Data
{
int year;
int month;
int day;
};
当写完这句代码时,并不会分配存储空间,如下所示:
struct Data d1={2015,3,20} ;
当写完这句代码才会分配存储空间,所占字节为(4+4+4)12个,并且存储是依次存储,即month地址比year大4个字节,day比month大4个字节。内存情况如下图所示:
地址打印出来看一下,代码如下
输出如下
还有一点,结构体在存储变量时会有一个补齐算法,即结构体所占用的存储空间必须是最大成员字节数的倍数。如
struct Student
{
int age;
char *name;
};
struct Student stu;
stu.age=10;
stu.name="Jack";
此时stu所占字节数为16。
3.定义结构体的方式
主要有三种
第一种 先定义类型,再定义变量
struct Student
{
int age;
char *name;
};
struct Student stu;
第二种 定义类型的同时定义变量
struct Student
{
int age;
char *name;
} stu;
第三种 定义类型的同时定义变量(省略了类型名称)
struct
{
int age;
char *name;
} stu;
4.结构体数组
当需要记录很多不同类型的信息时,比如一个班的姓名、学号、身高,我们可以考虑使用结构体数组来解决问题,它的定义与数组有相似之处,可以参照数组来理解。举个例子
记录三个学生(不写太多,都一样的)的姓名、学号、身高,并遍历他们的信息
代码如下
输出如下
5.指向结构体的指针
利用指针我们可以间接操纵结构体,对结构体进行取值和赋值,举个例子加深理解
代码如下
输出如下
当然,也可以将(*p).no改为p->no,它们是等价的。也就是说访问结构体变量有三种方式
第一种方式
Stu.name;
第二种方式
(*p).name;
第三种方式
P->age;
6.结构体嵌套
看名字就知道大概意思了,就是在结构体中有结构体的存在,如果一个学生的信息记录包括生日和入学日期,我们可以单独定义一个日期的结构体,这样在学生信息结构体中就可以利用这样日期结构体,可以节省时间,提高编译效率。如下所示
struct Data
{
int year;
int month;
int day;
};
struct Student
{
char *name;
int no;
double height;
struct Data birthday; // 生日
struct Data ruxueData; // 入学日期
};
三、枚举
枚举用来取几个固定变量的场合,它的使用与结构体相似,可以参照结构体来理解。
第一步 定义枚举类型
enum Sex
{
Man,
Woman,
Unkown
};
第二步 定义枚举变量
enum Sex s = Man;
枚举里面的值其实是整型变量,第一个值默认是0,依次递增。这个可以打印出来看看,代码如下
输出如下
四、预处理指令
定义:编译器把代码翻译成“0”和“1”之前执行的指令
预处理指令主要包括三种:宏定义、条件编译、文件包含
所有的预处理指令都是以“#”开头
这里只说下宏定义
宏定义
分为带参数的宏定义和不带参数的宏定义
1.不带参数的宏定义
#define COUNT 7;
这句代码的作用是,在代码被编译成0和1之前,会把代码中所有的COUNT替换成7
注意:在双引号之间的是不会被替换的,如
char *name=”COUNT”;
在上面的代码中,预处理指令不会将COUNT替换成7。
预处理指令的作用域:从编写指令的那一行开始,一直到文件结束。
如果想取消这个宏定义 如下
#undef COUNT
这句代码过后,COUNT的宏定义就会被取消。
还有一点,宏名一般用大写
2.带参数的宏定义
#define sum(v1+v2) v1+v2
这句代码的作用是在代码被编译成0和1之前,会将sum(v1+v2)替换成v1+v2。但这种写法很不规范,如果出现优先级的问题时,结果可能会出错。举个例子,代码如下
输出如下
按照我们的想法,结果应该是100,可是输出是35,这是因为宏定义只是完成了一个替换的工作,它相当于替换成了5+5*5+5,因为优先级的缘故,会先运算乘积,在运算加,所以是35。
为了避免上面的情况,我们一般会在参数外面加上括号,代码如下所示
输出如下
这样就避免了上述错误。
五、Typedef
格式 :typedef 类型 新的名称
我们可以使用typedef关键字为各种数据类型定义一个新名字(别名)。如typedef int myint 这句代码的作用是给int给了个别名,这句代码之后我们可以用myint来定义整型变量这个关键字对于结构体、枚举等比较复杂的定义很有利,很使我们的代码精简很多,增强可读性。如
typedef struct {int shengao;
int tizhong;
}Person;
这里面的Person就是结构体的名称,函数里可以写成Person p = {178,65};很多东西都是一样的,万变不离其中,就不多写了。