C++初探 4-4(复合类型 - 类型组合与数组的替代)

目录

类型组合

数组的替代品

模板类vector

模板类array(C++11)

比较数组、vector对象和array对象


        本笔记参考:《C++ PRIMER PLUS(第6版)》


类型组合

以结构的组合为例:

struct S1
{
	int year;
	char data;
};
  1. 创建结构S1的变量:
    S1 s_01, s_02, s_03;
    s_01.tear = 2000;    //使用成员运算符访问成员
  2. 创建指向结构S1的指针:

    S1* pa = &s_02;
    pa->year = 2000;        //使用间接成员运算符访问成员
  3. 创建结构S1的数组:

    S1 sArr[3];                //sArr是一个数组
    
    sArr[0].data = 'I';        //sArr[0]是一个结构
    (sArr + 1)->year = 2001;   //(数组名也是一个指针)相当于 sArr[1].year = 2001
  4. 创建S1的 结构指针 数组:

    S1* arp_1[3] = { &s_01, &s_02, &s_03 };
    const S1* arp_2[3] = { &s_01, &s_02, &s_03 };    //此处const的使用:防止指针指向的值被修改
    
    std::cout << arp[1]->data << std::endl;          

    其中,arp[1]就是一个指针,可以使用间接成员运算符。

  5. 创建S1的 结构指针数组 指针:

    const S1** ppa = arp_2;    //数组名arp指向该数组的首元素的地址
                               //因为前面的arp_2使用了const,此处也要使用,保持类型的统一
    

    注意,数组arp内的元素就是结构指针,也就是说,ppa指向的地址实际上存储的是一个指针的值,为了类型上的一致,需要使用一个二级指针。但是这种声明容易出错,为了方便,可以使用C++11带有的auto:

    auto ppb = arp_2;

    如果解引用二级指针,就会得到一个一级指针,也就是说,*ppa 是一个指向数组arp第一个元素的指针,即 &s_01 :

    std::cout << (*ppa)->year << std::endl;
    std::cout << (*(ppb + 1))->year << std::endl;

      上述输出的第二行语句,如果使用的是 (*ppb + 1) ,意思是将访问的地址向后移动1个字节,这样会造成输出错误。

            二级指针ppb的访问权限: +1 跳过数组arp_2的一个元素;

            一级指针*ppb的访问权限:+1 跳过1个字节。

数组的替代品

        模板类vector和array是数组的替代品,接下来将进行简单的介绍。

模板类vector

        类似于string类,vector也是一种动态数组:可以在运行阶段设置长度,在末尾添加新数据,在中间插入新数据。

  实际上,vector内部确实使用了new与delete来管理内存。

        要使用vector对象,要知道:

  1. vector对象需通过头文件vector进行引用;
  2. vector位于名称空间std中;
  3. 这种模板使用不同语法指定其的存储类型和元素数。

使用例:

#include<iostream>
#include<vector>

int main()
{
	using namespace std;

	vector<int> vi;			//创建一个int类型的数组,可存储 0 个元素

	int n = 0;
	cin >> n;
	vector<double>vd(n);	//创建一个double类型的数组,可存储 n 个元素

	return 0;
}

        由于vector对象可以在插入或者添加值时自动调整长度,因此可以将 vi 的初始长度设置为 0 (后继的长度调整需要使用vector包内的方法)。

        vector对象的声明方式:

        vector类的功能比数组更加强大,但是效率却更低,而原本的数组不怎么方便和安全。为此,C++11新增了模板类array。

模板类array(C++11)

        类array同样位于名称空间std中,使用时需要包含头文件array。

        与数组一样,array对象的长度是固定的,并且被存储在栈(静态内存分配)中。它拥有与数组比肩的效率,并且更加安全、方便。

使用例:

#include<iostream>
#include<array>

int main()
{
	using namespace std;
	array<int, 5> ai;		//创建一个array类,类型是int,可存储5个元素
	array<double, 4> ad = { 1.2, 3.1, 3.1416, 4.3 };	

	return 0;
}

        array对象的声明方式:

比较数组、vector对象和array对象

通过例子比较两者的区别:

#include<iostream>
#include<vector>
#include<array>

int main()
{
	using namespace std;

	double a_1[4] = { 1.2, 2.4, 3.6, 4.8 };	//原始的数组类型

	vector<double> a_2(4);	//创建一个初始可以包含4个元素的vector对象
	//C98:没有初始化vector的快捷方式
	a_2[0] = 1.0 / 3.0;
	a_2[1] = 1.0 / 5.0;
	a_2[2] = 1.0 / 7.0;
	a_2[3] = 1.0 / 9.0;

	//C++11:创建,并初始化array对象
	array<double, 4> a_3 = { 3.14, 2.72, 1.62, 1.41 };
	array<double, 4> a_4;
	a_4 = a_3;				//这种处理方式在大小相同的array对象中可以成立

	//使用array对象
	cout << "a_1[2]:" << a_1[2] << "\t 其地址为 " << &a_1[2] << endl;
	cout << "a_2[2]:" << a_2[2] << " 其地址为 " << &a_2[2] << endl;
	cout << "a_3[2]:" << a_3[2] << "\t 其地址为 " << &a_3[2] << endl;
	cout << "a_4[2]:" << a_4[2] << "\t 其地址为 " << &a_4[2] << endl;

	//错误的存储操作
	cout << endl << "进行操作:a_1[2] = 20.2;" << endl;
	a_1[-2] = 20.2;
	cout << "上述操作将会导致:" << endl;
	cout << "\ta_1[-2]:" << a_1[-2] << "\t其地址为 " << &a_1[-2] << endl;
	cout << "\ta_3[2] :" << a_3[2] << "\t其地址为 " << &a_3[2] << endl;
	cout << "\ta_4[2] :" << a_4[2] << "\t其地址为 " << &a_4[2] << endl;

	return 0;
}

程序执行的结果是(本次编译在Ubantu系统中进行):

【分析】

        ① 首先要注意三点:

  1. 数组、vector对象和array对象都可以通过标准数组表示法访问元素;
  2. array对象与数组存储在栈中,而vector对象存储在堆中;
  3. array对象可以整体赋值,或者在对象之间进行赋值。但数组和vector对象只能逐元素操作。

        ② 另外,上述提到了一个错误的操作:

a_1[-2] = 20.2;

        实际上,在一些编译器中,上述这种语句会引发警告:

        因为 a_1[-2] 等价于 *(a_1 - 2) ,所以这条语句的含义是将a_1的指向 向前移动两个double元素的单位,在这个位置进行信息的存储。

  注:C++不检查这种越界访问错误。因此,这种错误可能影响内存中其他正在运行的程序,这是不安全的。

        那么vector对象和array对象有禁止这种行为吗?答案是可以禁止,或者说,仍然可以书写上述这种不安全的代码:

a_2[-2] = .5;
a_3[200] = 1.4;

尽管在程序执行时,可能引发assert警告:

        ③ 为了解决②中的问题,可以使用vector对象和array对象的成员函数at():

a_2.at(1) = 2.3;	//将2.3输入到a_2[1]中

        这个成员函数将会在运行期间捕获非法索引,程序将默认中断。(代价是:这种额外的检查将会运行更长时间)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值