指针和数组
使用数组的时候编译器一般会把它转化成指针。 !!使用数组下标时,通常使用 size_t 类型,是一种无符号类型
对数组的元素使用取地址符就能得到指向该元素的指针。
string nums[] = {"one","two","three"};
string *p = &nums[0]; // p 指向 nums 的第一个元素
// cout << *p << endl; 输出:one
在很多使用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首元素的指针:
string *p2 = nums; //等价于 p2 = &nums[0]
在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。
可知,在一些情况下数组的操作实际上是指针的操作。
使用数组作为一个 auto 变量的初始值时,推断得到是指针而非数组:
int ia[] = {0,1,2,3,4,5,6};
auto ia2(ia); //ia2 是一个指针,指向 ia 的第一个元素
ia2 = 22; //错误:ia2是一个指针
其中:
auto ia2(ia); 等价于 auto ia2(&ia[0]);
!!但是对于 decltype(),则不会发生转换。
即返回的类型是一个大小相同的数组:
decltype(ia) x = {9,8,7,6,5,4,3};
指针也是迭代器:
对于 vector 和 string 的迭代器支持的运算,数组的指针全部都支持。
也可以 for 指针遍历数组。
如:
int arr[size] = {};
// 可以通过 &arr[0] 或者 arr 获得首地址
// 可以通过 &arr[size] 获得尾元素的下一个位置的指针
int *b = &arr[0];
int *e = &arr[size];
for(int *x = b;x != e;++ x) {
cout << *x << endl;
}
// 当然,首地址和尾地址可以通过标准库函数 begin 或者 end 获得 首地址 和 尾元素的下一个位置的指针
int *b = begin(arr);
int *e = end(arr);
指针运算
可以使用 vector 和 string 所有的迭代器运算。
给指针加上一个整数,得到的新指针仍需指向同一数组的其他元素,或尾元素的下一个位置。
即:必须在 begin(arr) 与 end(arr) 之间。
constexpr size_t sz = 5;
int arr[sz] = {1,2,3,4,5};
int *ip = arr; // 等价于 int *ip = &arr[0];
int *ip2 = arr + 4; // ip2 指向 arr 的尾元素 arr[4]
同样,两个指针相减得到是它们之间的距离。类型是 ptrdiff_t,定义在 cstddef 中,差值可能为负值,是带符号类型
只有当两个指针指向相关的对象时,才能够进行比较。
下标运算与指针:
对数组进行下标运算其实是对指向数组元素的指针执行下标运算
int ia[] = {0,2,4,6,8};
int i = ia[2];
int *p = ia;
i = *(p + 2); //等价于 i = ia[2]
int *p = &ia[2];
int j = p[1]; //p[1] 等价于 *(p + 1),实际上是 ia[3]
int k = p[-2]; //p[-2] 等价于 *(p - 2),实际上是 ia[0]
!!内置的下标(???先打个问号)运算符所用的索引值可以是负数,这一点与 vector 和 string 不一样