C++数组入门

在C++编程中,数组作为一种基本的数据结构,扮演着不可或缺的角色。无论是处理简单的数据存储,还是实现复杂的算法,数组都提供了一种高效且直观的方式来管理和操作数据。对于每一个学习C++的程序员来说,理解数组的原理、使用方法以及它与内存管理的关系,都是迈向更高级编程技巧的重要一步。

在这篇博客中,我们将深入探讨C++数组的各个方面,从基本的定义和初始化,到内存布局与指针的结合使用。通过这些内容,你将不仅能够掌握如何在C++中正确地使用数组,还能理解背后更深层次的内存管理机制。这些知识将帮助你编写更高效、更健壮的C++代码。

类与结构体中的默认访问控制

  • 类 (class) 中的成员变量: 默认情况下,类中的所有成员变量和成员函数的访问控制权限都是 private。这意味着它们只能被类内部的成员函数或者友元函数访问,外部无法直接访问这些成员。

  • 结构体 (struct) 中的成员变量: 默认情况下,结构体中的所有成员变量和成员函数的访问控制权限都是 public。这意味着它们可以被外部直接访问,结构体在这方面与类有着不同的默认行为。

数组概述

  • 数组索引从0开始: 在C++中,数组的索引是从0开始的,这意味着第一个元素的索引是0,第二个元素的索引是1,依此类推。如果数组的大小是 n,那么最后一个元素的索引是 n-1

  • 打印数组: 当你尝试直接打印一个数组时,输出的是数组的首地址(即第一个元素的地址),而不是数组中的元素。数组名本身就是一个指向数组第一个元素的指针,所以打印数组名等价于打印数组的首地址。

在这里插入图片描述

数组与 for 循环的关系

  • 常与 for 循环搭配使用: 数组通常与 for 循环搭配使用,这样可以方便地对数组中的每个元素进行操作。通过循环遍历数组的索引,可以对数组进行初始化、修改或读取。
    在这里插入图片描述

内存布局与指针

  • 连续内存块: 数组在内存中是一块连续的存储空间,每个元素紧邻地存放在一起。这种布局使得数组的访问非常高效,因为通过数组名和索引计算,CPU可以迅速找到对应的内存位置。

  • 指针与数组: 由于数组的内存是连续的,可以很方便地通过指针来操作数组。数组名实际上是一个指向数组第一个元素的指针,因此可以通过指针偏移来访问数组中的任意元素。这种特性使得数组和指针在C++中密不可分,很多低级操作都依赖于此。
    在这里插入图片描述

动态内存管理

  • 使用 new 申请内存: 当需要在运行时动态分配数组时,可以使用 new 运算符。这会在堆(heap)上分配一块连续的内存用于存储数组。由于堆内存的生命周期不受函数调用的限制,因此分配的内存不会在函数结束时自动释放。

  • 释放内存: 动态分配的内存必须由程序员显式释放,使用 delete 运算符来避免内存泄漏。对于数组,需要使用 delete[] 来释放内存,这样可以确保数组的每个元素都得到正确的销毁。
    在这里插入图片描述

数组指针与地址存储

  • 数组指针的赋值: 当创建一个数组并将其赋值给一个指针时,这个指针实际上指向的是数组的首地址,而不是数组中的具体数值。通过这个指针,可以访问数组中的每个元素。由于数组名是一个指向数组第一个元素的指针,所以在需要传递数组时,通常传递的是数组的指针。

  • 在这里插入图片描述

提前声明数组的大小

#include <iostream>

class Entity {
public:
    static const int exampleSize = 5;  // 声明并初始化静态常量
    int example[exampleSize];          // 使用静态常量声明数组

    // 构造函数
    Entity() {
        for (int i = 0; i < exampleSize; i++) {
            example[i] = 2;            // 初始化数组元素
        }
    }
};

int main() {
    Entity entity;

    for (int i = 0; i < Entity::exampleSize; i++) {
        std::cout << entity.example[i] << " ";
    }

    return 0;
}

代码解释

  1. 静态常量声明:
    static const int exampleSize = 5; 声明了一个静态常量 exampleSize,它用于定义数组的大小。

  2. 数组声明:
    int example[exampleSize]; 使用 exampleSize 来定义数组的大小。由于 exampleSize 是静态常量,所以在编译时是已知的,可以用来定义数组的大小。

  3. 构造函数:
    构造函数 Entity() 中的循环用来初始化数组 example 中的每一个元素为 2

  4. 打印数组内容:
    main 函数中,我们创建了一个 Entity 对象,并通过循环输出数组 example 的每一个元素。

在类中使用 const int exampleSize = 5static const int exampleSize = 5 都是合法的,但它们的语义和作用范围不同。

const int exampleSize = 5;

  • 非静态成员常量: 如果你只写 const int exampleSize = 5;,这个常量是类的每个实例(对象)都有一份拷贝。这意味着如果你创建多个 Entity 对象,每个对象都持有自己的一份 exampleSize
  • 内存开销: 如果有很多对象实例化,尽管 exampleSize 不变,但每个实例都会有一份拷贝,这可能会稍微增加内存开销(虽然这是微不足道的,除非有大量实例)。
  • 用法限制: 你无法在类外部通过 Entity::exampleSize 直接访问该常量,因为它属于对象的实例。

static const int exampleSize = 5;

  • 静态成员常量: 使用 static const 表明这个常量属于类本身,而不是某个实例。所有的实例共享这一个常量。
  • 内存优化: 由于这个常量是静态的,所有实例共享一份内存,这在有大量实例时可以节省内存。
  • 全局访问: 你可以通过 Entity::exampleSize 直接访问这个常量,而无需创建 Entity 的实例。这在某些情况下会更方便。

选择使用哪种方式

  • 使用 static const: 如果这个常量在所有实例之间不变,且需要被所有实例共享,推荐使用 static const
  • 使用 const: 如果你希望每个实例都有自己独立的常量值,或者这个常量和实例的某些特性强相关,可以使用非静态 const

对于数组大小这种场景,通常会使用 static const,因为数组大小通常是类级别的常量,并不需要每个对象都持有一份拷贝。

std::array 创建数组

#include <iostream>
#include <array>  // 需要包含 <array> 头文件

class Entity {
public:
    static const int exampleSize = 5;  // 声明并初始化静态常量
    int example[exampleSize];          // 使用静态常量声明数组
    std::array<int, 5> another;        // 使用 std::array 声明另一个数组

    // 构造函数
    Entity() {
        for (int i = 0; i < another.size(); i++) {
            example[i] = 2;            // 初始化 example 数组元素
            another[i] = 2;            // 初始化 another 数组元素
        }
    }
};

int main() {
    Entity entity;

    // 打印 example 数组内容
    for (int i = 0; i < Entity::exampleSize; i++) {
        std::cout << entity.example[i] << " ";
    }
    std::cout << std::endl;

    // 打印 another 数组内容
    for (int i = 0; i < entity.another.size(); i++) {
        std::cout << entity.another[i] << " ";
    }

    return 0;
}

代码解释

  1. 引入 <array> 头文件:
    因为你使用了 std::array,所以必须包含 <array> 头文件。

  2. 静态常量 exampleSize:
    static const int exampleSize = 5; 用来定义数组的大小,同时也在定义 example 数组时使用。

  3. 数组声明:

    • int example[exampleSize]; 是一个普通的C++数组。
    • std::array<int, 5> another; 是一个固定大小为5的标准库数组,具有更丰富的功能和更安全的边界检查。
  4. 构造函数:
    构造函数中使用循环来初始化 exampleanother 数组中的每一个元素为 2。注意这里 another.size() 返回数组的大小,而 exampleSize 也是5,所以两个数组的大小是一致的。

  5. 打印数组内容:
    main 函数中,分别打印了 exampleanother 数组的内容。

小结

通过这种方式,你同时使用了普通C++数组和std::array,其中std::array提供了更多的功能和类型安全。在实践中,如果你需要一个固定大小的数组并且希望有更多的函数支持(如size()),std::array 通常是更好的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值