C语言程序员程序员技术栈

c++基础(数组)

2019-04-30  本文已影响2人  zidea
Cplusplus-tutorial-in-hindi.jpg

数组就是一些列具有相同类型变量集合,便于维护。可以将数组理解为一个变量的集合的变量。

数组声明

数组在声明的时候需要指定出数组中元素的类型和数组的大小

 int arr[5];

数组即指针

int main(int argc, char const *argv[])
{
    int arr[5];

    std::cout << arr << std::endl;

    std::cin.get();
}

运行代码,我们发现 arr 是一个内存地址,定义一个数组 arr 实际是一个指针类型,是一个数组的指针。

0x7ffeeafaa7f0

visual studio IDE 提供根据内存地址查看内存的功能,可以查看到数组是连续的内存的根据内存元素类型(也就是占用内存大小)以及数组的长度乘积所定。这里每个 int 占 4 字节。

数组还是一个有序的元素集合,这表示我们通过下标可以访问到数组的元素,在 c++ 下标是从 0 开始计算的,也有的语言是从 1 开始计算。

arr[0] = 1;

数组越界

当我们访问到那些不受我们控制的内存(arr[-1], arr[5]),编译时候就会抛出警告,不过编译还是成功。不过既然我们做出规定还是应该按规定办事,要不可能在以后存在隐患和问题,难于调试。

    arr[-1] = 1;
    arr[5] = 1;
warning: array index 5 is past the end of the array (which contains 5 elements)
      [-Warray-bounds]

数组的遍历

for (int i = 0; i < 5; i++)
    {
        std::cout << arr[i] << std::endl;
    }

进一步证明数组就是指针

int main(int argc, char const *argv[])
{
    int arr[5];

    int *prt = arr;

    for (int i = 0; i < 5; i++)
    {
        std::cout << prt[i] << std::endl;
    }

    std::cout << arr << std::endl;

    std::cin.get();
}

定义一个指针变量然后将数组 arr 赋值给这个变量。然后遍历 prt 可以得到同上面相同结果。

int main(int argc, char const *argv[])
{
    int arr[5];

    int *prt = arr;

    for (int i = 0; i < 5; i++)
    {
        prt[i] = 2;
    }

    *(prt + 2) = 5;

    for (int i = 0; i < 5; i++)
    {
        std::cout << prt[i] << std::endl;
    }

    std::cin.get();
}

在上面代码中我们可以通过移动指针位置来修改指定位置数组的值,prt + 2 为指针为 2 的元素然后,通过*(prt+2) 进行对其赋值,输入结果如下。

2
2
5
2
2

这里是 int 类型指针所以内存存储单元为 4 字节,所以指针移动 2 表示移动了 8 字节,已经知道字符是占一个字节,所以将指针修改用于存储字符(char*),现在是按字符的字节数来移动指针所以移动 8 字节。然后将其转换为指向数据类型为 int 的指针。

*(int *)((char *)prt + 8) = 5;

栈与堆

之前我们所定义数组都是位于栈内存而非堆内存,如果我们用 new 所创建的数组都是位于堆内存而非栈内存。

int main(int argc, char const *argv[])
{
    int arr[5];

    int *another_arr = new int[5];

    std::cin.get();
}

栈:是一种连续储存的数据结构,具有先进后出的性质。通常的操作有入栈(圧栈)、出栈和栈顶元素。想要读取栈中的某个元素,就要将其之前的所有元素出栈才能完成。类比现实中的箱子一样。

堆:是一种非连续的树形储存数据结构,每个节点有一个值,整棵树是经过排序的。特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。常用来实现优先队列,存取随意。

数组位于堆还是位于栈内存区别在于其生命周期。

    int *another_arr = new int[5];
    delete[] another_arr;

因为位于堆内存,所需需要手动释放内存,这里因为是数组所以通过delete[] 来代替delete 释放数组another_arr

class Tut
{
    int arr[5];
    Tut()
    {

        for (int i = 0; i < 5; i++)
        {
            arr[i] = 2;
        }
    }
};

上面 Tut 类中定义了一个数组,并且在构造函数对其进行赋值。然后我们打开内存查看器,就会发现这个数组内存地址位于该类中。

class Tut
{
    int *arr = new int[5];
    Tut()
    {

        for (int i = 0; i < 5; i++)
        {
            arr[i] = 2;
        }
    }
};

如果修改通过 new 在 Tut 类中创建数组就会发现,在类中仅有数组的指针地址,我们需要通过该地址可以访问到数组内存。

在 c++ 中我们无法通过 size 来像其他语言那样获取到数组的大小。

arr->size();

我们可以通过下面方法来间接获取数组的大小,通过数组所占字节数/数组元素类型所占的字节数,不过并不推荐这样使用我们需要自己来维护数组的大小。

    int arr[5];
    int count = sizeof(arr) / sizeof(int);
    std::cout << count << std::endl;

推荐自己控制数组的大小

class Tut
{
    static const int size = 5;
    int arr[size];

    Tut()
    {

        for (int i = 0; i < size; i++)
        {
            arr[i] = 2;
        }
    }
};

c++11

在 c++11版本支持标准库中的数组,而且也提供了便于操作的一些方法。

#include <iostream>
#include <array>
class Tut
{
    static const int size = 5;
    int arr[size];

    std::array<int, 5> another;

    Tut()
    {

        for (int i = 0; i < another.size(); i++)
        {
            another[i] = 2;
        }
    }
};

不过更多便利就是意味着更多性能的代价,个人推荐使用原生数组而不是c++ 提供数组。

上一篇 下一篇

猜你喜欢

热点阅读