首页 > 编程语言 >【C++学习笔记】数组与指针(三)

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

时间:2024-09-09 08:53:18浏览次数:10  
标签:cout int 元素 笔记 C++ 数组 array 指针

目录

一、数组

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;
}

标签:cout,int,元素,笔记,C++,数组,array,指针
From: https://blog.csdn.net/qq_38196449/article/details/142004468

相关文章

  • 【C++学习笔记】逻辑判断语句与循环语句(二)
    目录一、逻辑判断语句1.1ifelse语句1.2 switch语句1.3枚举类型二、循环语句2.1while循环2.2dowhile循环2.3for循环2.4break与continue关键字2.5goto语句一、逻辑判断语句1.1ifelse语句#include"iostream"usingnamespacestd;intmain(){......
  • 【C++】list(下)
    个人主页~list(上)~list四、模拟实现1、list.h(1)关于整个list的搭建①节点②迭代器③接口(2)自定义类型实例化2、test.cpp(1)test1(2)test2五、额外小知识四、模拟实现1、list.h#pragmaonce#include<iostream>namespacelittle_monster{ template<classT> ......
  • c++的初始化列表与const成员
    初始化列表与const成员const成员使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。在定义const成员时......
  • c++的构造函数与析构函数
    构造函数与析构函数构造函数1、什么构造函数类、结构、联合中的特殊成员函数,与类名、结构名、联合名同的成员函数,没有返回值。class类名{public:  类名(参数列表) {     }};2、何时调用构造函数当创建类对象时(实例化对象)会自动调用构造函......
  • 【算法笔记】多源最短路问题——Floyd算法
    0.前言在图中,如果要求任意两点间的距离,则可以使用Floyd(\(\mathcalO(N^3)\)......
  • 【算法笔记】单源最短路问题——Dijkstra算法(无优化/优先队列/set优化)
    0.前言Dijkstra算法可在\(\mathcalO(m\logm)\)或\(\mathcalO(m\logn)\)的时间内求解无负权单源最短路问题。本文中,我们将详细介绍算法的原理、实现,以及常用的两种优化。另外,Dijkstra算法也不要乱用,比如说多源的最短路,用Dijkstra求解的复杂度只有\(\mathcalO(nm\logm)\),但......
  • 【算法笔记】三种背包问题——背包 DP
    前言背包(Knapsack)问题是经典的动态规划问题,也很有实际价值。01背包洛谷P2871[USACO07DEC]CharmBraceletSAtCoderEducationalDPContestD-Knapsack1有\(n\)个物品和一个总容量为\(W\)的背包。第\(i\)件物品的重量是\(w_i\),价值是\(v_i\)。求解将哪些物品装入背包......
  • 【算法笔记】Kruskal/Prim算法——求解最小生成树问题
    前言生活中经常遇到类似这种的问题:公路修建有一些城市,城市之间要修建高速公路,每两个城市之间都可以修双向的路。其中每两个城市之间修路都需要花费对应的金额。请问如何修路,使得总花费的金额最少,且任意两个城市之间都可以直接或间接通过修建的路来通行?实际上,我们可以把这种......
  • 【算法笔记】树状数组/Binary Indexed Tree/Fenwick Tree
    前言树状数组,即树形存储的数组,又称BinaryIndexedTree或FenwickTree。抛开它树形的存储结构,这种神奇的数据结构的应用看起来与「树」没什么关系:有一个序列\(A=(A_1,A_2,\dots,A_N)\),在不超过\(\mathcalO(\logN)\)的时间复杂度内完成下列操作:\(\to~\)求\([L,R]\)区间内所......
  • 【算法笔记】位运算详解
    0.前言突然想到位运算是个好东西,就来水一波文章了……注意:我把能想到的有关位运算的所有内容都放进来了,所以篇幅较长,请谅解!若有写的不清楚或者不够详细的地方欢迎在评论区补充,谢谢支持!本文中参考代码均使用C++编写。废话不多说,下面步入正题。1.基本运算有一定基础的可以......