【C++养成计划】深入数组和字符串(Day8)

一曲冷凌霜 提交于 2020-07-23 23:52:28

写在前面:大家好!我是【AI 菌】,一枚爱弹吉他的程序员。我热爱AI、热爱分享、热爱开源! 这博客是我对学习的一点总结与记录。如果您也对 深度学习、机器视觉、算法、Python、C++ 感兴趣,可以关注我的动态,我们一起学习,一起进步~
我的博客地址为:【AI 菌】的博客

上一篇:【C++养成计划】玩转数字——数学运算函数/随机数(Day7)
昨天,我们学习了对有关数字的一常用些操作;今天来一起探索C++中两种最基本的数据结构:数组和字符串。



1. 初探数组

(1) 什么是数组

在C++中,数组让你可以按照顺序将一系列相同类型的数据存储到内存中。
数组具有如下几个特点:

  • 数组是一系列元素
  • 数组中所有元素的类型都相同
  • 这组元素组成一个完整的集合

(2) 数组的存储方式

在这里插入图片描述
数组的存储方式和图书馆中存放书的方式是类似的。想想书架上某一排上存放的书籍,这就是一个一维数组,因为它只沿着一个维度延伸。每本书都是一个数组元素,而书架就是为存储这些书籍而预留的内存。

同样的道理,整个书架就是一个二维数组,因为它不仅可以沿着横向延伸,还能沿着纵向延伸。那么一个图书室就可以看成是一个三维数组,因为一个图书室有很多个书架,每个书架还能按行和列摆放不同书籍,可以从3个不同维度延伸。如此说来,整个图书馆有很多个图书室,因此它可以沿着4个维度延伸,所以图书馆可看作是一个四维数组。依次类推,可以举例出n维数组。

存储数据的空间大小,也就类似于书占书架的位置多少。不同的是,数组中每一个元素所占用的空间大小是相同的,因为数组中所有元素的类型都相同。元素所占用的空间大小与元素的类型有关。比如一个int类型的元素占用4个字节的空间,一个double类型的元素占用8个字节的空间。

(3) 声明和初始化数组

数组声明
在 C++ 中要声明一个数组,需要指定元素的类型type、数组的名称arrayName和数组的长度length(也叫元素的个数),如下所示:

type arrayName[length];

例如,要声明一个元素类型为int,个数是5的数组ArrayNums

int ArrayNums[5];

数组初始化
在声明数组时,还能对数组初始化。将ArrayNums里的5个元素分别初始化一个值。

int ArrayNums[5]={8, 16, 32, 64, 128};

当然,也可以只对前面几个元素进行初始化,如下所示:

int ArrayNums[5]={8, 16}; //初始化前两个数

注:这里所声明的数组都是静态数组,即它们的长度都是固定的。

(4) 访问数组中的数据

访问数组中的元素,要使用从0开始的索引。比如存储在数组ArrayNums中的一个元素是ArrayNums[0],第二个元素是ArrayNums[1],依次类推。
访问数组时,不能超越其边界,否则结果是无法预料的。在很多情况下,这将导致程序崩溃。比如你可以在只包含5个元素的数组中取回索引为10的元素,但这样会给程序带来安全和稳定性方面的风险。
下面举一个简单的例子,声明并初始化一个int数组,并将其元素显示在屏幕上。

#include<iostream>
using namespace std;

int main() 
{
	int ArrayNums[5]={8, 16, 32, 64, 128};
	for(int i=0;i<5;i++)
		cout<<ArrayNums[i]<<endl; //逐一输出每一个元素 
	return 0;
} 

运行结果:
在这里插入图片描述
除此之外,我们还可以修改数组中的数据。比如我们已经声明并初始化了一个数组ArrayNums,现在想修改数组中的第三个元素,可按如下方式进行赋值:

ArrayNums[2]=10; //将ArrayNums数组中第三个元素改为10

2. 多维数组

大于或等于2维的数组都称为多维数组,我们这里以最常见的二维数组进行讲解。

(1) 声明和初始化

多维数组声明
在C++中,要声明多维数组,可指定每维包含的元素数。比如,一个书架有2排,每排可以存放5本书,那么就可以按如下声明这个书架(二维数组):

int Bookshelf[2][5];

多维数组初始化
如果想给每本书指定(初始化)一个名称,假设这10本书的名称分别为0~9,则可按如下方式进行初始化:

int Bookshelf[2][5]={{0, 1, 2, 3, 4}, {5, 6, 7, 8, 9}};

同样,你也可以按如下方式进行初始化:

int Bookshelf[2][5]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

然而,第一种初始化方式更好,因为它能让你更容易看出数组的结构。

(2) 访问多维数组的元素

和一维数组一样,访问数组中的元素,要使用从0开始的索引。比如书架第1排上的第2本书是Bookshelf[0][1],第2排上的第5本书就是Bookshelf[1][4]。
下面演示一个简单的例子,在屏幕上显示出书架上每一本书的名称:

#include<iostream>
using namespace std;

int main() 
{
	int Bookshelf[2][5]={{0, 1, 2, 3, 4}, {5, 6, 7, 8, 9}};
	for(int i=0;i<2;i++)
	{
		for(int j=0;j<5;j++)
			cout<<Bookshelf[i][j]<<" "; //逐一输出每一个元素 
		cout<<endl;
	}
	return 0;
} 

运行结果:
在这里插入图片描述

3. 动态数组

在前面我们声明的一维数组和二维数组都属于静态数组。静态数组的特点是,在数组声明时就确定了数组元素的个数,且在后期不能再改变。

但是在实际问题中,可能无法在一开始就能确定数组的长度。比如,要在应用程序中存储图书馆中的图书信息,你无法知道需要处理图书的上限数。就小图书馆来说,为稳妥起见,你可以对上限做合理的假设。但是在这种情况下,将预留大量的内存,从而降低了系统的性能。

为了减少占用的内存,可不使用前面介绍的静态数组,而使用动态数组,并在运行阶段根据需要调整数组大小。C++提供了std::vector类,这是一种方便且易于使用的动态数组。
想更深入了解vector类的用法和各种骚操作,可以戳戳这里:动态数组类:vector

注:对类等概念还不太了解的同学,此小节可先暂时不掌握;待后面我讲完类,可再来学习。

4. C风格字符串

(1) C风格字符串中的风险

C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持,是一种特殊的字符数组。字符串实际上是使用空字符 ‘\0’ 终止的一维字符数组。

下面我们采用C风格字符串,创建了一个 “Hello World” 。

char SayHello[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0'};

请注意,该数组的最后一个字符为空字符‘\0’。这也被称为字符串结束字符,因为它告诉编译器字符串到此结束。这种C风格字符串是特殊的字符数组,因为总是在最后一个字符后加上空字符‘\0’。
当在初始化字符数组时忘记添加‘\0’,打印该数组时,Hello World后面会出现垃圾字符。如下所示:

#include<iostream>
using namespace std;

int main() 
{
	char SayHello[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0'};
	cout<<"加空字符输出:"<<SayHello<<endl;
	char SayHello1[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};
	cout<<"不加空字符输出:"<<SayHello1<<endl;
	char SayHello2[] = "Hello World"; 
	cout<<"字符串形式输出:"<<SayHello2;
	return 0;
} 

运行结果如下:

在这里插入图片描述
分析:
第一行,末尾加了空字符’\0’的字符数组,输出情况正常。
第二行,末尾没加‘\0’的字符数组,输出情况异常,如图中红色框所示,出现了垃圾字符。
第三行,使用字符串常量的形式,可以省去末尾的’\0’,输出仍然正常。这是因为C++ 编译器会在初始化数组时,自动把 ‘\0’ 放在字符串的末尾。



对比可知,使用C风格字符串——一维字符数组,要特别注意空字符‘\0’的使用;否则在有些情况下,可能会引起程序崩溃,影响系统的稳定性。而使用C++中的字符串类string可以避免这些问题。

(2) C风格的字符串函数

C++中的cstring类中提供了很多实用的字符串函数,如下表所示:
在这里插入图片描述
在使用这些函数时,程序前面需要加上头文件:

#include <cstring>

下面举个简单的例子,使用上述的一些函数:

#include<iostream>
#include<cstring>
using namespace std;

int main() 
{
	char str1[] = {'H','e','l','l','o',' ','\0'};
	char str2[] = {'C','p','p','\0'};
	strcat(str1,str2);
	cout<<"连接:"<<str1<<endl;
	cout<<"连接后的长度:"<<strlen(str1)<<endl;
	return 0;	
} 

运行结果:
在这里插入图片描述
注意:这些C风格字符串作为输入的函数非常危险,因为它们会寻找终止空字符‘\0’,如果程序员没有在字符数组末尾添加空字符,这些函数将跨越字符数组边界。

5. C++中的String类

为了避免以上的问题,C++提供了string类,这是一种功能强大而安全的字符串操作方式。无论是处理文本输入,还是执行拼接等字符串操作,使用这些C++标准字符串都是效率最高的方式。

详细了解String类的用法和各种骚操作,可以看我之前写的两篇博文,这里不再赘述。
第一篇:C++:string类的基本用法(一)
第二篇:C++:常用的string类字符串函数(二)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!