====================================================||
欢迎讨论技术的可以相互加微信:windgs (请备注csdn+xx职业)
====================================================||
目录
欢迎讨论技术的可以相互加微信:windgs (请备注csdn+xx职业)
今天突然间看到一篇文章讲解指针和引用还有数组、指针、数值形参等,但是里面都是错误的,直接对指针进行指针+1,把指针的地址都给做偏移了,相信误导了很多的同学。所以随便写了下,希望对各位有点用处,不懂之处可以留言或者加wx
1. 指针和引用
引用
只是对象的别名。定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。定义一个引用之后,对该引用的所有操作都是在与之绑定的对象上进行的。
存在引用的引用、指针的引用
指针
就是内存的一块地址编号,存储这各种对象,所以存在对指针的引用。如,
存在指针的指针、引用的指针(形参的时候不可以)
int i = 42;
int *p = &i;
int *&r = p;
解析:离变量名最近的符号(此处是&)对变量有最直接的影响,因此 r 是一个引用。声明符的其余部分用以确定 r 引用的类型是什么,此例中的 int * 说明 r 引用的是int类型的指针。
例子:修改指针的值
2. 指针和数组
数组有一个特性:在很多用到数组名字的地方,编译器都会自动将其替换为一个指向数组首元素的指针!如,
auto与数组
当使用数组作为一个auto变量的初始值时,推断得到的类型是指针,而非数组!如,
int ia[] = {0,1,2};
auto ia2(ia); // ia2 是一个int指针,指向ia的第一个元素!
decltype与数组
与之相反,当使用decltype关键字时,上述转换不会发生,decltype推断得到的类型就是原表达式真实的类型。
int A[] = { 0,1,2 };
decltype(A) B; // B是一个数组,其大小为3
B[0] = 1;
B[1] = 2;
B[2] = 3;
for (auto i = begin(B); i != end(B); ++i) {
cout << *i << " ";
}
cout << endl;
结果:1,2,3
下标和指针
对数组执行下标运算其实就是对指向数组元素的指针执行下标运算。如,
int *p = &A[2];
int i = p[-2]; // 其实就是 i=*(p-2)
内置的下标运算符所使用的索引值可以是负数。
数组元素的个数
指向数组的指针
首先,要讲一下多维数组:多维数组实际上是数组的数组,即数组的元素类型是数组。如,
int A[3][4];
A 是一个数组,大小为3,元素类型为 int[4],即元素类型为大小为4的 int数组。
多维数组名转换得来的指针实际上是指向第一个内层数组的指针:
int *ptrs[10]; // 指针数组
int (*p)[4] = A; // 指向数组的指针
p = &A[2];
默认情况下,类型修饰符从右向左依次绑定。对 ptrs 来说,从右向左理解为:首先,[10] 说明我们定义的是一个大小为10的数组,它的名字为 ptrs,然后int*说明数组中存放的是指向int 的指针。
当声明带上了括号后,等于拥有了最先解释权:首先,圆括号括起来的部分(*p)说明p是一个指针,剩余部分则说明了指针所指向的对象的类型,此处是int[4],即大小为4的int数组;所以p是一个指针,指向一个大小为4的int数组。此处圆括号不可少!
3. 数组形参
注意,不存在元素类型为引用的数组!所以如下声明是错误的。
int &refs[10] = /* ? */;
引用一个数组:数组本身就是对象,所以允许定义数组的引用。如,
int B[4];
int (&ref)[4] = B; // 引用一个大小为4的int数组
解释过程和指向数组的指针一样。首先看圆括号部分,(&ref)说明ref是一个引用,其余部分int[4]说明了ref引用的是一个大小为4的int数组。
使用数组时通常会将其转换为指针,所以当我们传递一个数组时,实际上传递的是指向数组首元素的指针。即使显式指定了数组大小,也没有用,因为编译器会忽略它!如下三个函数声明是等价的:
void print(const int*);
void print(const int[]);
void print(const int[10]); // 都是一样编辑器已经做处理
以上函数的形参都是 const int* 类型的。数组的大小对该函数的调用没有影响。
通常情况下,可以显式传递一个表示数组大小的形参、或传递指向数组首元素和尾后元素的指针来解决以上问题。
void print(const int A[], size_t size);
void print(const int *beg, const int *end);
传递数组的引用
形参可以是数组的引用。此时,引用形参绑定到对应的实参上,也就是绑定到某个数组上。
// 维度是类型的一部分
void print(int (&arr)[10]);
传递数组的指针
数组不允许拷贝,所以我们无法以传值方式使用数组形参。
和所有数组一样,当将多维数组传递给函数时,真正传递的是数组首元素的指针。此时,传递的指针就是一个指向数组的指针,数组的第二维度的大小是数组类型的一部分,不能省略。
void print(int (*matrix)[10], int rowSize);
也可以使用数组的语法定义函数,此时编译器会一如既往地忽略掉第一个维度,所以最好不要把它包含在形参列表内:
void print(int matrix[][10], int rowSize);