0
点赞
收藏
分享

微信扫一扫

Cherno C++ P30 C++数组

静悠 2022-01-23 阅读 47

YouTube视频链接

C++数组

本文是ChernoP30视频的学习笔记。
  C++数组就是表示一堆相同类型变量组成的集合。假设我想要有5个整数的数组名为example。

int example[5];

  现在我们要设置和访问这些整数,先写数组的名字然后再[]内写上一种叫做索引(index)的东西。索引是在数组中指向的那一个变量或者元素,第一个元素要写上0,因为在C++中下标是从0开始的。

#include<iostream>
int main()
{
	int example[5];
	example[0] = 2;
	example[4] = 4;
	std::cin.get();
}

  我们为5个整型分配了空间,第一个索引是0,最后一个索引是4。打印这些元素只需要指明索引,如果想打印数组就需要打印这个数组的地址。因为实际上是一个指针类型。
在这里插入图片描述

数组的安全检查

  如果我们像exampl[-1]这样去使用了不属于这个数组的空间,在debug模式下会得到一个程序崩溃的错误消息。然而在release模式下可能不会得到报错信息,这意味着我们已经写入了不属于我们的内存。因此我们需要设置安全检查,确保总是在数组的边界内写东西。

数组和指针

  如下Main.cpp代码

#include<iostream>

int main()
{
	int example[5];

	for(int i=0;i<5;i++)
	example[0] = 2;

	std::cin.get();
}

  我们在std::cin.get();前设置断点,然后运行代码查看内存情况(调式->窗口->内存->内存1)。我们要去数组的内存地址,example实际上使它自己的内存地址,因为example是一个整型指针。我们在地址框中输入example,然后按下回车键,可以看到数组值一字排开。
在这里插入图片描述  所以数组一个很重要的点是存储的数据是连续的,在内存中每个整数是4个字节,所以我们得到的是一行20字节的内存。当我们通过example[i]来访问特定索引时,实际上是对内存取了一个偏移量。因为数组实际上只是一个指针,这里可以创建一个整型指针ptr,并赋值为example,可以发现编译正常。
在这里插入图片描述
  若我们访问2号元素设置等于5,结果是写入从指针开始8个字节的偏移量。我们也可以用指针简单地重写,指针算术上是ptr+2,然后逆向引用设置为6。我们在11行设置断点,然后到example的地址,它是数组的内存地址。我们可以看到example[2]也就是第三个元素的数字被设置为5。
在这里插入图片描述  然后继续按下F10,可以看到第三个元素已经变成6。由于指针为int类型,所以ptr+2将会增加2*4的偏移。
在这里插入图片描述

堆上创建数组

  我们还可以在堆上(heap)创建一个数组,通过new关键字来创建一个数组,[]内是数组大小,然后创建一个新的数组another,类型是int*。

#include<iostream>
zai
int main() 
{
	int example[5]; //在栈上创建
	int* another = new int[5]; //在堆上创建
	delete[] another;
	std::cin.get();
}

  这两行代码是一个意思,但是生存期不同。int example[5];是在栈上创建,当我们到达最后一行的花括号时,它会被销毁,因为跳出了作用域范围。如果是在堆上创建的话,直到程序把它销毁之前都是处于活动状态的,所以我们需要用delete关键字来删除。因为使用了数组的操作符[]来分配内存,我们还需要使用[]来删除它。
  在example数组中我们令example[i]等于2,对another数组也做同样的事情。在第12行设置断点并运行,我们在内存视图地址中输入another或者example都会得到5个2在一行的结果。
在这里插入图片描述  那么为什么要动态地使用new来分配,而不是在栈上创建呢。最大的原因还是生存期的不同,用new分配的内存将一直存在直到删除它。

堆上创建数组的间接寻址

  如果我创建一个名为Entity的类,然后将example数组移动到这里,再创建一个构造函数,用for循环语句初始化数组值为2,创建Entity对象e。

#include<iostream>
class Entity
{
public:
	int example[5];
	Entity()
	{
		for (int i = 0;i < 5;i++)
			example[i] = 2;
	}
};
int main()
{
	Entity e;

	std::cin.get();
}

  运作该程序,如果我们到Entity对象e的内存地址,即在内存视图地址中输入&e并按回车键,可以看到Entity的内存地址上就是一行2。
在这里插入图片描述  如果我们使用new关键字在堆上创建,运行完全相同的代码。再次进入内存地址,发现根本没有2,而是另一个内存地址。
在这里插入图片描述
  复制这个内存地址放到内存视图的地址中,但是要把它倒过来(小端法的原因),0x012feb88,按下回车键。会得到一行为2的数据,这就是所谓的间接寻址。
在这里插入图片描述
  我们实际得到的e的内存地址包含的另一个地址0x012feb88,才是我们数组的实际内存地址。所以应该在栈上创建数组来避免这种情况,因为这样在内存中跳跃肯定会影响性能。

C++11中的数组

  在C++11中我们有标准数组std::array,这是一个内置数据结构在C++11库中。它有很多优点,例如边界检查,记录数组大小(原始数组无法计算大小,无法使用example.size())。

std::arry<int,5>another;

  此时的another.size()大小为5。

举报

相关推荐

0 条评论