[C++学习]数组

一、描述

数组是一种类似于vector的复合类型,但与vector不同的是,数组的大小确定不变,不能随意向数组添加元素。

二、定义和初始化

数组声明形如a[b],b必须为常量表达式并且大于0。

unsigned s = 4; // 不是常量表达式
constexpr unsigned size = 4; // 常量表达式

int a1[4]; // 含有4个整数的数组
int a2[s]; // 错误写法: s不是常量表达式
int a3[size]; // 含有4个整数的数组

默认情况下,数组的元素被默认初始化,默认初始化会令数组含有未定义的值。定义时必须确定数组类型,不能使用auto关键字。与vector一样,数组是一个对象,所以不存在引用的数组。

显式初始化

int a1[3] = {1, 2, 3}; // 含3个元素,分别是1,2,3
int a2[] = {1, 2, 3}; // 含3个元素,分别是1,2,3
int a3[5] = {1, 2, 3}; // 含5个元素,分别是1,2,3,0,0

string a4[3] = {"hello", "world"}; // 含3个元素,分别是"hello","world"和""
字符数组

字符数组有一种额外的初始化形式:可以利用字符串字面值对此类字符串进行初始化。这种方法会在字符串字面值结尾处多一个空字符'\0',该字符也会被拷贝到字符数组中去。

char a1[] = {'C', '+', '+'}; // 列表初始化,没有空字符
char a2[] = {'C', '+', '+', '\0'}; // 列表初始化,有空字符
char a3[] = "helloworld"; // 自动添加字符串结束的空字符

不能将数组的内容拷贝给其他数组作为初始值,也不能用数组给其他数组赋值!

int a1[] = {1, 2, 3};
int a2[] = a1; // 不能用一个数组初始化另外一个数组
a2 = a1; // 不能用数组给其他数组赋值

三、访问数组元素

和string、vector一样,数组的元素访问也可以用下标运算符。数组索引从0开始。

使用数组下标时,通常将其定义为size_t类型。size_t是一种机器相关的无符号类型,它被设计得足够大以便能够表示内存中任意对象的大小。在cstddef(C语言stddef.h头文件的C++语言版本)头文件中定义了size_t类型。

for循环遍历数组示例:

int arr[] = {1, 2, 3, 4, 5};
for (size_t i = 0; i < 5; i = i + 1)
{
    cout << arr[i] << endl;
}
for (auto i : arr)
{
    cout << i << endl;
}

四、指针与数组

对数组的元素使用取地址符得到的是该元素的指针。

string nums[] = {"one", "two", "three"};
string *p = &nums[0];

然而数组还有一个特性:在很多用到数组名字的地方,编译器都会自动将其替换为指向数组首元素的指针。

string *p2 = nums; // 等价于string *p = &nums[0];

使用auto关键字时,推断类型为指针而不是数组,使用decltype关键字时返回类型时对应的数组。比如:

int a[] = {0, 1, 2, 3, 4, 5, 6};

auto a1(a); // a1是一个整型指针,指向a的第一个元素
decltype(a) a2 = {0, 1, 2, 3, 4, 5, 6}; // a2是一个整形数组

指针也是迭代器

数组的指针也允许使用递增运算符,使其移向下一位置。

int a[] = {0, 1, 2, 3, 4, 5, 6};
int *p = a;
++a; // p指向a[1]

但是与迭代器不同之处在于,数组指针指向尾后时不清楚具体元素是什么,所以不能对尾后指针进行递增或解引用。

int a[] = {0, 1, 2, 3, 4, 5, 6}; // 尾后指针指向地址为&a[7]
for (int *p = a; p != &a[7]; p = p + 1)
{
    cout << *p << endl;
}

C++11新标准中引入了名为begin和end函数:

int a[] = { 1, 2, 3, 4, 5 };
int* p_begin = begin(a);
int* p_end = end(a);
for (auto p = p_begin; p != p_end; p = p + 1)
{
	cout << *p << endl;
}

begin函数返回值是指向a数组的首元素的指针,end函数返回值是指向a数组尾元素的下一个位置的指针。

指针运算

  • 给一个指针加上或减去某个整数值,结果仍然是指针。新指针指向的元素与原来的指针相比前进或后退了该指数值个位置。
  • 两个指针相减的结果类型是一种名为ptrdiff_t的标准库类型,与size_t一样被定义在cstddef头文件中,因为差值可能为负,所以ptrdiff_t是一种带符号类型。
  • 两个指针指向同一个数组的元素或尾元素下一个位置时,就能利用关系运算符进行比较。例如:
int a[] = { 1, 2, 3, 4, 5 };
int* b = a;
int* e = a + 5;
while (b < e)
{
	cout << *b << endl;
	b = b + 1;
}

五、多维数组

多维数组的初始化

int a1[2][2] = {
    {1, 2 },        // 第一行元素初始化
    {3, 4 }         // 第二行元素初始化
};

int a2[2][2] = {1, 2, 3, 4}; // 与上面的方法等价

int a3[2][2] = {
    {0}, {1}
}; // 仅仅初始化每行的首元素,其余默认为0

for循环处理多维数组

C++11新标准中添加了范围for循环语句:

int a[2][2] = {1, 2, 3, 4};
for (const auto &row : a)
{
	for (auto &col : row)
	{
		cout << col << " ";
	}
	cout << endl;
}

指针与多维数组

使用for循环遍历:

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

使用begin和end函数的简化:

int a[2][2] = {1, 2, 3, 4};
for (auto p = begin(a); p != end(a); p++)
{
	for (auto q = begin(*p); q != end(*p); q++)
	{
		cout << *q << " ";
	}
	cout << endl;
}
posted @ 2019-09-21 14:27  Dumbledore  阅读(174)  评论(0编辑  收藏  举报