数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int a1[3] = {0, 1, 2};
int a2[] = {0, 1, 2}; // 可以省略维度
int a3[5] = {0, 1, 2}; // {0, 1, 2, 0, 0},后面的是默认值
string a4[3] = {"qwt"}; // {"qwt", "", ""} 默认值是空字符串
char a5[] = "C++"; // 末尾自动添加 '\0'
char a6[3] = "C++"; // error

constexpr size_t n = 5;
int a7[n] = {0, 1, 2};

// 计算数组长度
int length = sizeof(numbers) / sizeof(numbers[0]);
// sizeof 变量可以不加括号
cout << "Size of qwt array = " << sizeof qwt << " bytes." << endl;
// sizeof 数据类型要加括号
cout << "Size of one element = " << sizeof(int) << " bytes." << endl;

sizeof 返回类型或数据对象的长度,单位为 字节

只有在定义数组时才能初始化,如果没有初始化定义的数组,则元素值不确定,可能是以前驻留在该内存单元中的值

1
2
3
4
int cards[4] = {3, 6, 8, 10}; // okay
int hand[4]; // okay
hand[4] = {5, 6, 7, 9}; // not allowed
hand = cards; // not allowed

数组名本质是地址,那么将地址赋值给另一个地址这种操作本身就是错误的

  • 数组名是一个指针,代表第一个元素的地址
  • 编译器不会检查数组越界,数组名是数组的地址

二维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
int a1[3][4] = {
{0, 1, 2, 3}, // initializers for the row indexed by 0
{4, 5, 6, 7}, // initializers for the row indexed by 1
{8, 9, 10, 11} // initializers for the row indexed by 2
};

int a2[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
int a3[3][4] = {{ 0 }, { 4 }, { 8 }}; // 只初始化第一列,其余为 0
int a4[3][4] = {0, 3, 6, 9}; // 只初始化第一行,其余为0

// loop
for (auto row : a1)
for (auto col : row)

复杂声明

1
2
3
4
int *ptrs[10]; // ptrs is an array of ten pointers to int
int &refs[10] = /* ? */; // error: no arrays of references
int (*Parray)[10] = &arr; // Parray points to an array of ten ints
int (&arrRef)[10] = arr; // arrRef refers to an array of ten ints

数组名

数组名也是表示第一个元素的地址,但是 sizeof 不会将数组名解释为地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
double wages[3] = {1.0, 2.0, 3.0};
short stacks[3] = {1, 2, 3};

double *pw = wages;
short *ps = &stacks[0];

cout << *ps << endl; //1
cout << *(ps + 1) << endl; // 2

cout << sizeof(wages) << endl; // 24
cout << sizeof(pw) <<endl; // 8

short *p = &stacks[2];
int x = p[-2]; // stacks[0]

数组名被解释为第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址

1
2
3
short tell[10];
cout << tell << endl; // displays &tell[0]
cout << &tell << endl; // displays address of whole array

虽然打印出的两个地址相同,但 &tell[0] 是一个 2 字节内存块的地址,而 &tell 是一个 20 字节内存块的地址

tell + 1 地址值加 2,而 &tell + 1 地址值加 20

1
2
3
4
short *pas[20]; // pas 数组,每个元素都是 short *
short (*pas)[20]; // pas 指针,指向一个数组,每个元素是 short

short (*pas)[20] = &tell; // (*pas)[0] 是 tell 数组第一个元素

char 数组扩展

1
2
char flower[10] = "rose";
cout << flower << "s are red\n";

因为数组名是第一个元素的地址,所以 cout 对象认为 char 的地址是字符串的地址,就会打印该地址处的字符,然后继续打印后面的字符,直到遇到空字符位置

引号括起来的字符串 "s are red\n" 也是第一个元素的地址

1
2
3
4
5
6
7
8
9
10
11
12
char animal[20] = "bear";
const char *bird = "wren";
char *ps;

cout << "Enter a kind of animal: ";
// cin >> bird;
// cout << bird << endl;
// cin >> ps;
// cout << ps << endl;
cin >> animal;
cout << animal << endl;
cout << (int *)animal << endl; // 通过强制类型转换打印处 animal 的地址

以上三中输入情况只有 char 数组可以输入

1
2
3
4
5
6
7
const char* cities[5] = {  
"CiXi",
"YuYao",
"NingBo11",
"HangZhou11",
"ShangHai11"
};

字符指针地址,因为每个字符串都代表着每个首字符的地址

1
2
3
4
5
// char 字符串常用函数
strlen(p) // Returns the length of p, not counting the null.
strcmp(p1, p2) // Compares p1 and p2 for equality. Returns 0 if p1 == p2,apositive value if p1 > p2, a negative value if p1 < p2.
strcat(p1, p2) //Appends p2 to p1.Returns p1.
strcpy(p1, p2) //Copies p2 into p1.Returns p1.

string 赋值给 char 数组

1
2
3
string s = "qwt";
char *str = s; // error: can’t initialize a char* from a string
const char *str = s.c_str(); // ok,c_str() 返回 C 风格字符串

扩展

1
2
3
int a1[3] = {0, 1, 2};
auto a2(a1); // a2 is an int* that points to the first element in a1
decltype(a1) a3 = {0, 1, 2};

C++11 新特性,新增了 begin()end() 两个函数

1
2
3
int a[3] = {0, 1, 2};
int *beg = begin(a); // pointer to the first element in a
int *last = end[a]; // pointer one past the last element in a

函数和数组

1
int sum_arr(int arr[], int n); // int arr[10],维度也可以写上

实际上 arr 传递的是数组指针,并且也是指向第一个元素的地址,所以也可以用下面的写法

1
int sum_arr(int *arr, int n);

在 C++ 中只有用于函数头或函数原型时,int *arrint arr[] 的含义才是相同的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int sum_arr(const int *begin, const int *end)
{
int total = 0;
const int *pt;
for (pt = begin; pt!=end; pt++)
total += *pt;
return total;
}

int main()
{
int cookies[7] = {0, 1, 2, 3, 4, 5, 6};
int sum = sum_arr(cookies, cookies + 7);
return 0;
}

也能够引用传递

1
2
3
4
5
void print(int (&arr)[10])
{
for (auto elem : arr)
cout << elem << endl; // arr is a reference to an array of ten ints
}

函数和二维数组

1
2
int data[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};
int total = sum(data, 3);

sum() 的函数原型

1
2
3
int sum(int (*arr)[4], int size);
// 或
int sum(int arr[][4], int size);

initializer_list

当不确定元素数量,且元素类型一致时,可以使用 initializer_list 进行初始化序列

1
2
3
4
5
6
7
8
9
10
11
12
13
initializer_list<T> lst; // Default initialization; an empty list of elements of type T.

initializer_list<T> lst{a,b,c...}; // lst has as many elements as there are initializers; elements are copies of the corresponding initializers. Elements in the list are const.

// Copying or assigning an initializer_list does not copy the elements in the list. After the copy, the original and the copy share the elements.
lst2(lst);
lst2 = lst;

lst.size(); //Number of elements in the list.

// Returns a pointer to the first and one past the last element in lst.
lst.begin();
lst.end();

可以当作函数参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <initializer_list>
using namespace std;

void printValues(initializer_list<int> values)
{
for (auto value : values)
{
cout << value << " ";
}
cout << endl;
}

int main()
{
printValues({1, 2, 3, 4, 5});
return 0;
}

能够用 initializer_list 来初始化 vector 等容器

1
2
initializer_list<int> values = {1, 2, 3, 4, 5};
vector<int> myVector(values);

initializer_list 不支持下标查询元素,可以通过 range-based for loop 和 迭代器查询元素