最近写项目时遇到个指针坑,决定记录一下。
看下面代码,猜下运行结果
#include <bits/stdc++.h> using namespace std; int number1 = 1; int number2 = 2; void f(int *a) { a = &number2; } int main() { int *p = &number1; f(p); printf("%d ", *p); return 0; }
运行结果是1。
之前用指针有一个误区,指针只是指向某个类型的地址,指针本身也是一个类型,所以当参数传入时,已经不是同一个指针了。可以尝试输出a和p的地址,会发现是不一样的。
(PS:这坑在java上更明显,因为java对象引用实质和指针一样,所以改变参数的指向不是一个好方法)
对于上面的代码,可以做如下改进:
方案一:进行内存赋值操作
#include <bits/stdc++.h> using namespace std; int number1 = 1; int number2 = 2; void f(int *a) { *a = number2; } int main() { int *p = &number1; f(p); printf("%d ", *p); return 0; }
方案二:传入指针的地址进行操作
#include <bits/stdc++.h> using namespace std; int number1 = 1; int number2 = 2; void f(int **a) { *a = &number2; } int main() { int *p = &number1; f(&p); printf("%d ", *p); return 0; }
这里顺便探讨下指针可以有多少级,其实理论上指针可以无限级。这样可能有个疑惑,那我指针的指针的指针……编译器是如何定义的呢,定义一个指针时如果有那么多地址他又是如何分配内存?我们尝试输出一下。
#include <bits/stdc++.h> using namespace std; int main() { int number = 0; printf("%p %p ", &number, &(&number)); return 0; }
发现编译错误,提示error: lvalue required as unary '&' operand。我们换一种写法。
#include <bits/stdc++.h> using namespace std; int main() { int number = 0; int *p = &number; printf("%p %p ", p, &(p)); return 0; }
好,这样是可以成功编译的。我们再试一下,再开一个指针。
#include <bits/stdc++.h> using namespace std; int main() { int number = 0; int *p = &number; int **pp = &p; //编译错误 //printf("%p %p %p ", p, &(p), &(&p)); //编译成功 printf("%p %p %p ", p, &(p), &(pp)); return 0; }
好,得出结论。编译器本身不会管你有多少级指针,这都是你自己分配的,至于能分配多少个取决于内存大小。编译器只负责定义类型,在某个地址的内存存下你的数据。至于指针,则是另一种数据类型,而他存的值就是他所指向的地址。