【C++学习笔记】数组与指针(三)

目录

一、数组

1.1 数组声明与赋值

1.2 数组的特点

特点1:任意类型均可创建数组

特点2:固定大小

特点3:内存连续且有序

特点4:C++无数组下标越界错误

特点5:数组变量不记录数据

1.3 遍历数组

普通for循环

foreach增强循环

1.4 字符数组

1.5 多维数组

二维数组

三维数组

遍历

二维数组

三维数组

1.6 指针

指针基础

野指针与空指针

指针运算

动态内存管理

指针悬挂

常量指针

1.7 数组元素的移除

1.8 数组元素的插入


一、数组

数组:是由一批相同类型的元素(element)的集合所组成的数据结构,分配一块连续的内存来存储。

下标索引:从0开始。

#include "iostream"
using namespace std;

int main(){

    int array[5]; // 得到了一个可以存放5个元素的整型数组
    array[0] = 11; // 往数组里存值
    array[1] = 22;
    array[2] = 33;
    array[3] = 44;
    array[4] = 55;

    cout << array[0] << endl; // 从数组里取值
    cout << array[1] << endl;
    cout << array[2] << endl;
    cout << array[3] << endl;
    cout << array[4] << endl;

    return 0;
}

1.1 数组声明与赋值

int array[] = {11, 22, 33, 44, 55};

1.2 数组的特点

特点1:任意类型均可创建数组

  • 基本数据类型:int、float、double、char、string、bool等
  • 复合数据类型:结构体、联合体等
  • 指针类型:int*、char*、float*等
  • 枚举类型:enum

均可形成数组。
 

特点2:固定大小

C++数组,一旦定义完成,其大小(长度)即固定。

int array[5];
int array[] = {11, 22, 33, 44, 55};

如上代码,无论哪种方式定义,数组v的大小固定为5。

特点3:内存连续且有序

如下数组定义:

int v[] = {1, 2, 3, 4, 5};

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

  • char 1字节
  • int 4字节
  • double 8字节等

  • 无论何时访问数组元素,均一致(手动修改值除外),如v[0],取出的都是数值1
  • 也是基于此确保数组元素类型一致,比如int数组每个元素4字节的空间,无法存储double数值
  • 通过 sizeof(数组)/sizeof(数组某元素) 可以得到数组元素个数

特点4:C++无数组下标越界错误

#include "iostream"
using namespace std;

int main(){

    int array[] = {11, 22, 33, 44, 55};

    cout << array[100] << endl; // 从数组里取值

    return 0;
}

特点5:数组变量不记录数据

如下数组定义:

int v[] = {1, 2, 3, 4, 5};

数组变量v本身:

  • 并非记录了数组内全部元素(即:不存数据)
  • 而是记录了v[0]元素的内存地址

数组元素访问规律如下:

  • 通过数组变量(如v)记录下标0元素内存位置,即可找到v[0]
  • 通过v[0]地址 + 单个元素空间大小(如int数组,4字节),即可找到v[1]
  • 通过v[1]地址 + 4字节,即可找到v[2]
  • ……
  • 以此类推

1.3 遍历数组

普通for循环

#include "iostream"
using namespace std;

int main(){

    int array[] = {11, 22, 33, 44, 55};

    for (int i = 0; i < sizeof (array)/sizeof (array[0]); ++i) {
        cout << array[i] << endl;
    }

    return 0;
}

foreach增强循环

#include "iostream"
using namespace std;

int main(){

    int array[] = {11, 22, 33, 44, 55};

    for (int element : array) {
        cout << element << endl;
    }

    return 0;
}

1.4 字符数组

"hello";   // 方式一

char s[] = "hello";   // 方式二

char * s = "hello";   // 方式三

上述代码,方式一(字面常量)和 方式二定义的字符串,其本质都是:字符数组。

即:

"hello";

char s[] = "hello";

均可以表现为:

char s[] = {'h', 'e', 'l', 'l', 'o', '\0'};

注意:在字符数组中,额外在最后添加一个元素\0(空字符),作为结束标记。

#include "iostream"
using namespace std;

int main(){

    char s[] = "hello";
    for (char c : s) {
        cout << c << endl;
    }

    return 0;
}

1.5 多维数组

二维数组

#include "iostream"
using namespace std;

int main(){

    int v1[2][2]; // 声明二维数组
    v1[0][0] = 1;
    v1[0][1] = 2;
    v1[1][0] = 3;
    v1[1][1] = 4;

    cout << v1[0][0] << endl;

    int v2[2][2] = {{1,2},{3,4}}; // 二维数组
    cout << v2[1][0] << endl;

    return 0;
}

三维数组

#include "iostream"
using namespace std;

int main(){
    
    // 三维数组
    int v3[2][2][2] = {{{1,2},{3,4}},{{5,6},{7,8}}};
    cout << v3[0][0][0] << endl; // 1

    
    return 0;
}

遍历

二维数组
#include "iostream"
using namespace std;

int main(){
    
    int v[2][3] = {{1, 2, 3}, {4, 5, 6}};
    // 遍历二维数组v,使用sizeof
    for(int i = 0; i < sizeof(v)/sizeof(v[0]); i++){
        for(int j = 0; j < sizeof(v[i])/sizeof(v[i][0]); j++){
            cout << v[i][j] << " ";
        }
        cout << endl;
    }

    return 0;
}

三维数组
#include "iostream"
using namespace std;

int main(){

    int array[2][2][2] = {{{1,2},{3,4}},{{5,6},{7,8}}};
    for (int i = 0; i < sizeof(array)/sizeof(array[0]); i++) {
        for (int j = 0; j < sizeof(array[i])/sizeof(array[i][0]); j++) {
            for (int z = 0; z < sizeof(array[i][j])/sizeof(array[i][j][0]); z++) {
                cout << array[i][j][z] << " ";
            }
            cout << endl;
        }
        cout << endl;
    }

    return 0;
}

1.6 指针

指针基础

指针:特定类型数据在内存中的存储地址,即内存地址

#include "iostream"
using namespace std;

int main(){

    int num = 10;
    int *p = &num;

    cout << p << endl;  // 0xd151fffcd4
    cout << *p << endl;  // 10

    return 0;
}

野指针与空指针

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

指针运算

尽管指针变量内记录的是内存地址,但仍可以进行基础的数学计算。

指针运算是对指针的基础型操作,非常适合操纵数组并配合做动态内存分配。

#include "iostream"
using namespace std;

int main(){
    
    // 初始化一个整数数组
    int array[] = {1,2,3,4,5};
    // 获取数组中索引为2的元素的地址赋值给指针p
    int *p = &array[2];
    
    // 通过指针p加上偏移量2来访问数组中索引为4的元素
    cout << *(p + 2) << endl; // 5

    return 0;
}

动态内存管理

动态内存分配:即由程序员手动的进行内存空间的分配、内存空间的释放等内存管理操作。

C++代码中,变量、数组等对象的创建,是由C++自动分配内存的,称之为(自动)静态内存分配。

(自动)静态内存管理,是不会进行内存空间的自动清理的。(无垃圾回收机制)
我们需要手动的管理内存,即手动分配,用完清理。

#include "iostream"
using namespace std;

int main(){
    
    // 动态分配一个整数类型的内存空间(4字节)
    int *p = new int;
    // 在分配的内存空间中存储值10
    *p = 10;
    // 输出内存空间中存储的值,目的是展示new申请的内存空间的使用情况
    cout << "new申请的4字节空间内,存放的是:" << *p << endl;
    // 释放之前分配的内存空间,以避免内存泄漏
    delete p;

    return 0;
}

指针悬挂

所以,总结出两点经验:

  • 不要轻易进行指针之间相互赋值
  • delete回收空间前,确保此空间100%不再被使用
#include "iostream"
using namespace std;

int main(){

    int * p1 = new int;
    *p1 = 10;

    int * p2 = p1; // 指针之间相互赋值

    cout << "p1指针指向的内存区域的值是:" << *p1 << endl;
    delete p1;
    cout << "p2指针指向的内存区域的值是:" << *p2 << endl;

    return 0;
}

常量指针

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

1.7 数组元素的移除

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

#include "iostream"
using namespace std;

int main(){

    int * pArr = new int[5] {1, 2, 3, 4, 5};
    // 创建一个新的数组,将需要保留的复制到新数组中
    int * pNewArr = new int[4];

    // 循环去遍历老的数组,将需要保留的元素复制到新数组中
    for(int i = 0; i < 5; i++){
        if (i == 2) {
            continue;
        }

        if (i > 2) {
            pNewArr[i - 1] = pArr[i];
        } else {
            pNewArr[i] = pArr[i];
        }
    }

    delete [] pArr; // 回收老数组

    // 循环打印新数组
    for(int i = 0; i < 4; i++){
        cout << pNewArr[i] << endl;
    }

    return 0;
}

1.8 数组元素的插入

#include "iostream"
using namespace std;

int main(){

    // 需求:将元素分别插入下标1和3的位置

    int * pArr = new int[5] {1, 2, 3, 4, 5};
    // 创建一个新的数组
    int * pNewArr = new int[7];

    int offset = 0; // 偏移量用来控制新老数组元素的下标对照
    // 循环新数组,挨个进行元素填充
    for(int i = 0; i < 7; i++){
        if (i == 1) {
            pNewArr[i] = 11; // 插入新元素
            offset++;
            continue;
        } else if (i == 3) {
            pNewArr[i] = 66; // 插入新元素
            offset++;
            continue;
        }

        // 不是插入位置,从老数组中提取元素放入新数组中
        // 公式:老数组的元素下标 + offset = 新数组的元素下标
        // 当前循环的i是新数组的下标
        pNewArr[i] = pArr[i - offset];
    }

    delete [] pArr;

    // 遍历新数组
    for(int i = 0; i < 7; i++){
        cout << pNewArr[i] << " ";
    }

    return 0;
}

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全真王重阳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值