C++中的数组

一.数组

1.数组的概念:

是由一批相同类型的元素的集合所组成的数据结构

2.数组的定义语法:

数据类型 数组名[数组长度];

其中数据类型表示数组这个容器内要放什么样的数据,数组名就是容器的名字,数组长度就是代表容器的大小

3.下标索引的概念:

数组内的每个“格子”都有自己的编号,也就是下标索引(注意下标索引是从0开始的,也就是说第一个数据的索引是0)

所以我们可以通过数组名[下标索引]的方式来访问我们想要的位置上的数据

二.数组的特点

1.任意类型都可以构建数组,包括下方的各种数据类型

①:基本数据类型如:int, float, double, char, string, bool

②:复合数据类型如:结构体,联合体

③:指针类型如:int*, char*, float*

④:枚举类型如:enum

2.固定大小

C++中的数组一旦完成了定义,那么它的大小就已经固定了,无法进行修改

3.内存连续并且有序

数组内存的空间是连续分配的,并且每个元素分配的大小取决于存放类型

因此我们可以通过sizeof(数组) / sizeof(数组中的某个元素)获得数组的元素个数

4.元素值可修改

我们可以通过数组名[下标索引]对锁定的元素进行赋值,对该处位置的存储值进行修改

5.数组变量不记录数据

数组变量本身并不记录元素,而是记录从第一个元素开始的内存地址,然后通过记录的内存地址依次获取之后的元素(因为数组的内存是连续并且有序的)

三.数组的遍历:

对数组进行遍历是以后我们经常会用到的功能,不管使用for循环还是使用while循环都能实现我们想要的效果,但是具体到时候使用什么循环还是要具体的情况,我在这里仅仅只是简单举例

1.for循环遍历

#include"iostream" 
using namespace std;

int main() {
	int ans[] = {1, 2, 3, 4, 5};
	for (int i = 0; i < sizeof(ans) / sizeof(ans[0]); i++) {
		cout << ans[i] << endl;
	}
}

2.while循环遍历:

#include"iostream" 
using namespace std;

int main() {
	int ans[] = {1, 2, 3, 4, 5};
	int len = sizeof(ans) / sizeof(ans[0]);
	int i = 0;
	while (i < len) {
		cout << ans[i] << endl;
		i++;
	}
}

3.for循环的高级写法

原理:

通过临时变量在每一次循环体中记录数组的每一个元素,数组有几个元素循环体就执行几次

程序中的演示:

#include"iostream" 
using namespace std;

int main() {
	for (元素类型 临时变量名 : 数组变量) {
		代码; 
	} 
}

举例:

#include"iostream" 
using namespace std;

int main() {
	int ans[] = {1, 2, 3, 4, 5};
	for (int i : ans) {
		cout << i << endl;
	}
}

注意:这种方式在版本较低的情况下用不了

四.字符数组

C++中定义字符串可以有以下三种方式:

"String"; 
char str[] = "String";
char * str = "String";

其中第一种方式和第二种方式定义的字符串的本质都是字符数组,它们的存储机制为:将每一个字符都作为一个元素存入字符数组中,然后在字符数组中的最后一个元素之后添加一个"\0"(空字符)作为结束标记

五.多维数组

1.概念:

对数组进行嵌套,也就是说数组内的每个元素都是数组,根据嵌套的层次可以有二维,三维,四维,乃至更多维度的数组

2.定义语法:

数据类型 数组名[一维][二维]...[n维];
// 如我们定义一个二维int型数组:
int sum[5][5];

3.多维数组的遍历:

我们可以通过for和while循环对多维数组进行遍历,其中我们需要注意的基本原则是:

①:有着几维我们就至少写上多少层嵌套循环

②:每一层循环都对应一个维度

③:一般使用for循环更加方便

④:遍历的举例:

#include"iostream" 
using namespace std;

int main() {
	int nums[3][3];
	int num = 1;
	for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {
		for (int j = 0; j < sizeof(nums[0]) / sizeof(nums[0][0]); j++) {
			nums[i][j] = num;
			num++;
			cout << nums[i][j];
		}
		cout << endl;
	}
}

六.指针

1.指针在C++中的重要作用:

指针是C++中至关重要的组成部分,它具有强大的功能,本质是协助程序员完成内存的直接操纵

2.指针的概念:

特定数据类型在内存中的存储地址,也就是内存地址(注意指针只是一个逻辑概念,实际的应用其实应该是指针变量)

3.指针变量的定义语法:

①:

数据类型* 指针名; // 声明
指针名 = &指向的地址; // 赋值

②:

变量类型* 指针名 = 指向的地址; // 定义与赋值一同进行

注意:

①:*的含义:

在声明时:*指针名表示的是变量,这是一个指针变量,其中存的是内存地址

int* p; // 声明了一个指针变量,其变量名为p

在使用时:*指针名表示取出指针所指向的内存区域的数据

#include"iostream" 
using namespace std;

int main() {
	int num = 10;
	int* p = &num;
	int ans = *p; // 取出了p指针变量所存储的地址中的值 
	cout << ans << endl;
}

②:&符号表示取变量的内存地址,是一个取内存地址的单目操作符

4.野指针和空指针

①:野指针:

被声明但是没有进行初始化(赋值)的指针,这个指针会指向随机的内存空间,可能会导致未知的问题

为了避免野指针,我们应该养成及时初始化的习惯,或者将指针置为空指针

// 置为空指针的方法:
int* p = NULL; // NULL是C++中内置的宏,表示空,本质是0
int* p = nullptr; // nullptr是C++11标准引入的关键字,表示指针为空

②:空指针表示不指向任何地方,那么也就不会再出现安全问题

空指针只在需要指针,但是需要延迟赋值的场景下作为过渡进行使用

我们在使用指针时一定要注意进行初始化,养成好习惯!

5.指针运算:

尽管指针变量内存储的是内存地址,但是仍然可以进行基础的数学计算,指针运算是对指针的基础型操作,非常适合操纵数组并配合做动态内存分配

①.指针加减运算:

指针进行加减运算的结果和指针指向内存区域的数据类型相关,以加法为例:

char类型的指针+1表示地址+1(单位为字节)

int类型的指针+1表示地址+4(单位仍为字节)

double类型的指针+1表示地址+8

...

就从上方的几个例子就可以看出,指针的加减法(加减n)就是内存地址加减n * 该类型所占的字节量 

②.使用指针和循环对数组进行遍历:

#include"iostream" 
using namespace std;

int main() {
	int nums[5] = {1, 2, 3, 4, 5};
	int* p = nums;
	for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {
		cout << *(p + i) << endl;
	}
}

七.动态内存分配

1.概念:

由程序员手动进行的内存空间的分配,内存空间的释放等内存管理操作

2.静态内存分配:

在C++代码中,变量、数组等对象的创建是由C++自动分配内存的,称之为静态内存分配,而静态内存管理是不会进行内存空间的自动清理的(不会进行垃圾回收),因此我们需要手动地进行内存管理(手动分配,用完清理)

3.动态内存分配的方法:

①:new:

new运算符用于申请并且分配内存空间,并且提供指向该空间的指针

基本语法:

new type; // 申请普通变量空间
new type[n]; // 申请数组空间

②:delete:

delete运算符用于释放内存(仅可用于new运算符申请的内存区域)

基本语法:

delete 指针名; // 删除普通变量空间
delete[] 指针名;  // 删除数组空间

③:一次连贯的内存分配:

八.数组元素的移除

在C++中的内置中并未提供对数组元素进行增加(插入)、移除的功能,这些功能需要手动进行实现(vector容器提供)

1.移除元素的思路:

①:通过new操作符申请新数组的内存空间,并且复制数据到新数组

②:通过delete删除旧数组的空间占用

③:将旧数组的指针指向新数组的地址

2.移除元素实例:

#include"iostream" 
using namespace std;

int main() {
	int *pOld = new int[5] {1, 2, 3, 4, 5};
	int *pNew = new int[4];
	for (int i = 0; i < 5; i++) {
		if (i == 3)
			continue;
		if (i > 3)
			pNew[i - 1] = pOld[i];
		else 
			pNew[i] = pOld[i];
	}
	for (int i = 0; i < 4; i++) {
		cout << *(pNew + i) << endl;
	}
}

九.数组元素的插入

1.插入数组元素的思路:

①:创建新数组,将老数组元素和新插入元素一起复制到新数组当中

②:新元素在指定位置进行插入(意味着老数组元素要配合做下标增加)

③:插入数组元素案例:

#include"iostream" 
using namespace std;

int main() {
	int *pOld = new int[5] {1, 2, 3, 4, 5};
	int *pNew = new int[7];
	int reset = 0;
	for (int i = 0; i < 7; i++) {
		if (i == 1) {
			pNew[i] = 1;
			reset++;
			continue;
		} else if (i == 3) {
			pNew[i] = 3;
			reset++;
			continue;
		}
		pNew[i] = pOld[i - reset];
	}
	for (int i = 0; i < 7; i++) {
		cout << *(pNew + i) << endl;
	}
}

十.指针悬挂

1.概念:

指针指向的区域已经被回收,这种问题被称为指针悬挂

2.注意:

①:不要轻易地进行指针之间的相互赋值

②:delete回收空间之前,要确保此空间一定不会再被使用

十一.const指针

const是C++的关键字,被译为常量,const指针表示常量指针

1.指向const的指针:

表示指向区域的数据是不变的,但可以更换指向

语法:

const 数据类型 *指针名;
数据类型 const *指针名;

也就是说,可以改变当前指针所指向的地址,但是不能更改当前指针指向地址中的数据

2.const指针:

表示指针本身不可更改,但指向的数据可以更改

语法:

数据类型 * const 指针名 = 地址; // 这里必须进行初始化,因为之后指针的地址不可修改

也就是说,const指针当前所指向的地址是不可改变的,但是其中的数据可以进行更改

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值