C++菜鸟学习笔记系列(10)——数组

简介: C++菜鸟学习笔记系列(10)——数组

C++菜鸟学习笔记系列(10)

本期主题:数组、数组与指针之间的关系

我们在学习C语言时对于数组一定有很多的了解。数组在C以及C#中都很常见,但是对于C++语言我们更喜欢用vector和迭代器而不是数组和下标。

数组与我前面介绍的vector类型相比非常类似,它们都是可以存放相同对象的元素,且都可以通过其所在位置进行访问。但是与vector相比数组的大小确定不变,不能随意向数组中添加元素,缺少了一部分灵活性。(也正是数组的大小固定导致我们在C++中更喜欢用vector而不是数组)


(如果你有一定的C语言基础,可以直接跳过第一部分内容,直接读后面关于数组的使用及其与指针之间的关系就可以了。)

1.定义及初始化内置数组

数组是一种复合类型。数组的声明类似于a[d]的形式,其中a是数组的名字,d是数组的维度。维度说明了数组中元素的个数,因此必须大于0。数组中元素的个数也属于数组类型的一部分,编译的时候维度应该是已知的。即维度必须是一个常量或者是一个常量表达式。

下面我们来看一下具体怎么定义数组:

const int i = 10;
void main()
{
  int j = 10;
  int arr1[10];
  int arr2[i];
  int arr3[j]; //error
}

在上述代码中我们可以通过字面值或者一个常量值来作为数组的维度值,但是一个变量不能作为数组的维度值。

显式初始化数组元素

我们可以对数组的元素进行列表初始化,此时允许忽略数组的维度。如果在声明时没有指明维度,编译器会根据初始值的数量计算并推测出来;相反的,如果我们指明了维度,那么在列表初始化的时候初始值的总数量不能超出指定的大小。如果维度比提供的初始值数量大,则用提供的初始值初始化靠前的元素,剩余的元素则默认初始化。

下面我们来看一下显式初始化数组的例子:

  int arr1[sz] = {1, 2, 3};
  int arr2[] = {1, 2, 3}; // equal to  arr1[sz] = {1, 2, 3}
  int arr3[sz] = {1, 2, 3, 4};//error 初始值的总数量超出维度
  int arr[4] = {1, 2, 3};

上述代码中的数组初始化方式适合大多数据类型数组的声明,但是对于字符数组仍然存在一些特殊性。

字符数组有一种额外的初始化方式,即我们可以使用字符串的字面值对此类数组进行初始化。当使用这种方式时初始化字符数组时一定要注意字符串字面值的结尾处还有一个空字符,这个空字符也会像字符串的其他形式一样被拷贝到字符数组中去。

  char a1[] = {'1', '2', '3'}; // 没有添加空字符
  char a2[] = {'1', '2', '3', '\0'}; // 显式添加了一个空字符
  char a3[] = "123"; // 等价于a2[] = {'1', '2', '3', '\0'},会自动添加空字符
  char a4[3] = "123"; //提示错误,因为没有考虑后面的空字符,所以超出了数组大小 

注意:不能把数组的内容拷贝给其他数组作为其初始值,也不能使用数组为其他数组赋值。

2.访问数组元素

与标准库类型vector和string一样,数组的元素也是能够使用范围for语句或者下标运算符来访问。

数组除了大小固定这一特点外其余用法和vector基本类似,它们都可以使用下标运算符,但是仍存在一个不太明显的区别是数组中的下标运算符是由C++语言直接定义的,而vector中的下标运算符是库模板vector定义的,只能用于vector类型的运算对象。

下面我们来看一个使用数组下标的小例子:

/*
Author: wxc_1998
Date: 2018/10/6
*/
#include <iostream>
using namespace std;
const int sz = 10;
void main()
{
  int arr[sz], i = 0;
  int sum = 0;
  while (i < sz)
  {
    arr[i] = i;
    i++;
  }
  cout << "the array of 'arr' is:"<< endl;
  for (int j = 0 ; j < sz ; j++)
  {
    sum += arr[j];
    cout << arr[j] << " ";
  }
  cout << endl << "the sum of 'arr' is :" << sum;  
  cout << endl << "press any key to continue!";
    cin.clear();
    cin.sync();
    cin.get();
}

注意:与标准库类型vector和string类似的,检查数组的下标是否在正确的区间内也是我们对代码检验正确性的一个重要内容,但是除了谨慎小心和进行彻底测试之外我们并没有更好的办法去避免这一类问题的出现。

3.指针和数组之间的联系

在C++语言中指针与数组之间有非常密切的联系,使用数组时,编译器常常把它转换为指针。

我们在C++菜鸟学习笔记系列(4)中曾经有过介绍使用取址符&可以获得某个对象的指针,取址符可以用于任何对象。数组的元素也是对象,对数组使用下标运算符得到该数组中某个位置的元素然后再通过取址符就可以获得指向该元素的指针。

例如:

  string arr[] = {"123", "456", "789"};
  string *p = &arr[0];

当我们省略下标直接对数组的名字使用取地址符时:

string *p2 = &arr;

编译器会默认将其替换为一个指向数组首元素的指针,等价于string *p = &arr[0];

由此我们还可以对数组的下标有这样的理解,即我们可以认为:arr[3]等价于在编译器中先找到arr[0]的位置,然后再往后移动3个元素得到arr[3],类似于

string *p2 = &arr;
cout << *(p2 +3);

从上述的介绍中我们可以意识到尽管我们肯定可以通过计算得到数组最后一个元素的指针,但是这样是非常繁琐而且极易出现错误。为了让指针的使用更加简单、安全,C++ 11标准中引入了begin 和 end两个函数,类似于迭代器中的成员函数begin()、end(),不同的是在这里数组是作为begin 和 end两个函数的参数。

下面我们来看一个使用的小例子:

/*
Author: wxc_1998
Date: 2018/10/6
*/
#include <iostream>
#include <iterator>
using namespace std;
const int sz = 10;
void main()
{
  int arr[sz], i = 0;
  int sum = 0;
  while (i < sz)
  {
    arr[i] = i;
    i++;
  }
  cout << "the array of 'arr' is:"<< endl;
  int *b = begin(arr);
  int *e = end(arr);
  while (b != e)
  {
    cout << *b << " ";
    sum += *b;
    b++;
  }
  cout << endl << "the sum of 'arr' is :" << sum;  
  cout << endl << "press any key to continue!";
    cin.clear();
    cin.sync();
    cin.get();
}

如上所示我们改写了第一个例子中的代码,实现了相同的功能,通过begin 和 end两个函数来确定数组的头和尾,然后通过指针的移动获得数组中的所有元素。


好了这次我们就介绍到这里了。


注:虽然这篇博客的内容十分简单,但是大家若有转载还请标明出处!


还有大家若对博客中的内容有任何问题可以随时联系我提问。

目录
打赏
0
0
0
0
3
分享
相关文章
【C++核心】特殊的元素集合-数组与字符串详解
这篇文章详细讲解了C++中数组和字符串的基本概念、操作和应用,包括一维数组、二维数组的定义和使用,以及C风格字符串和C++字符串类的对比。
116 4
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
40 5
|
6月前
|
C++
c++学习笔记07 结构体
C++结构体的详细学习笔记07,涵盖了结构体的定义、使用、数组、指针、嵌套、与函数的交互以及在结构体中使用const的示例和解释。
57 0
|
5月前
|
C++
C++(十一)对象数组
本文介绍了C++中对象数组的使用方法及其注意事项。通过示例展示了如何定义和初始化对象数组,并解释了栈对象数组与堆对象数组在初始化时的区别。重点强调了构造器设计时应考虑无参构造器的重要性,以及在需要进一步初始化的情况下采用二段式初始化策略的应用场景。
|
6月前
|
C++
【学习笔记】【C/C++】 c++字面值常量
【学习笔记】【C/C++】 c++字面值常量
61 1
|
6月前
|
C++数组、vector求最大值最小值及其下标
C++数组、vector求最大值最小值及其下标
220 0
|
6月前
|
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
88 0
|
6月前
|
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
69 0
|
6月前
|
C++
c++学习笔记09 引用
C++引用的详细学习笔记,解释了引用的概念、语法、使用注意事项以及引用与变量的关系。
48 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等