补充C++基础笔记。
数组
数组和vector:
相同之处:也是存放类型相同的对象的容器,这些对象本身没有名字,需要通过其所在位置访问。
不同之处:数组的大小确定不变,不能随意向数组中增加元素。
定义和初始化内置数组:维度已知
- 定义
unsigned cnt = 42; //不是常量表达式
constexpr unsigned sz = 42; //常量表达式
int arr[10]; //含有10个整数的数组
int *parr[sz]; //含有42个整数指针的数组
string bad[cnt]; //错误:cnt不是常量表达式
- 初始化
const unsigned sz = 3;
int ial[sz] = {0, 1, 2}; //3个元素的数组
int a2[] = {0, 1, 2}; //维度是3的数组
int a3[5] = {0, 1, 2}; //等价于a3[] = {0, 1, 2, 0, 0}
string a4[3] = {"hi", "bye"}; //等价于a4[] = {"hi", "bye", ""}
- 字符数组:使用字符串初始化时,字符串字面值的结尾处有一个空字符,会被拷贝进去
char a1[] = {'C', '+', '+'}; //列表初始化,没有空字符
char a3[] = "C++"; //自动添加表示字符串结束的空字符
- 注意:不能将数组的内容拷贝到其他数组作为初始值,也不能用数组为其他数组赋值。
- 更复杂的数组声明–指针和引用
int *ptrs[10]; //ptrs是含有10个整型指针的数组
int &refs[10] = /*?*/; //错误:不存在引用的数组
int (*Parray)[10] = &arr; //Parray指向一个含有10个整数的数组
int (&arrRef)[10] = arr; //arrRef引用一个含有10个整数的数组
int *(&arry) [10] = ptrs; //arry是数组的引用,该数组含有10个指针
- 一个小例子
string sa[10]; //sa中有10个""
int ia[10]; //ia中有10个0
int main() {
string sa2[10]; //sa2中有10个""
int ia2[10]; //ia2中10个未定义元素 -- 内置变量
//和内置类型的变量一样,如果在函数内部定义了某种内置类型的数组,那么默认初始化会令数组含有未定义的值
}
访问数组元素
- 与标准库类型vector和string一样,数组的元素也能使用范围for语句或下标运算符来访问 -> 数组除了大小固定这个特点外,其他用法与vector基本类似。
- 在使用数组下标的时候,要将其定义成
size_t
类型。
指针和数组
- 使用取地址符可以获取指向某个对象的指针 + 数组也是对象 -> 对数组的元素取地址符就能得到指向该元素的指针。
string nums[] = {"one", "two", "three"}; //数组的元素是string对象
string *p = &nums[0]; //p指向nums的第一个元素
string *p2 = nums; //等价于p2 = &nums[0]
auto的情况
int ia[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; //ia是一个含有10个整数的数组
auto ia2(ia); //ia2是一个整数指针,指向ia的第一个元素
–> 实际上,在大多数表达式中,使用数组类型的额对象其实是使用一个指向该数组首元素的指针。
decltype(ia) ia3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ia3 = p; //错误:不能用整型指针给数组赋值
ia2[4] = i; //正确:把i的值赋给ia3的一个元素
- 指针也是迭代器:支持vector和string的迭代器支持的全部运算
小例子:输出数组arr的全部元素
for (int *b = arr; b != e; ++b)
cout << *b << endl;
- C++11新标准:begin和end两个函数
数组不是类 -->> 这两个函数不是成员函数
小例子:找出arr中的第一个负数
int *pbeg = begin(arr), *pend = end(arr); //pbeg指向arr的首元素,pend指向arr尾元素的下一位置
while (pend != pend && *pend >= 0)
++pbeg;
注意:尾后指针不能执行解引用和递增操作
- 指针运算:解引用、递增、比较、与整数相加、两个指针相减
相减的结果:一种名为ptrdiff_t的标准库类型[定义在cstddef头文件中的机器相关的类型] -> 是一种带符号类型 - 下标和指针
int ia[] = {0, 2, 4, 6, 8};
int i = ia[2]; //ia转换成指向数组首元素的指针,ia[2]得到(ia + 2)所知的元素
int *p = &ia[2]; //p指向索引为2的元素
int j = p[1]; //p[1]等价于*(p + 1), 就是ia[3]所表示的那个元素
int k = p[-2]; //p[-2]是ia[0]表示的那个元素
–> 内置的下标运算符的索引值不是无符号类型,这一点与vector和string不同
多维数组:数组的数组
- 处理多维数组的小例子
方式一:
constexpr size_t rowCnt = 3, colCnt = 4;
int ia[rowCnt][colCnt];
for (size_t i = 0; i != rowCnt; ++i) {
for (size_t j = 0; j != colCnt; ++j) {
ia[i][j] = i * colCnt + j;
}
}
方式二 – C++11新增了范围for语句:
constexpr size_t rowCnt = 3, colCnt = 4;
int ia[rowCnt][colCnt];
for (auto &row : ia)
for (auto &col : row) {
col = cnt;
++cnt;
}
–> 要使用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型。