目录
前言:什么是自定义数据类型 ?
所谓自定义数据类型,就是用一个新名字重新对一个数据类型命名,后面新名字就有了该数据类型的功能,在调用该新名字时,就相当于调用该数据类型。
自定义数据类型包含不同的使用方法,每一个方法都有自己的关键字。
一,自定义数据类型之:数据类型命名
现在C语言中常见的数据类型有:
整型:int, short, long, long long
浮点型:float, double
字符型:char
但是如何定义一个字节类型呢?
byte(字节类型)1字=1字节=8位=8比特。计算机二进制中一个0或者1就代表1位。
类型数据命名关键字:typedef(意思为type define)
语法:typedef Type NewTypeName ;
已有类型 新名字
使用该关键字可以对C语言中数据类型进行新命名。
值得注意的是:typedef并没有创建新类型,只是创建了类型别名。
typedef unsigned char byte;
这个语句就是把unsigned char重新命一个名字type,两者类型和功能一模一样。
typedef经常用于简化类型名。
1,深入应用typedef:
typedef对数组类型和函数类型的应用;
每一个函数/数组类型都有自己对应的指针类型,
例如int(int);对应int(*p)(int);
float[4];对应float(*q)[4];
现在可以使用typedef关键字统一函数/数组指针类型为type* h; 格式。
typedef float(Farr4)[4];
/* Farr4代表float[4]类型的数组 */
typedef int(IFunc)(int,int);
/* IFunc代表int(int,int)类型的函数 */
float gar[4] = {1, 2, 3, 4};
int add(int a, int b)
{
return a + b;
}
Farr* pa = &gar;
IFunc* pb = add;
以上代码,Farr* q 指针可以指向所有float[4]类型的数组;
IFunc* p指针可以指向所有int(int, int)类型的函数;
另一个注意的点:在函数内部起新名字无影响。
二,自定义数据类型之:结构体类型命名
结构体关键字:struct
作用:创建不同数据类型的一个集合。它的本质是变量的集合。
语法:
struct TypeName
{
Type1 var1;
Type2 var2;
....
TypeN varN;
};
定义好一个Struct结构体之后,就可以使用了:
#include <stdio.h>
struct student
{
char name[20];
int id;
short major;
};
int main()
{
struct student s1 = {"qingshan", 7, 98};
struct student* ps = &s1;
printf("s1.name = %s\n",s1.name);
printf("s1.major = %d\n",ps->major);
return 0;
}
1,两个操作符:
. 操作符用于取值:s1.name(取值为qingshan)
->操作符用于指针的取值:ps->major(取值为98)
1,深入理解struct结构体:
1,struct结构体变量中的成员占用独立的内存。
当前的地址要为每个变量所占字节的整数倍,如果不是,变量起始地址就会往后移,找到一个是整数倍的地址,然后该地址就会作为变量的其实地址。
2,位域。
在现代的程序设计中,我们是用字节作为最小的单位使用内存。
但特殊场合,可以使用struct结构体将比特位作为最小的单位使用内存。
因为结构体类型能够指定成员变量占用内存的比特位宽度(位域)。
位域示例:
struct BW
{
unsigned char a : 4; //a占用一个字节的4位宽度。
unsigned char b : 3; //a占用一个字节的3位宽度。
unsigned char c : 1; //a占用一个字节的1位宽度。
};
示例中sizeof(struct BW) = 1;
-
使用位域时,位域成员必须为整型,默认情况下成员依次排列。
-
位域成员占用位域数不能超过类型宽度(错误示例 char d : 9;)
-
存储位不足时自动启用新存储单元。
-
可以舍弃当前未使用的位,重新启动存储单元。
struct BW
{
unsigned char a : 4;
unsigned char : 0; //申请语句,表示重新开始启用新字节。
unsigned char c : 4;
};
3,struct结构体可以用typedef赋予新名字。
#include<stdio.h>
typedef struct student Stu; //student新名字为Stu.
struct student
{
char name[20];
int id;
short major;
};
int main()
{
Stu s = {{0}}; //赋值。
return 0;
}
第11行:后面没有被赋值的初始值,默认初始值为0;
4,struct结构体可以省略类型名,称之为无名结构体类型。
但省略类型名后,每次创建变量都必须给出完整的结构体定义。
无名结构体类型总是互不相同的类型。
int main()
{
struct {int a, int b;} v1; //无名结构体类型。
struct {int a, int b;} v2;
struct {int a, int b;}* pv;
v1.a = 1;
v1.b = 2;
v2 = v1; //error.
pv = &v1; //error.
return 0;
}
在这里,v1和v2是不同类型。
三,自定义数据类型之:联合体类型命名
联合体关键字:union
作用:创建不同数据类型的一个集合。它的本质是变量的集合。
用法:union是struct的兄弟,用法十分相似。
语法:
union TypeName
{
Type1 var1;
Type2 var2;
....
TypeN varN;
};
1,union与struct的区别:
-
union类型所有成员共享同一段内存(所有成员的起始地址相同)
-
union类型的大小取决于它所包含的成员最大的那一个。
-
union类型的变量只能对第一个成员变量初始化,后面变量的值就等于第一个变量的值。
2,union类型应用:
可以用来判断系统大小端。
-
小端系统:低位数据存储在低地址内存中。
-
大端系统:低位数据存储在高地址内存中。
四,自定义数据类型之:枚举类型命名
枚举类型关键字:enum
作用:创建不同数据类型的一个集合。它的本质是变量的集合。
用法:能够定义整型常量的集合类型。
语法:
enum TypeName
{
IntConst1, (逗号可以不写)
IntConst2, (IntConst为整型常量)
....
IntConstN
};
注意事项:
-
第一个枚举常量默认值为0;
-
后续常量的值在前一个常量值的基础上加1;
-
可以任意对枚举常量指定整型值(只能指定整型值)
enum Day{MON = 1,TUE, WED, THU, FRI, SAT, SUN};
enum Season{Spring, Summer = 2, Autumn, Winter = -1};
输出值:MON = 1,TUE = 2, WED = 3, THU = 4, FRI = 5, SAT = 6, SUN = 7
Spring = 0, Summer = 2, Autumn = 3, Winter = -1