[C++] 数组

目录

1. 与vector容器的区别

2. 定义

3. 初始化

4. 存储指针的数组、数组的引用、数组的指针

5. 访问数组

6. 标准库中的begin()和end()函数

7. 指针的运算

8. 数组的[]运算符和标准库类型string、vector的[]运算符的区别

9. 多维数组

9.1 概念

9.2 多维数组的初始化

9.2 范围for语句处理多维数组

9.3 指针和多维数组

9.3.1 使用指针来访问多维数组

9.3.2 类型别名简化多维数组的指针


1. 与vector容器的区别

相同点:都是一种能存储类型相同的对象的容器。

不同点:数组的存储对象的大小是确定的,且一旦确定,后续不能超过所定大小的容量,而vector是可以随意添加元素的。

2. 定义

int A[d];    :A是数组名,d是数组所存储的维度即容量大小,注意:因为维度必须已知,所以d只能是常量表达式一般来说d是无符号整型,但并不是说d不能为负数(理由如下),C/C++,定义了新的类型size_t,它是一种机器相关的无符号类型,被设计的足够大,以便于能够表示内存中任意对象的大小,其在C++中定义在头文件#include<cstddef>中,寻常就使用在表示数组下标以及内存管理相关的函数中。通常数组名,即标识符A所代表的是指向第一个元素的指针。

size_t d=10;
int A[d]; //err 因为d不是常量表达式

const size_t d=10;
int A[d]; //true

constexpr size_t d=10;
int A[d]; //true

int A[10*2-10]; //true

当用指针来指向数组时,会发生隐式转换,这种转换在特定的运算符中是不会发生的,比如:作为decltype关键字的参数、作为 &、 sizeof 以及 typeid 等运算符的运算对象。

int a[10];
int *p=a;  // 转换:int *p=&a[0];

3. 初始化

与内置类型一样,在函数体内部定义的数组,没有进行初始化的话,所有的值都是未确定的,在函数体外部定义的数组,数组元素的值都默认初始化,比如:是int类型则初始化为0,string类型则初始化为"",等等。其余,一般初始化方式如下:

int A[4]{0,1,2,3};
int A[4]={0,1,2,3};
int A[4]={0,1,2};      // 0,1,2,3,0
string A[3]={"a","b"}; // a,b,""
char A[3]="ab"  //ab

注意:

  1. 如果初始化的长度小于数组定义的长度的话,则未初始化的值将进行值初始化。
  2. 字符数组的初始化,如果没有显式的写出空白字符则需要为空白字符留一个位置。如:
const char ok[3]="abc"; //err 没有为空白字符留位置,因为空白字符也占一个位置
const char ok[3]="ab"; //true

4. 存储指针的数组、数组的引用、数组的指针

int arr[10];

int *ptr[10]; //存放指针的数组

int (*ptr)[10]=&arr; //指向arr的数组,注意:他们的容量必须是一样的

int (&ptr)[10]=arr; //arr数组的引用

int *(&ptr2)[10]=ptr; //存放指针的ptr数组的引用

int (*(&ptr2)[10]=ptr; //err,不存在这样的数组,因为,这是指向ptr的引用的数组,但引用不是一个对象,所以不能这样。

建议:阅读数组的复合操作时,从内往外读,如最后一个,先读括号里面的,&ptr2得它是一个引用,然后读*(&ptr2)得它是一个存放指针的数组。

5. 访问数组

一般使用范围for语句来访问数组

constexpr size_t d=3;
int A[d]{0,1,2};
for(auto &c:A)
{
    c=10;
}

6. 标准库中的begin()和end()函数

定义在头文件#include<iterator>中,这里的begin()和end()函数与容器里的函数不是同一个,同名,不过功能相似,标准库里的begin()返回的是数组里的首元素的指针end()返回是数组尾元素的下一个元素的指针。使用方式:

constexpr size_t k=3;
int A[k]={0,1,2};
int *b=begin(A);
int *e=end(A);

7. 指针的运算

指针的运算与迭代器的运算是相似的,同样有比较、与整数相加、两个指针相减、递增等,也不存在两个指针相加的运算。但是,两个指针相减返回的类型是一个名为ptrdiff_t的标准库类型,其和size_t一样,存在于cstddef头文件中。与size_t不同的是,ptrdiff_t是有符号整型,因为,两个指针相减是有可能产生负值的。

8. 数组的[]运算符和标准库类型string、vector的[]运算符的区别

数组的[]运算符,的下标可以是有符号类型也可以是无符号类型,但标准库类型的下标就必须是无符号类型。

int a[10]={0,1,2,3,4,5,6,7,8,9};
int *p=a+3;
int k=p[-2];  //k=1;

9. 多维数组

9.1 概念

严格来说,C++中没有多维数组,常说的多维数组实际上是数组的数组,应像读指针数组和数组指针那样从内往外读,如int a[3][4],的意思是a首先是一个容量为3的整型数组,然后每一个元素里,又存有一个容量为4的整型数组。同时因为数组的本质其实是指针的操作,所以:二维数组里,每一层存储的都是另一个数组的首指针!如int a[3][4],a的第一层是容量为3的整型数组,这个数组里面的每个元素都存储的是容量为4的数组的首指针。

9.2 多维数组的初始化

多维数组的初始化和一维数组类似,都符合如下特点:

  1. 如果在全局范围内定义,则默认初始化所有元素值为0,若在局部范围内定义,则不会进行默认初始化。
  2. 若只初始化了首元素,则其余的元素全部进行默认初始化。
int a[3][3]=
{
    {0},
    {1},
    {2}
};          // 0 0 0
            // 1 0 0
            // 2 0 0

iny a[3][3]={0};// 0 0 0
                // 0 0 0
                // 0 0 0

9.2 范围for语句处理多维数组

	int ia[3][4] = { 0 };
	for (auto &arr : ia)
	{
		for(auto &col:arr)
		{
            col=1;    //将数组元素全部改变为1
        }
	}   

注意:当使用范围for语句只访问多维数组时,除了最内层循环外,都必须要是引用类型!!

	int ia[3][4] = { 0 };
	for (const auto &arr : ia)  //有无const都可以,只是,这里写上const是为了强调,二维数组的这个行是常量,不可修改。
	{
		for(auto col:arr)
		cout <<col<<endl;
	}

因为:以此二维数组ia为例,当第一层循环不是引用类型时,比如是 auto arr : ia 则此时,数组会被自动转换为指针,auto arr = &ia[0][0] 等价于 auto arr = ia[0] ; 这样的话得到的就是ia二维数组的第一个元素即容量为4的数组的首地址,这样 auto 就会自动转化为 int * 的类型,如果转为了 int * 类型,则到了下一层,此时,arr已经不是数组了,而是一个int型的指针,而对int型的指针进行遍历,显而易见的是不行的。(也可以这样理解,范围for循环处理数组时的机制是使用数组的begin()和end()函数,而一个 int * 指针并不是这两个函数的有效参数,所以不行)。

9.3 指针和多维数组

与一维数组一样,多维数组的标识符,表示着,第一层的第一个数组的首指针。

int ia[3][4];
int (*p)[4] = ia;  // p是指向ia[0]一个容量为4的整型数组的指针
p = &ia[2];        // p此时修改为指向ia[2]一个容量为4的整型数组的指针

9.3.1 使用指针来访问多维数组

因为C++新标准引入了 auto 和 decltype 关键字,所以,访问时,可以避免在数组面前加上一个指针类型了。

int ia[3][4];
for(auto p=ia;p!=ia+3;p++)
{
    for(auto q=p;q!=p+4;q++)
    {
        cout<<*q<<" ";
    }
    cout<<endl;
}

或者使用begin()和end()函数进行访问也可以,注意begin()和end()里取的是 *p,因为p此时是a的指针,而不是a的元素里数组的指针,所以用 *p 。

注意:什么时候取*,什么时候不取* ,要斟酌下,一般非最内层的都要取 * 。

int a[3][4];
for(auto p=begin(a);p!=end(a);p++)   //第一层,p:0~3
{ 
    for(auto q=begin(*p);q!=end(*p);q++) //第二层,q:0~4
    {
        cout<<*q<<" ";
    }
    cout<<endl;
}

9.3.2 类型别名简化多维数组的指针

using int_array=int[4];  // 等价于 typedef int int_array[4];

for(int_array *p=ia; p!=ia+3;p++)
{
    for(int *q=*p;q!=*p+4;q++)
        cout<<*q<<" ";
    cout<<endl;
}

将一个容量为4的int型数组命名为 int_array ,用其来控制循环的变量。

总结:

#include<iostream>
#include<vector>
#include<cstddef>
using namespace std;
int main()
{
	int ia[3][4] = {
		{1},
		{2},
		{3}
	};
	//1
	for (auto &i : ia)
	{
		for (auto j : i)
			cout << j << " ";
		cout << endl;
	}
	//2
	for (size_t i = 0; i < 3; i++)
	{
		for(size_t j=0;j<4;j++)
			cout << ia[i][j] << " ";
		cout << endl;
	}
	//3
	for (auto p = begin(ia); p != end(ia); ++p)
	{
		for (auto q = begin(*p); q != end(*p); ++q)
			cout << *q << " ";
		cout << endl;
	}
    //4
	typedef int int_array[4];
	for (int_array *i = ia; i != ia + 3; ++i)
	{
		for (int *j = *i; j != *i + 4; ++j)
			cout << *j << " ";
		cout << endl;
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值