黑马程序员C++2024新版笔记 第三章 数组

发布于:2025-05-20 ⋅ 阅读:(21) ⋅ 点赞:(0)

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.数组特点

  1. 任意类型(基本数据类型int、double、char、string等;复合数据类型结构体、联合体等;指针类型int*,char*等;枚举类型enum)都可以构建数组。
  2. 数组一旦定义大小就固定了,且无边界检查(越界不会报错,但是运行时可能出现问题)
  3. 数组的内存空间连续分配,而且是有序的,每个元素分配大小取决于存放类型,因此数组中元素类型是一致的,且可以通过sizepf(数组)/sizeof(数组某元素)计算数组元素个数。
  4. 数组的元素值是可以修改的。通过下标访问元素即可实现对存储值修改,但是不可更改类型。
  5. 数组变量不记录数据,而是记录了第一个元素的内存地址,该地址可供访问其中的元素。

代码演示练习:

#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 = &num;
    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 &num;就会报错。基本语法:

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;

}


网站公告

今日签到

点亮在社区的每一天
去签到