C++编程入门系列之八(自定义数据类型)
上两节中鸡啄米讲了编程入门知识-算法的选择结构和循环结构,这一讲鸡啄米给大家介绍下自定义数据类型。
什么是自定义数据类型呢?大家记得像char、int、float等类型吗?这些都是C++内置的基本数据类型,这些数据类型是不能满足我们在编程中的要求的,需要自己定义一些数据类型使用。自定义数据类型有:枚举类型、结构类型、联合类型、数组类型和类等。这一讲鸡啄米主要讲枚举类型、结构类型和联合类型,其他类型后面鸡啄米会细讲。
1.枚举类型
我们在现实当中经常遇到这种情况,描述一件事情时只能取几个有限的值,比如,一周只有星期一、星期二…星期日七天,比赛结果只有胜、负、平和比赛取消等四种结果。我们可以用0到6的整数表示星期一到星期日,7,8,9等都不是合法数据,如果我们用整数来表示星期几那就需要专门判断下是不是在0到6之间,但是如果用枚举类型定义就没有这种问题,因为枚举类型就那几个可能的值。枚举类型的声明形式为: enum 枚举类型名 { 变量值列表 }; 变量值列表里都是整型变量,另外不要忘记最后面的分号!
比如,enum weekday { sun,mon,tue,wed,thu,fri,sat };
这里的枚举元素sun、mon…都没有指定值,它们就使用默认值,依次为0,1,2…。即sun就是0,mon就是1,…sat是6。也可以在声明枚举类型时指定枚举元素的值,比如
enum weekday { sun=7, mon=1, tue, wed, thu, fri, sat };
这里sun就是7,mon是1,后面的值在mon的基础上依次加1,即tue等于2,wed为3…sat是6。枚举元素按常量处理,不能对它们赋值除了声明的时候,像sun=0;这样的语句就是非法的。
枚举类型我们声明了以后就能像int、float等类型那样用了,可以定义枚举类型的变量。整数值需要赋给枚举变量时,应进行强制类型转换。
鸡啄米给大家个例子:设某次体育比赛的结果有四种可能:胜(win)、负(lose)、平局(tie)、比赛取消(cancel),编写程序顺序输出这四种情况。分析:由于比赛结果只有四种可能,所以可以声明一个枚举类型,声明一个枚举类型的变量来存放比赛结果。
#include <iostream>
using namespace std;
enum game_result {WIN, LOSE, TIE, CANCEL};
int _tmain(int argc, _TCHAR* argv[])
{
game_result result; // 声明变量时,可以不写关键字enum
enum game_result omit = CANCEL; // 也可以在类型名前写上关键字enum
int count;
for (count = WIN ; count <= CANCEL ; count++)
{
result = (game_result)count;
if (result == omit)
{
cout << "The game was cancelled\n";
}
else
{
cout << "The game was played ";
if (result == WIN)
cout << "and we won!";
if (result == LOSE)
cout << "and we lost.";
cout << "\n";
}
}
return 0;
}
运行结果是:
- The game was played and we won!
- The game was played and we lost.
- The game was played
- The game was cancelled
2.结构体
有时候我们需要将一些不同类型的数据组合成一个整体,例如,一个学生的学号、姓名、年龄和成绩等,它们数据类型不同,但都属于一个人。这就要用到结构体了,结构体就是由不同数据类型也可以是相同数据类型的若干数据组成的结合体,声明形式为:
struct 结构体名
{
数据类型 成员名 1;
数据类型 成员名 2;
:
数据类型 成员名 n;
};
这里最后那个分号也不要忘记哦。鸡啄米把上面提到的那个学生的结构体可以定义成如下形式:
struct student //学生信息结构体
{
int num; //学号
char name[20]; //姓名
char sex; //性别
int age; //年龄
float score; //成绩
char addr[30]; //住址
};
定义了结构体类型,我们就可以用它来定义结构体变量,就像int a;那样。结构体型变量的定义形式也类似int等类型: 结构体类型名 结构体变量名;。比如,定义一个上面的那个结构体变量,student s;。可以像这样声明了结构体类型以后再定义结构体变量,也可以把它们放在一起。结构体变量占用内存的大小可以用sizeof(结构体类型名或变量名)计算。在定义结构体变量时可以直接赋初值。结构体成员的使用形式是:结构体变量名.成员名。
鸡啄米给大家一个结构体变量的例子。
#include <iostream>
using namespace std;
struct student //学生信息结构体
{
int num;//学号
char name[20];//姓名
char sex;//性别
int age;//年龄
}stu={97001,"Lin Lin",'F',19}; // 声明结构体类型的同时,定义结构体类型的变量,并赋初值。也可以分开。
int _tmain(int argc, _TCHAR* argv[])
{
cout<<stu.num<<" "<<stu.name<<" "<<stu.sex<<" "<<stu.age;
return 0;
}
大家可以放到vs2010上运行下看看结果。
3.联合体
有的时候需要几个不同类型的变量共用一组内存单元,这时就需要用联合体,联合体类型声明的语法形式为:
union 联合名
{
数据类型 成员名 1;
数据类型 成员名 2;
:
数据类型 成员名 n;
};
联合体类型变量声明的语法形式是:联合体类型名 联合体变量名;。联合体类型变量的引用形式是:联合体变量名.成员名。
鸡啄米给大家举个联合体类型的例子:
union uarea
{
char c_data;
short s_data;
long l_data;
};
联合体类型在内存中是怎样占用内存单元的呢?联合体占用的内存大小是其占内存最大的成员需要的内存大小,就像上边的uarea,它占用的内存大小就是最大成员long需要的4个字节。联合体里同时只能放一个成员的值。uarea放c_data时c_data占用第一个字节,放s_data时s_data占用前两个字节,放l_data时l_data占用全部的4个字节。
联合体也可以没有名称,叫做无名联合体。无名联合体只是声明一个成员项的集合,这些成员有相同的内存地址,可以用成员项的名字直接访问。鸡啄米给大家一个无名联合体例子:
union
{
int i;
float f;
}
在程序总可以直接用成员项i和f的名字访问i和f,比如 i=2; f=3.2;。无名联合体一般是用作结构体的内嵌成员。鸡啄米给写一个使用联合体的例子:
#include <iostream>
using namespace std;
union myun
{
int k;
struct { int x; int y; int z; }u;
}a;
int _tmain(int argc, _TCHAR* argv[])
{
a.u.x =4;
a.u.y =5;
a.u.z =6;
a.k = 0;
cout<<a.u.x<<" "<<a.u.y<<" "<<a.u.z<<" ";
return 0;
}
这个程序输出0 5 6。为什么呢?不应该是4,5,6吗?因为联合体的成员共用内存,所以a.u.x占用的内存里的4被后来的a.k**覆盖了**,变成了0。
4.类型定义语句–typedef
我们编程时除了可以使用基本数据类型名和自定义的数据类型名以外还可以给一个已经存在的数据类型起个别名,这样做有几个好处,可以给已有的类型起一个有意义的名字,我们一看就知道它表示什么,提高可读性;还可以给较长的类型名另起一个短名。使用的语法形式是:typedef 已有类型名 新类型名表;。新类型名表中可以有多个标识符,它们之间用逗号分开,就是在一个typedef语句中可以为一个已有数据类型声明多个别名,比如,
typedef double length,width;
length a;
width b;
鸡啄米讲了几个复杂点的自定义数据类型,大家好好消化吧,结构体类型用的比较多,而且结构体里可以放函数的,只是我们一般不那样用,跟我们以后要讲的C++中的核心概念-类很相似,可以说基本一样。就到这里了,大家辛苦了!
思考:
- 本文讲述了哪几个自定义的数据类型?
- 枚举类型的用处是什么? 写出一个枚举类型
- 结构体定义的形式以及在内存中存储的大小?
- 什么是联合体?如何定义的?占用的内存单元是多少?本文例子中的结果为什么与预想的不同