本章的主要内容包括:
C语言的类型定义
结构
联合
位运算和位段第八章 结构及其它回首页写程序时自己定义的数据类型称作,用户定义类型,。
形式,typedef 类型名 标识符;
typedef的作用仅仅是用新类型名来代表已存在的类型名,并未产生新的数据类型 。 原有的类型名依然有效 。
新的类型名可以和 C语言中原有的各种基本类名一样,方便地用于定义变量,定义函数的返回值,定义其它构造类型的元素或成员 。
例 8.1,typedef int INTEGER;
给 int类型一个新的名字 INTEGER,此后,可以用 INTEGER来定义整型变量 。 如,INTEGER i,j,a[10];
例 8.2,typedef char * CHARP;
新类型名 CHARP是字符指针类型,表示的旧类型是 char *。
CHARP p; 等价于,char *p;
例 8.3,typedef double VECT[4];
定义一种具有 4个元素的双精度数组类型 VECT;程序中 VECT
v1,v2;定义两个 4个元素的双精度数组 。
8.1 类型定义定义新类型的步骤:
(1) 首先按通常定义变量的方法写出定义的主体;如:
double *f;
(2) 将变量名换成新类型名;
double *PDOUBLE;
(3) 在最前面加上关键字 typedef;
typedef double *PDOUBLE;
(4) 可以用新类型定义变量了;
PDOUBLE f1,f2;
讨论自定义数据类型的作用
8.1 类型定义结构可以将若干个不同类型的数据组合成一个复合数据对象 。 组成结构的数据项称结构的成分或成员 。
结构类型成员的数量必须固定,但该结构中各个成员的类型可以不同 。
8.2.1 结构类型说明,结构变量定义
8.2.1.1 结构类型说明
struct 结构名 {成员说明序列 };
结构名是结构类型说明的标志,如果所定义的结构类型,在程序中很少使用,可以省略结构名,在说明类型的同时定义结构变量;如果所定义的结构类型,在程序中要多次使用,应该使用结构名说明结构类型,以后在程序需要该结构类型的地方,用
,struct 结构名,的形式代表整个说明 。 相当于一个类型名 。
8.2 结构例日期可以用包含三个成员的结构来描述:
struct date
{ int year,month,day; };
学生信息的结构类型可说明如下:
struct student
{ char name[15];
char sex;
struct date birthday;
float score[4];
};
其中 struct date是一个已说明过的结构类型名 。
8.2 结构
8.2.1.2结构变量定义结构变量定义有 4种方法:
(1) 直接定义结构类型变量,将一个结构说明当成类型描述,在它后面列出变量标识符 。 这种表示方法没有结构名,定义形式如下:
struct {成员说明序列 } 结构变量表;
例,struct
{ char name[10];
int age;
int class;
} stu1,stu2[5],*stu3;
8.2 结构
8.2.1.2结构变量定义结构变量定义有 4种方法:
(2) 声明类型同时,定义结构变量
struct 结构名 {成员说明序列 } 结构变量表;
例,struct point {
double x,y,z;
} p1,p2,*p3;
说明结构类型 point,并定义三个变量 。
8.2 结构
8.2.1.2结构变量定义结构变量定义有 4种方法:
(3) 使用已声明的结构类型,定义结构变量
struct 结构类型名 结构变量表;
例:使用上面的例子中说明的 struct point。
struct point p1,p2[5],*p3;
(4) 定义结构类型,再定义结构变量
typedef struct {成员说明序列 } 结构类型名;
结构类型名 结构变量表;
8.2 结构
8.2.1.3结构的实现
C语言为结构对象分配足够大的存储空间,顺序地放入各个成员,但具体的存储位置,由一组对齐规则来调整,结构里的成员未必一个紧接着一个存放,它们之间可能有空位 。
结构类型和结构变量的空间计算,sizeof
讨论结构存储中使用对齐原则的原因
8.2 结构
8.2.2 结构变量的初始化和使用
8.2.2.1 结构变量的初始化可以在定义的同时初始化,使用 {}将变量的成员的初始化值组合起来 。
如 struct point {
double x,y;
} p1={1.5,4,6},p[3]={{1.5,2.5},{3.4,2.4},{8.6,9.0}};
初始化描述中的初始值将顺序提供给结构变量的各基本成员,初始化表达式只能是可静态求值的表达式 。 给出的初始化数据与结构成员类型一致,个数不得多于成员数量,如果提供的数据项不够,与数组的规定一样,其余成员自动用 0初始化 。
如果定义时没有提供初始值,系统对结构变量的处理方式与其它变量一样 。 外部和全局变量,用 0初始化,自动变量不进行初始化,各成员的状态不确定 。
8.2 结构
8.2.2 结构变量的初始化和使用
8.2.2.2 结构变量操作
1.整体赋值:
同样类型的结构变量,可整体进行相互赋值 。
2.结构成员引用成员运算符:两个运算符,,”和,->”,点号,,”
优先级:与圆括号,下标运算符相同,在 C的运算符中优先级最高结合方式:自左向右结构中简单变量成员的引用形式有下面三种:
(1) 结构变量名,成员名 ( 名字引用 )
(2) 结构指针 ->成员名 ( 指针引用 )
(3) (*结构指针 ).成员名 ( 将指针转化为名字应用 )
8.2 结构
8.2.2 结构变量的初始化和使用
8.2.2.2 结构变量操作
3.对结构成员进行操作结构变量中的每一个成员都属于某个具体的类型,可以象普通变量一样,对它进行同类变量所允许的任何操作 。
例:
scanf(“%s”,stu1.name);
strcpy(stu1.name,”Zhang yang”);
scanf(“%c”,&stu1.sex);
stu1.sex=’M’;
stu1.birthdat.year=1963;
scanf(“%d”,&stu1.birthday.year);
8.2 结构
8.2.3 结构与函数
(1) 向函数传递结构变量的成员
C语言函数实参,形参传递数据只有值传递,结构变量的成员可以是简单变量,数组或指针变量等,作为成员变量,可以参与其类型允许的任何操作,这个原则也适用于参数传递结构变量中的每一个成员都属于某个具体的类型,可以象普通变量一样,
对它进行同类变量所允许的任何操作 。
(2) 向函数传递结构变量把结构变量作为一个整体传递给函数,要求函数的形参也属于相同的结构类型 。 这时传递的是实参结构变量的值,系统将为相同结构类型的形参开辟相应的存储单元,并将实参中各成员的值赋给对应的形参成员 。
讨论结构变量作为函数参数的利弊 。
8.2 结构
8.2.3 结构与函数
(3) 传递结构的地址结构指针做函数实参,对应形参应该是一个基类型相同的结构指针 。
讨论结构地址作为函数参数的好处
8.2.4 结构指针与链表链表的特点是将数据存储在位置任意的结构存储块中,
用结构指针将这些存储块连接在一起,从第一个存储块顺着指针可以访问到所有的数据 。 链表中的每一个存储块叫一个结点 。
实现链表需要使用结构指针和动态存储管理机制 。
8.2 结构
8.2.4 结构指针与链表链表示意:
8.2 结构链表实现结点类型构造的讨论,指向本结点类型的指针是实现链表的基础
structnode
{ int data;
struct node*next;
};
联合也是 C语言的一种构造机制,一个联合通常由几个类型不同的成员组成,这些成员共享同一个位置开始的存储区 。 每一个时刻,联合只能保持它的某一个成员的值 。
8.3.1 联合类型说明,联合变量定义形式:
union {成员说明 } 变量表;
union 联合名 {成员说明 } 变量表;
例,union data
{ int i;
float f;
char str[5];
} d1,d2;
说明联合 data,同时定义了两个联合变量 d1和 d2。
8.3 联合联合既可以出现在结构内,它的成员也可以是结构 。 例:
struct
{ char name[10];
union
{ int roomnum;
char *addr;
} info;
} x[5];
8.3.2 联合变量的初始化和使用
8.3.2.1 联合变量初始化联合变量定义时也可以初始化,但初始化值只能给第一个成员 。
如,union data d1=10;
说明联合 data,同时定义了两个联合变量 d1和 d2。
8.3 联合
8.3.2.2 联合变量的使用
1,联合成员引用三种形式:
联合变量名,成员名指针变量名 ->成员名
(*指针变量名 ),成员名联合的成员变量同样可参与所属类型允许的所有操作 。
联合成员的赋 操作取到的值总是最近一次存入的成员变量的值 。
2,联合变量整体赋值赋值结果是两个存储区内容相同 。
8.3 联合
8.3.2.2 联合变量的使用
3,和函数有关的联合和结构一样,不仅联合成员可以象简单变量一样参与函数操作,
联合变量和联合指针可以做函数形参,返回值和调用实参 。
8.3.2.3 联合变量的存储联合变量存储区大小,由联合成员中要求最大存储空间的成员的空间要求决定 。
联合变量使用原则:保持使用和最近一次赋值意义上的一致,也就是说,程序中,原来在联合存储空间中以什么方式存入数据,
就应该按照这种方式要求的使用方法去使用存入的数据 。 这种一致性靠写程序的人来实现 。
8.3 联合枚举是 C语言中用于定义一组命名常量的机制 。 如果一个变量只有可能的几种值,可以定义为枚举类型 。 枚举是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围 。
枚举说明:
enum 枚举类型名 {枚举常量表 };
枚举常量表中枚举常量是用户定义的标识符,它们的值从 0开始从左向右递增 。 说明中可以用赋值号改变枚举常量的值,随后的枚举常量的值顺序递增,直到下一个指定特定值的枚举常量为止 。 作为枚举常量的标识符不能再做常量,变量的名字 。
枚举变量的定义形式为:
enum 枚举类型名 枚举变量 1,枚举变量 2...;
也可以在说明枚举类型的同时定义枚举变量 。
讨论程序设计中为什么使用枚举 。
8.4 枚举对二进制位的操作功能 。 可以用位运算符实现二进制直接操作 。
常用的位运算有四个:
位,否定,,一个运算对象,对象值为 1时得到 0值,对象值为 0时得到 1值 。
位,与,,两个运算对象的值都为 1时得到结果 1,其它情况结果为 0。
位,或,,两个运算对象的值都为 0时得到结果 0,其它情况结果为 1。
位,异或,,两个运算对象的值不相同时得到结果
1,否则结果为 0。
8.5 位运算和位段
8.5.1位运算
C语言中位运算符有,
按位求反 ~ ① 按位与 & ③
左移 << ② 按位异或 ^ ④
右移 >> ② 按位或 | ⑤
( 圆圈中的数字表示运算符的优先级 )
扩展运算符包括,<<=,>>=,&=,^=,|=。
位运算的实质是对字节或字中的实际位进行检测,设置或移位,
它只适用于字符型和整数型变量以及它们的变体,对其它数据类型不适用 。
移位运算:
右移,变量名 >>移位的位数左移,变量名 <<移位的位数讨论位运算符和逻辑运算符的不同 。
8.5 位运算和位段
8.5.1位运算 ---位运算实例:
(1) ~0110 将八进制数 110按位取反,结果为,0267( 八进制数 )
~ 01001000
10110111
(2)“左移,运算 ( <<):左端移出部分舍弃,右端补 0
char a=4,b; b=a<<2;
用二进制数表示:
a,00000100 (a=4)
b=a<<2,00010000 (b=16=4*2*2)
左移时,若左端移出部分没有 1,则每左移 1位,相当于移位对象乘以 2。
可用此方法代替乘法,加快运算速度 。 若左端移出包含 1,这一特性不成立 。 如:
char a=68,b; b=a<<2;
用二进制数表示:
a,01000100 (a=68)
b=a<<2,00010000 (b=16)
8.5 位运算和位段
8.5.1位运算 ---位运算实例:
(3)“右移,运算 (>>),右端移出部分舍弃,左端移入二进制保持原来数的性质,如果原来是正数或无符号数,移入补 0,否则移入补 1。
int a=-071000,b; b=a>>2;
用二进制数表示的过程如下:
a的原码,1111001000000000 ( a=-071000)
a的补码,1000111000000000 ( 机内形式 )
b=a>>2,1110001110000000 ( b机内形式,补码 )
b的原码,1001110010000000
b的八进制数,-016200
若右端移出部分没有 1,则每右移 1位,相当于移位对象除以 2。
(4) 按位,与,( &),和 0与的位得 0,和 1与的位保持不变 。 可用和 0与的方法,将某一位清 0,可用和 1与的方法取某一位的值 。
如,12&10的计算过程:
00001100
& 00001010
00001000
8.5 位运算和位段
8.5.1位运算 ---位运算实例:
(5) 按位,或,( |),和 1或的位得 1,和 0或的位保持不变 。 可用和 1或的方法,将某一位置 1,可用和 0或的方法取某一位的值 。
如,12|10的计算过程:
00001100
| 00001010
00001110
(6) 按位,异或,( ^),运算位上数相同得 0,数不同得 1。 可用和 1异或的方法,对某一位求反,可用和 0异或的方法保持某一位不变 。
如,12^10的计算过程:
00001100
^ 00001010
00000110
位运算对象长度不同时,将右端对齐,左端根据数的性质决定补 0或 1。
保持数据值的性质不变 。
8.5 位运算和位段
8.5.2位结构位结构是一种特殊的结构,其中以位为单位的成员称为,位段,或,位域,。
位结构定义的一般形式为,
struct位结构名
{ 数据类型 变量名,整型常数 ;
数据类型 变量名,整型常数 ;
} 位结构变量 ;
数据类型必须是 unsigned。 整型常数必须是非负的整数,范围是 0~15,
表示二进制位的个数,即表示有多少位 。 长度为 0的位段表示下一个位段从下一个存储单元开始存放 。
一个位段必须存储在同一存储单元中,不能跨两个单元 。 如果第一个单元空间中不能容纳下一个段位,则该空间不用,而从下一个单元起存放 。
讨论位段的存储注意,1,位结构中的成员不能使用数组和指针,但位结构变量可以是数组和指针,如果是指针,其成员访问方式同结构指针 。
2,位结构成员可以与其它结构成员一起使用 。
8.5 位运算和位段第八章 结构及其它本章主要知识点:
结构的基本概念 。 结构与成员的基本概念,结构与数组的区别,结构类型的定义,结构变量的说明,结构中成员占用存储器情况,与结构有关的运算符,引用结构中成员,结构变量的初始化,对结构成员的一般操作规定 。
结构与函数的关系 。 通过参数在函数之间传递结构的成员,传递整个结构,
函数的返回值为结构类型 。
结构与数组关系 。 将数组作为结构的成员,由结构构成结构数组,在函数之间传递结构数组 。
结构与指针的关系 。 指针作为结构中的成员,指向结构的指针,与结构指针相关的运算符,通过指针引用结构成员,结构的地址与结构成员的地址,
运算符 ->与其他相关运算符 ( ++,--,&,*和,) 的关系,在函数之间传递结构指针 。
结构的简单应用 。 链表的概念,用结构构成链表,链表的基本操作 。
联合的基本概念 。 联合与结构区别,联合类型的定义,联合变量的说明,
联合中成员占用存储器情况,与联合有关的运算符 (,),引用联合中的成员,联合变量的初始化 。
掌握本章内容的关键是理解数据类型对数据表示和运算的约束 。
回本章首页