1.数组定义
数组是一批相同类型的元素(element)的集合组成的数据结构。
声明语法:
<数据类型> <数组名> [<数组长度>]
int v[6] // 声明了可以存放6个int数字的数组
数组的每个元素有编号,称之为下标索引,从0开始。通过数组名[下标索引]访问数组内元素(存、取)。
#include <iostream>
using namespace std;
int main() {
// 11,22,33,44,55放入数组中
int v[5];
// 用下标索引访问每一个元素,从0开始
v[0] = 11;
v[1] = 22;
v[2] = 33;
v[3] = 44;
v[4] = 55;
cout << "数组的第1个元素是:" << v[0] << endl;
cout << "数组的第2个元素是:" << v[1] << endl;
cout << "数组的第3个元素是:" << v[2] << endl;
cout << "数组的第4个元素是:" << v[3] << endl;
cout << "数组的第5个元素是:" << v[4] << endl;
// 数组的声明和赋值同步完成的写法
// 数组类型 数组名[] = {元素1, 元素2, 元素3, ..., 元素n};
int v2[] = {11, 22, 33, 44, 55}; // 后面的元素可以推断出数组长度,因此数组大小可以不写
cout << "数组的第1个元素是:" << v[0] << endl;
cout << "数组的第2个元素是:" << v[1] << endl;
cout << "数组的第3个元素是:" << v[2] << endl;
cout << "数组的第4个元素是:" << v[3] << endl;
cout << "数组的第5个元素是:" << v[4] << endl;
return 0;
}
2.数组定义练习题讲解
#include <iostream>
#include <random>
using namespace std;
// 随机数生成器函数
int get_random_num(int min, int max) {
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> distrib(min, max);
return distrib(gen);
}
int main() {
// 1.获得随机数
int num = get_random_num(1, 10);
// 2.需要用户输入10次数字,将内容存入数组中
int arr[10]; // 定义数组
for (int i = 0; i < 10; i++) {
cout << "请输入第" << i + 1 << "个数字:";
cin >> arr[i];
}
// 3.判断每个元素是否和随机数相等
int result = 0;
for (int i = 0; i < 10; i++) {
if (arr[i] == num) {
result += 1;
}
}
cout << "用户猜正确" << result << "次" << endl;
return 0;
}
3.数组特点
- 任意类型(基本数据类型int、double、char、string等;复合数据类型结构体、联合体等;指针类型int*,char*等;枚举类型enum)都可以构建数组。
- 数组一旦定义大小就固定了,且无边界检查(越界不会报错,但是运行时可能出现问题)
- 数组的内存空间连续分配,而且是有序的,每个元素分配大小取决于存放类型,因此数组中元素类型是一致的,且可以通过sizepf(数组)/sizeof(数组某元素)计算数组元素个数。
- 数组的元素值是可以修改的。通过下标访问元素即可实现对存储值修改,但是不可更改类型。
- 数组变量不记录数据,而是记录了第一个元素的内存地址,该地址可供访问其中的元素。
代码演示练习:
#include <iostream>
#include <random>
using namespace std;
// 随机数生成器函数
int get_random_num(int min, int max) {
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> distrib(min, max);
return distrib(gen);
}
int main() {
// 特点1: 任意类型均可构建数组
cout << "特点1: 任意类型均可构建数组---" << endl;
float v1[] = {1.1, 2.2, 3.5, 4.4, 5.5};
double v2[] = {1.1, 2.2, 3.5, 4.4, 5.5};
char v3[] = {'a', 'b', 1, 2, 3};
string v4[] = {"林志铭", "蔡依信", "刘亦飞"};
bool v5[] = {true, 0, 1, true, false};
enum Color { RED, GREEN, BLUE };
Color v6[] = {RED, GREEN, BLUE, GREEN, BLUE};
cout << "float数组的第一个元素: " << v1[0] << endl;
cout << "double数组的第一个元素: " << v2[0] << endl;
cout << "char数组的第一个元素: " << v3[0] << endl;
cout << "string数组的第一个元素: " << v4[0] << endl;
cout << "bool数组的第一个元素: " << v5[0] << endl;
cout << "枚举数组的第一个元素: " << v6[0] << endl;
cout << endl;
// 特点2:固定大小,没有边界检查
cout << "特点2: 固定大小(无边界检查)" << endl;
int v7[] = {1, 2, 3, 4, 5};
cout << "访问越界的10号下标: " << v7[10] << endl;
cout << endl;
// 特点3:内存连续且有序,可通过 sizeof(数组)/sizeof(数组元素) 得到数组长度
cout << "特点3:内存连续且有序---" << endl;
cout << "v7数组的第一个元素是" << v7[0] << endl;
cout << "v7数组的第一个元素是" << v7[0] << endl;
cout << "v7数组的第一个元素是" << v7[0] << endl;
cout << "v7数组的第一个元素是" << v7[0] << endl;
cout << "v7数组的长度是" << sizeof(v7) << "字节" << endl;
// 特点4: 元素值可以修改
cout << "特点4: 元素值可以修改---" << endl;
int v8[] = {1, 2, 3, 4, 5};
v8[1] = 66; // 修改下标1的元素值
v8[0] = 11; //
cout << "经过修改,v8的下标1元素值是:" << v8[1] << endl;
cout << "经过修改,v8的下标6元素值是:" << v8[0] << endl;
cout << endl;
// 特点5:数组变量本身不记录数据
cout << "特点5: 数组变量本身不记录数据---" << endl;
int v9[] = {1, 2, 3, 4, 5};
cout << "直接cout v9这个变量:" << v9 << endl;
// v9变量本身记录的是内存地址,这个地址是v9数组首元素的地址
cout << endl;
return 0;
}
4.数组遍历(高级for循环语法)
while循环写法:
高级for循环写法:
#include <iostream>
#include <random>
using namespace std;
// 随机数生成器函数
int get_random_num(int min, int max) {
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> distrib(min, max);
return distrib(gen);
}
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// while
int i = 0;
while (i < sizeof(arr)/sizeof(arr[0])) {
cout << "while循环取出内容: " << arr[i] << endl;
i++;
}
// for
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) {
cout << "for循环取出内容: " << arr[i] << endl;
}
// for的高级写法
for (int element: arr) {
cout << "高级for循环取出内容: " << element << endl;
}
return 0;
}
5.字符数组
以上字符数组在使用sizeof统计长度时会额外添加一个空字符,也就是6。
#include <iostream>
using namespace std;
int main() {
"hello"; // 底层是字符数组
char s[] = "hello"; //底层也是字符数组
cout << s[0] << endl;
cout << s[1] << endl;
cout << s[2] << endl;
cout << s[3] << endl;
cout << s[4] << endl;
cout << s[5] << endl;
cout << sizeof(s) << endl;
for (char i:s) {
cout << i;
}
}
6.多维数组
写多维数组时,无论使用上述哪种语法,必须在[]内提供长度,如int v[3][2]。
#include <iostream>
using namespace std;
int main() {
int v1[2][2];
v1[0][0] = 11;
v1[0][1] = 22;
v1[1][0] = 33;
v1[1][1] = 44;
int v2[2][2] = {1, 2, 3, 4};
int v3[2][2] = {{1, 2},{3, 4}};
cout << "v1数组的第二个元素内第一个元素是:" << v1[1][0] << endl;
cout << "v2数组的第二个元素内第一个元素是:" << v2[1][0] << endl;
cout << "v3数组的第二个元素内第一个元素是:" << v3[1][0] << endl;
// 三维数组
int V3[2][2][2];
V3[0][0][0] = 1;
V3[0][0][1] = 2;
V3[0][1][0] = 3;
V3[0][1][1] = 4;
V3[1][0][0] = 5;
V3[1][0][1] = 6;
V3[1][1][0] = 7;
V3[1][1][1] = 8;
cout << "三维数组V3的第二个元素内的第二个元素内的第一个元素是:" << V3[1][1][0] << endl;
int v4[2][2][2] = {
{{1,2},
{3,4}
},
{{5,6},
{7,8}
}
};
cout << "三维数组V4的第二个元素内的第二个元素内的第一个元素是:" << v4[1][1][0] << endl;
}
7.多维数组的遍历
#include <iostream>
using namespace std;
int main() {
// 二维数组遍历
int v1[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
for (int i = 0; i < sizeof(v1) / sizeof(v1[0]); i++) {
// v1[0] -> {1,2, 3};
// v1[1] -> {4,5,6};
for (int j = 0; j < sizeof(v1[1]) / sizeof(v1[1][0]); j++) {
cout << v1[i][j] << '\t';
}
}
cout << endl;
// 三维数组遍历
int v2[2][3][4] = {
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
},
{
{13, 14, 15, 16},
{17, 18, 19, 20},
{21, 22, 23, 24}
}
};
for (int i = 0; i < sizeof(v2) / sizeof(v2[0]); i++) {
for (int j = 0; j < sizeof(v2[0]) / sizeof(v2[0][0]); j++) {
for (int k = 0; k < sizeof(v2[0][0]) / sizeof(v2[0][0][0]); k++)
cout << v2[i][j][k] << '\t';
}
}
}
8.多维数组的遍历练习题讲解
#include <iostream>
#include <random>
using namespace std;
// 随机数生成器函数
int get_random_num(int min, int max) {
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> distrib(min, max);
return distrib(gen);
}
int main() {
string names[] = {
"Emma", "Liam", "Olivia", "Noah", "Ava",
"William", "Isabella", "James", "Sophia", "Benjamin",
"Mia", "Elijah", "Charlotte", "Lucas", "Amelia",
"Mason", "Harper", "Logan", "Evelyn", "Alexander",
"Abigail", "Ethan", "Emily", "Jacob", "Elizabeth",
"Michael", "Avery", "Daniel", "Sofia", "Matthew",
"Ella", "Jackson", "Madison", "David", "Scarlett",
"Joseph", "Victoria", "Carter", "Aria", "Owen",
"Grace", "Wyatt", "Chloe", "John", "Camila",
"Jack", "Penelope", "Luke", "Luna", "Henry"
};
string arr[2][2][5];
// 2x2x5三维数组
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 5; k++) {
string major = i == 0 ? "物理" : "计算机";
string class_name = j == 0 ? "一班" : "二班";
int set_number = k + 1;
string name = names[get_random_num(0,49)];
string msg = major + " " + class_name + " " + to_string(set_number) + " " + name;
arr[i][j][k] = msg;
}
}
}
cout << "信息准备完成,现在输出:" << endl;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 5; k++) {
cout << arr[i][j][k] << endl;
}
}
}
}
9.指针基础
修改指针的值,等于修改指针指向的地址的变量。
10.野指针和空指针
无论指针指向的变量类型是什么,指针本身被分配的内存大小为8个字节的空间(系统为64位时,在32位系统是4个字节)
11.指针运算
#include <iostream>
using namespace std;
int main() {
int num = 10;
int * p = #
cout << "指针变量p中记录的地址是" << p << endl;
p ++;
cout << "指针变量p中记录的增加1后的地址是" << p << endl;
double num2 = 10.0;
double * p2 = &num2;
cout << "指针变量p2中记录的地址是" << p2 << endl;
p2 +=4;
cout << "指针变量p2中记录的增加1后的地址是" << p2 << endl;
// 指针运算用于对数组进行操作
int v[] = {1,2,3,4,5,6,7,8,9,10};
int *vp = v; // 指针中记录了数组0下标的地址
cout << "数组对象v的第一个元素是" << *vp << endl;
cout << "数组v[0]元素是" << v[0] << endl;
cout << "数组的第二个元素是" << *(vp+1) << endl;
cout << "数组的第二个元素是" << v[1] << endl;
return 0;
}
12.动态内存管理
定义:程序员手动进行内存的分配和释放等内存管理操作。
虽然之前的学习中没有手动管理内存也能正常运行代码,但是下面的例子可以说明手动内存管理的必要性,也就是避免长期不使用的变量占用内存空间:
自动/静态内存分配:无垃圾回收机制,变量、数组等对象的创建都属于静态内存分配,需要程序员手动管理内存,即手动分配,用完清理。
new运算符
用于申请并分配内存空间,并提供指向该空间的指针(内存地址)。基本语法:
new type 申请普通变量空间
new type[n] 申请数组空间
delete运算符
用于释放内存,仅可用于new运算符申请的内存区域,例如delete #就会报错。基本语法:
delete 指针 删除普通变量空间
delete[] 指针 删除数组空间
代码示例:
#include <iostream>
using namespace std;
int main() {
int *p = new int;
*p = 10;
cout << "new申请的四字节空间内存放的是: " << *p << endl;
delete p; // 良好的代码习惯:使用new分配内存后写好delete释放
int *q = new int[2]; // 申请数组空间
q[0] = 10; // 等同于 *(q+0) = 10;
*(q+1) = 20; // 等同于 q[1] = 20;
cout << "数组的第一个元素是" << q[0] << endl;
cout << "数组的第二个元素是" << q[1] << endl;
delete[] q;
return 0;
}
13.数组元素的移除
C++内置并未提供对数组元素进行增删改查的操作,需要手动实现。(vector容器提供了,后续会学习)。
示例:
代码:
#include <iostream>
using namespace std;
int main() {
// 示例数组
int * pArr = new int[5] {1, 2, 3, 4, 5};
// 创建一个新的数组,将需要保留的元素复制到新的数组中
int *pNewAr = new int[4];
// 遍历数组,将需要保留的元素复制到新的数组中,不要的要跳过
for (int i = 0; i < 5; i++) {
if (i == 2) {
continue;
}
else if (i>2){
pNewAr[i-1]=pArr[i];
}
else {
pNewAr[i] = pArr[i];
}
}
// 可选
delete [] pArr;
// 可选
pArr = pNewAr; // 将老数组的指针指向新数组
cout << "新数组的元素是" << endl;
for (int i = 0; i < 4; i++) {
cout << pNewAr[i] << '\t';
}
return 0;
}