第四章 C++ 构造数据类型

本文详细介绍了C++中的构造数据类型,包括数组、指针、引用、结构体和枚举等,阐述了它们的定义、使用方法及注意事项。

基本数据类型能够单独处理一些简单的单一数据。对于一些复杂的数据,需要用构造数据类型进行描述。构造数据类型是由用户按照一定的语法规则自定义的数据类型。C++语言支持的构造数据类型有数组,指针,引用,结构体,枚举和类等等。

数组是一系列具有相同类型的数据的集合。一维数组是存储相同类型的一组数据。数组的每个存储单元可存储一个数据,这些数据称为该数组的元素。每个元素都有一个标号,称为数组的下标。使用数组名和下标可以访问数组中的元素。以下是数组的定义语法:

<数据类型>  <数组名>[<常量>] [={<初始值列表>}];

int a_array[5];				        // 定义名称为a_array的数组,长度是5
a_array[0] = 1;
a_array[1] = 2;
a_array[2] = 3;
a_array[3] = 4;
a_array[4] = 5;
std::cout << a_array[1] << "\n";	// 输出 2

int b_array[5] = {1,2,3,4,5};	    // 定义并初始化数组,能少,不能多
b_array[1] = 66;
std::cout << b_array[1] << "\n";	// 输出 66

数组的大小是一个常量,而不是一个变量,即数组大小是固定不变的明确数值。数组是内存中一片连续的存储空间,并固定下标从0开始计数,即第1个元素的下标是0,第2个元素的下标是1,以此类推。数组中任何一个元素都可以单独访问,访问的方式如下:<数组名>[<下标>]

备注:假如我们定义数组长度是10,但是访问的时候使用下标超过了10,例如x[12]去访问或者操作此元素,我们将这种情况称之为数组越界。越界访问数组可能导致程序出错,但是C++编译器对此并不做检查,但是程序运行的时候可能会崩溃!

多维数组是指维数大于1的数组,最常用的多维数组是二维和三维数组,定义如下方式:

int c_array[2][3];				// 定义一个2行3列的数组
c_array[0][0] = 1;
c_array[0][1] = 2;
c_array[0][2] = 3;
c_array[1][0] = 4;
c_array[1][1] = 5;
c_array[1][2] = 6;
std::cout << c_array[0][1] << "\n";	// 输出 2

int d_array[2][3] = { {1,2,3},{4,5,6} };
d_array[0][1] = 99;
std::cout << d_array[0][1] << "\n";	// 输出 99

二维数组可理解为“数组中的数组”,即数组中的每个元素又是一个一维数组。C++采用行优先存储规则,即先存第1行,再存第2行,以此类推。我们可以将一维数组理解成一行的线性数据形式,二维数组理解成行列的面性数据形式。例如上文中的c_array数组就如同这样的数据形式:

1  2  3

4  5  6

如果我们要访问二维数组里面的元素,就需要使用第一个中括号来确定第几行,然后使用第二个中括号来确定是第几列,这样就能唯一的标示出数组中的元素了。

按照数组元素的数据类型分类,数组可以分为数值数组,字符数组,指针数组,对象数组等等,这里重点介绍字符数组。字符数组是数据类型为char的数组。字符数组可以是一维的,用于存储一串字符,也可以是二维的,存储多个字符串。C++中的字符串在字符数组中以”\0”ASCII码值为0的空字符)作为结束符。举例如下:

char e_array[3];
e_array[0] = 'a';
e_array[1] = 'b';
e_array[2] = 'c';
std::cout << e_array[1] << "\n";	// 输出 b

char f_array[3] = {'A','B','C'};
std::cout << f_array[1] << "\n";	// 输出 B

char g_array[] = "hello,array";
std::cout << g_array[1] << "\n";	// 输出 e

备注:用char数组存储字符串的时候,数组的长度为:西文字字符数加1,中文字符数乘2再加1。这是因为1个西方字符的编码占用1个字节,1个汉字字符的编码占2个字节,加1是用于存储”\0”空字符。如果使用wchar_t数组的话,数组长度计算就又不一样了,大家可以自行推测一下。

char g_array[] = "hello,array";
std::cout << g_array[1] << "\n";	// 输出 e

int g_len = sizeof(g_array) / sizeof(g_array[0]);
std::cout << g_len << "\n";			// 输出数组长度 12

char h_array[] = "中国";
int h_len = sizeof(h_array) / sizeof(h_array[0]);
std::cout << h_len << "\n";			// 输出数组长度 5

wchar_t w_array[] = L"中国";
int t_len = sizeof(w_array) / sizeof(w_array[0]);
std::cout << t_len << "\n";			// 输出数组长度 3

指针类型是C/C++语言特有的数据类型。其他高级语言(C#Java)中,都不支持指针类型。指针是是一种特殊的数据类型,其值为内存地址。用指针类型说明的变量称为指针变量,保存了内存单元的地址。也就是说可以通过指针变量去直接访问内存空间。内存地址就是一个整数,系统为每个内存单元分配一个唯一的地址。定义指针变量的语法如下:

<数据类型> *<指针变量名> [= &<变量>];

int pa = 100;					// 定义一个普通int变量p_a
int* pb = &pa;					// 定义一个指针变量p_b,其值是变量p_a的内存地址
std::cout << *pb  << "\n";		// 输出 100, pa和*pb 是同一个内存空间

*星号是指针类型的关键字。在定义指针变量的同时,可以把另一个变量的内存地址赋予给该指针变量。指针数据类型应该与后面变量的数据类型相同。指针变量可以赋值NULL0,称之为空指针。用取地址符&可将普通变量的内存首地址赋值给指针变量。由于指针变量中存放的是内存首地址,因此指针变量的运算也就是内存地址的运算。

需要注意的是,在C++语言中,数组名就是一个指针常量,它指向数组的起始位置。也就是说,我们可以把数组名直接赋予一个指针变量,通过指针变量照样可以访问数组元素,如下:

int i_array[5] = { 1,2,3,4,5 };
int* pi = i_array;                      // 没有使用&取地址符
std::cout << *pi << std::endl;			// 输出1,相当于i_array[0]
std::cout << *(pi+1) << std::endl;		// 输出2,相当于i_array[1]

同样的,我们也可以使用指针来定义一个数组,如下:

int* p_array = new int[5];					// 用指针定义数组
p_array[0] = 123;
*(p_array + 1) = 456;
std::cout << p_array[0] << std::endl;		// 输出123
std::cout << *(p_array+1) << std::endl;		// 输出456

当使用一个指针变量指向一个二维数组的时候,指针变量对应的值就是一个一维数组,如下:

int j_array[2][3] = { {1,2,3},{4,5,6} };	// 定义一个二维数组
int(*pj)[3] = j_array;						// 不能直接赋值给cPtr,得有[3]
std::cout << (*pj)[0] << std::endl;			// 输出 1,相当于j_array[0][0]
std::cout << (*(pj+1))[0] << std::endl;		// 输出 4,相当于j_array[1][0]
std::cout << *(*(pj+1)+1) << std::endl;		// 输出 5,相当于j_array[1][1]

引用就是别名,就是给一个变量另命名一个名称。在程序中,可以用变量名访问变量的值,也可以用它的别名读取或操作变量的值。引用类型的定义语法如下:

<数据类型> &<引用变量名称> = <已定义的变量名>;

int rx = 200;
int& ry = rx;                   // 直接变量赋值即可
std::cout << ry << std::endl;	// 输出 200,n就是m的另一个名字

&符号用于声明引用类型的关键字,<数据类型>必须与被引用变量的数据类型完全相同。引起变量只在定义时候赋值,之后引用变量不再接受另外变量名的赋值。请注意&符号的使用,在指针使用的时候,它作为操作符,用来获取变量的内存地址。在定义类型的时候,它表示引用数据类型。

int rz = 300;
ry = rz;					    // 按照理解,ry应该变了,指向了rz
std::cout << ry << std::endl;	// 输出 300,这个ry是rx?还是rz?

rz = 400;
std::cout << ry << std::endl;	// 输出 300,说明ry不是rz
std::cout << rz << std::endl;	// 输出 400,说明ry不是rz
std::cout << rx << std::endl;	// 输出 300,说明ry仍然是rx

我们再ry初始化的时候,指向了rx,说明ry就是rx。后面我们使用ry=rz的时候,并不是让ry指向rz,而是把300的数值给了ry和rx,这就是为什么rz变成400之后,ry和rx仍然是300。

结构体是一个由程序员自定义的数据类型,可以容纳许多不同的数据值。一旦结构体类型被声明并且其数据成员被标识,即可创建该类型的多个变量。

使用关键字 struct来声明结构体。举例如下:

struct Student				// 定义一个学生的结构体
{
	int num;				// 学生序号
	char* name;			    // 学生姓名
	double score;			// 学生考试分数
};

Student stu1;
stu1.num = 1;
stu1.name = (char*)"richie";
stu1.score = 100;
std::cout << stu1.name << std::endl;	// 输出 richie

Student stu2 = { 2, (char*)"lee", 98 };
std::cout << stu2.name << std::endl;	// 输出 lee

我们自定义了一个数据类型student,然后就可以将student当做一个数据类型使用,定义其变量。

枚举类型是由若干个语义相关的枚举常量组成的集合。定义语法如下:

enum color {red, green, blue};	// 定义 Color 枚举类型,其中red=0, green=1, blue=2
color eye = red;				// 定于枚举型(color)变量eye,其值为red,也就是0
std::cout << eye << std::endl;	// 输出 0

enum是枚举类型关键字,<枚举类型名>由用户自定义。一个枚举类型包含多个枚举常量。枚举类型定义后,<枚举类型名>即成为新的数据类型名称,与基本数据类型一样使用。我们使用color数据类型定义变量后,该变量的值就只能是定义color类型时候的red,green,blue三个数值中的一个。

 本课程的所有代码案例下载地址:

C++示例源代码(配合教学课程使用)-C/C++文档类资源-CSDN下载

备注:这是我们游戏开发系列教程的第一个课程,主要是编程语言的基础学习,优先学习C++编程语言,然后进行C#语言,最后才是Java语言,紧接着就是使用C++和DirectX来介绍游戏开发中的一些基础理论知识。我们游戏开发系列教程的第二个课程是Unity游戏引擎的学习。课程中如果有一些错误的地方,请大家留言指正,感激不尽!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咆哮的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值