一、联合的定义
定义一个联合类型的一般形式为:
union 联合名
{
成员表
};
成员表中含有若干成员,成员的一般形式为: 类型说明符 成员名 成员名的命名应符合标识符的规定。
例如:
union
perdata { int class; char office[10]; };
定义了一个名为perdata的联合类型,它含有两个成员,一个为整型,成员名为class;另一个为字符数组,数组名为office。联合定义之后,即可进行联合变量说明,被说明为perdata类型的变量,可以存放整型量class或存放字符数组office。
二、联合变量的说明
联合变量的说明和结构变量的说明方式相同,
也有三种形式。即先定义,再说明;定义同时说明和直接说明。以perdata类型为例,说明如下:
union
perdata { int class; char officae[10]; }; union perdata
a,b; 或者可同时说明为: union perdata { int class;
char office[10]; }a,b;或直接说明为: union { int class; char office[10];
}a,b 经说明后的a,b变量均为perdata类型。 它们的内存分配示意图如图7—8所示。a,b变量的长度应等于 perdata
的成员中最长的长度, 即等于
office数组的长度,共10个字节。从图中可见,a,b变量如赋予整型值时,只使用了2个字节,而赋予字符数组时,可用10个字节。
联合变量的赋值和使用
对联合变量的赋值,使用都只能是对变量的成员进行。 联合变量的成员表示为: 联合变量名.成员名
例如,a被说明为perdata类型的变量之后,可使用 a.class a.office 不允许只用联合变量名作赋值或其它操作。
也不允许对联合变量作初始化赋值,赋值只能在程序中进行。还要再强调说明的是,一个联合变量,
每次只能赋予一个成员值。换句话说,一个联合变量的值就是联合变员的某一个成员值。
[例7.15]设有一个教师与学生通用的表格,教师数据有姓名,年龄,职业,教研室四项。学生有姓名,年龄,职业,班级四项。
编程输入人员数据, 再以表格输出。
main()
{ struct { char name[10]; int age; char job; union { int class;
char office[10]; } depa; }body[2]; int n,i; for(i=0;i<2;i++) {
printf("input name,age,job and department\n"); scanf("%s %d
%c",body[i].name,&body[i].age,&body[i].job);
if(body[i].job=='s') scanf("%d",&body[i].depa.class); else
scanf("%s",body[i].depa.office); } printf("name\tage job
class/office\n"); for(i=0;i<2;i++) { if(body[i].job=='s')
printf("%s\t= < %d\n",body[i].name,body[i].age
,body[i].job,body[i].depa.class); else printf("%s\t= <
%s\n",body[i].name,body[i].age, body[i].job,body[i].depa.office); }
} 本例程序用一个结构数组body来存放人员数据, 该结构共有四个成员。其中成员项depa是一个联合类型,
这个联合又由两个成员组成,一个为整型量class,一个为字符数组office。在程序的第一个for语句中,输入人员的各项数据,先输入结构的前三个成员name,age和job,然后判别job成员项,如为"s"则对联合depa·class输入(对学生赋班级编号)否则对depa·office输入(对教师赋教研组名)。
在用scanf语句输入时要注意,凡为数组类型的成员,无论是结构成员还是联合成员,在该项前不能再加"&"运算符。如程序第18行中
body[i].name是一个数组类型,第22行中的body[i].depa.office也是数组类型,因此在这两项之间不能加"&"运算符。程序中的第二个for语句用于输出各成员项的值:
本章小结
1.
结构和联合是两种构造类型数据,是用户定义新数据类型的重要手段。结构和联合有很多的相似之处,它们都由成员组成。成员可以具有不同的数据类型。成员的表示方法相同。都可用三种方式作变量说明。
2.
在结构中,各成员都占有自己的内存空间,它们是同时存在的。一个结构变量的总长度等于所有成员长度之和。在联合中,所有成员不能同时占用它的内存空间,它们不能同时存在。联合变量的长度等于最长的成员的长度。
3. “.”是成员运算符,可用它表示成员项,成员还可用“->”运算符来表示。
4.
结构变量可以作为函数参数,函数也可返回指向结构的指针变量。而联合变量不能作为函数参数,函数也不能返回指向联合的指针变量。但可以使用指向联合变量的指针,也可使用联合数组。
5. 结构定义允许嵌套,结构中也可用联合作为成员,形成结构和联合的嵌套。
6. 链表是一种重要的数据结构,它便于实现动态的存储分配。本章介绍是单向链表,还可组成双向链表,循环链表等。
typedef是类型定义的意思。typedef
struct 是为了使用这个结构体方便。
具体区别在于:
若struct node {}这样来定义结构体的话。在申请node 的变量时,需要这样写,struct node n;
若用typedef,可以这样写,typedef struct node{}NODE; 。在申请变量时就可以这样写,NODE
n;
区别就在于使用时,是否可以省去struct这个关键字。
分三块来讲述:
1 首先:
在C中定义一个结构体类型要用typedef:
typedef struct Student
{
int a;
}Stu;
于是在声明变量的时候就可:Stu stu1;
如果没有typedef就必须用struct Student stu1;来声明
这里的Stu实际上就是struct Student的别名。
另外这里也可以不写Student(于是也不能struct Student stu1;了)
typedef struct
{
int a;
}Stu;
但在c++里很简单,直接
struct Student
{
int a;
};
于是就定义了结构体类型Student,声明变量时直接Student stu2;
===========================================
2其次:
在c++中如果用typedef的话,又会造成区别:
struct Student
{
int a;
}stu1;//stu1是一个变量
typedef struct Student2
{
int a;
}stu2;//stu2是一个结构体类型
使用时可以直接访问stu1.a
但是stu2则必须先 stu2 s2;
然后 s2.a=10;
===========================================
3 掌握上面两条就可以了,不过最后我们探讨个没多大关系的问题
如果在c程序中我们写:
typedef struct
{
int num;
int age;
}aaa,bbb,ccc;
这算什么呢?
我个人观察编译器(VC6)的理解,这相当于
typedef struct
{
int num;
int age;
}aaa;
typedef aaa bbb;
typedef aaa ccc;
也就是说aaa,bbb,ccc三者都是结构体类型。声明变量时用任何一个都可以,在c++中也是如此。但是你要注意的是这个在c++中如果写掉了typedef关键字,那么aaa,bbb,ccc将是截然不同的三个对象。
第四篇:C/C++中typedef
struct和struct的用法
struct
_x1 { ...}x1; 和 typedef struct _x2{ ...} x2; 有什么不同?
其实,
前者是定义了类_x1和_x1的对象实例x1, 后者是定义了类_x2和_x2的类别名x2 ,
所以它们在使用过程中是有取别的.请看实例1.
[知识点]
结构也是一种数据类型,
可以使用结构变量, 因此, 象其它 类型的变量一样, 在使用结构变量时要先对其定义。
定义结构变量的一般格式为:
struct
结构名
{
类型
变量名;
类型
变量名;
...
}
结构变量;
结构名是结构的标识符不是变量名。
另一种常用格式为:
typedef
struct 结构名
{
类型
变量名;
类型
变量名;
...
}
结构别名;
另外注意:
在C中,struct不能包含函数。在C++中,对struct进行了扩展,可以包含函数。
======================================================================
实例1:
struct.cpp
#include
using namespace std; typedef struct _point{ int x; int y; }point;
//定义类,给类一个别名 struct _hello{ int x,y; } hello; //同时定义类和对象 int main()
{ point pt1; pt1.x = 2; pt1.y = 5; cout<< "ptpt1.x=" <<
pt1.x << "pt.y=" < //hello pt2; //pt2.x = 8; //pt2.y =10;
//cout<
//上面的hello pt2;这一行编译将不能通过. 为什么? //因为hello是被定义了的对象实例了. //正确做法如下:
用hello.x和hello.y hello.x = 8; hello.y = 10; cout<<
"hellohello.x=" << hello.x << "hello.y=" < return 0;
} 第五篇:问答
Q:
用struct和typedef struct 定义一个结构体有什么区别?为什么会有两种方式呢?
struct
Student
{
int a;
} stu;
typedef struct Student2
{
int a;
}stu2;
A:
事实上,这个东西是从C语言中遗留过来的,typedef可以定义新的复合类型或给现有类型起一个别名,在C语言中,如果你使用
struct xxx
{
}; 的方法,使用时就必须用 struct xxx var 来声明变量,而使用
typedef struct
{
}的方法 就可以写为 xxx var;
不过在C++中已经没有这回事了,无论你用哪一种写法都可以使用第二种方式声明变量,这个应该算是C语言的糟粕。
用法小结
第一、四个用途
用途一:
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,
// 和一个字符变量;
以下则可行:
typedef char* PCHAR; // 一般用大写
PCHAR pa, pb; // 可行,同时声明了两个指向字符变量的指针
虽然:
char *pa, *pb;
也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。
用途二:
用在旧的C的代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为:
struct 结构名 对象名,如:
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;
而在C++中,则可以直接写:结构名
对象名,即:
tagPOINT1 p1;
估计某人觉得经常多写一个struct太麻烦了,于是就发明了:
typedef struct tagPOINT
{
int x;
int y;
}POINT;
POINT
p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候
或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。
枚举
在实际问题中, 有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月,
一个班每周有六门课程等等。如果把这些量说明为整型, 字符型或其它类型显然是不妥当的。
为此,C语言提供了一种称为“枚举”的类型。在“枚举”类型的定义中列举出所有可能的取值,
被说明为该“枚举”类型的变量取值不能超过定义的范围。应该说明的是, 枚举类型是一种基本数据类型,而不是一种构造类型,
因为它不能再分解为任何基本类型。
枚举类型的定义和枚举变量的说明
一、枚举的定义枚举类型定义的一般形式为:
enum 枚举名
{ 枚举值表 };
在枚举值表中应罗列出所有可用值。这些值也称为枚举元素。
例如: enum weekday
{ sun,mou,tue,wed,thu,fri,sat };
该枚举名为weekday,枚举值共有7个,即一周中的七天。 凡被说明为weekday类型变量的取值只能是七天中的某一天。
二、枚举变量的说明 如同结构和联合一样,枚举变量也可用不同的方式说明,
即先定义后说明,同时定义说明或直接说明。设有变量a,b,c被说明为上述的weekday,可采用下述任一种方式:
enum weekday
{
......
};
enum weekday a,b,c;或者为: enum weekday
{
......
}a,b,c;或者为: enum
{
......
}a,b,c;
枚举类型变量的赋值和使用
枚举类型在使用中有以下规定:
1. 枚举值是常量,不是变量。不能在程序中用赋值语句再对它赋值。例如对枚举weekday的元素再作以下赋值:
sun=5;mon=2;sun=mon; 都是错误的。
2. 枚举元素本身由系统定义了一个表示序号的数值,从0 开始顺序定义为0,1,2…。如在weekday中,sun值为0,mon值为1,
…,sat值为6。
main(){
enum weekday { sun,mon,tue,wed,thu,fri,sat } a,b,c; a=sun; b=mon;
c=tue; printf("%d,%d,%d",a,b,c); } 3.
只能把枚举值赋予枚举变量,不能把元素的数值直接赋予枚举变量。如: a=sum;b=mon; 是正确的。而: a=0;b=1;
是错误的。如一定要把数值赋予枚举变量,则必须用强制类型转换,如: a=(enum
weekday)2;其意义是将顺序号为2的枚举元素赋予枚举变量a,相当于: a=tue;
还应该说明的是枚举元素不是字符常量也不是字符串常量, 使用时不要加单、双引号。
main(){
enum body { a,b,c,d } month[31],j; int i; j=a;
for(i=1;i<=30;i++){ month[i]=j; j++; if (j>d) j=a; }
for(i=1;i<=30;i++){ switch(month[i]) { case a:printf(" -
%c\t",i,'a'); break; case b:printf(" - %c\t",i,'b'); break; case
c:printf(" - %c\t",i,'c'); break; case d:printf(" - %c\t",i,'d');
break; default:break; } } printf("\n"); }位域
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态,
用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,
并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。
这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:
struct 位域结构名
{ 位域列表 };
其中位域列表的形式为: 类型说明符 位域名:位域长度
例如:
struct
bs { int a:8; int b:2; int c:6; }; 位域变量的说明与结构变量说明的方式相同。
可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:
struct
bs { int a:8; int b:2; int c:6; }data;
说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:
1.
一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:
struct
bs { unsigned a:4 unsigned :0 unsigned
b:4 unsigned c:4 }
在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。
2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。
3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct
k { int a:1 int :2 int b:3 int c:2 };
从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。
二、位域的使用位域的使用和结构成员的使用相同,其一般形式为:
位域变量名·位域名 位域允许用各种格式输出。
main(){
struct bs { unsigned a:1; unsigned b:3; unsigned c:4; } bit,*pbit;
bit.a=1; bit.b=7; bit.c=15; printf("%d,%d,%d\n",bit.a,bit.b,bit.c);
pbit=&bit; pbit->a=0; pbit->b&=3;
pbit->c|=1;
printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); }
上例程序中定义了位域结构bs,三个位域为a,b,c。说明了bs类型的变量bit和指向bs类型的指针变量pbit。这表示位域也是可以使用指针的。
程序的9、10、11三行分别给三个位域赋值。(
应注意赋值不能超过该位域的允许范围)程序第12行以整型量格式输出三个域的内容。第13行把位域变量bit的地址送给指针变量pbit。第14行用指针方式给位域a重新赋值,赋为0。第15行使用了复合的位运算符"&=",
该行相当于:
pbit->b=pbit->b&3位域b中原有值为7,与3作按位与运算的结果为3(111&011=011,十进制值为3)。同样,程序第16行中使用了复合位运算"|=",
相当于: pbit->c=pbit->c|1其结果为15。程序第17行用指针方式输出了这三个域的值。
类型定义符typedef
C语言不仅提供了丰富的数据类型,而且还允许由用户自己定义类型说明符,也就是说允许由用户为数据类型取“别名”。
类型定义符typedef即可用来完成此功能。例如,有整型量a,b,其说明如下: int aa,b;
其中int是整型变量的类型说明符。int的完整写法为integer,
为了增加程序的可读性,可把整型说明符用typedef定义为: typedef int INTEGER
这以后就可用INTEGER来代替int作整型变量的类型说明了。 例如: INTEGER a,b;它等效于: int a,b;
用typedef定义数组、指针、结构等类型将带来很大的方便,不仅使程序书写简单而且使意义更为明确,因而增强了可读性。例如:
typedef char NAME[20]; 表示NAME是字符数组类型,数组长度为20。
然后可用NAME 说明变量,如: NAME a1,a2,s1,s2;完全等效于: char
a1[20],a2[20],s1[20],s2[20]
又如:
typedef struct stu{ char name[20];
int age;
char sex;
} STU;
定义STU表示stu的结构类型,然后可用STU来说明结构变量: STU body1,body2;
typedef定义的一般形式为: typedef 原类型名 新类型名 其中原类型名中含有定义部分,新类型名一般用大写表示,
以
便于区别。在有时也可用宏定义来代替typedef的功能,但是宏定义是由预处理完成的,而typedef则是在编译时完成的,后者更为灵活方便。
本章小结
1. 枚举是一种基本数据类型。枚举变量的取值是有限的,枚举元素是常量,不是变量。
2.
枚举变量通常由赋值语句赋值,而不由动态输入赋值。枚举元素虽可由系统或用户定义一个顺序值,但枚举元素和整数并不相同,它们属于不同的类型。因此,也不能用printf语句来输出元素值(可输出顺序值)。
3. 位运算是C语言的一种特殊运算功能,
它是以二进制位为单位进行运算的。位运算符只有逻辑运算和移位运算两类。位运算符可以与赋值符一起组成复合赋值符。如&=,|=,^=,>>=,<<=等。
4. 利用位运算可以完成汇编语言的某些功能,如置位,位清零,移位等。还可进行数据的压缩存储和并行运算。
5. 位域在本质上也是结构类型,不过它的成员按二进制位分配内存。其定义、说明及使用的方式都与结构相同。
6. 位域提供了一种手段,使得可在高级语言中实现数据的压缩,节省了存储空间,同时也提高了程序的效率。
7. 类型定义typedef
向用户提供了一种自定义类型说明符的手段,照顾了用户编程使用词汇的习惯,又增加了程序的可读性