- Published on
Pointer(指针)
- Authors
- Name
- Yanbin
- @ybtaimu
指针定义
Pointer是一个值
,这个值代表一个内存地址
,因此指针相当于指向某个内存地址的路标。
字符表示指针,通常跟在类型关键字的后面,表示指针指向的是什么类型的值。 比如,char表示一个指向字符的指针,float*表示一个指向float类型的值的指针
int* intPtr;
上面示例声明了一个变量intPtr,它是一个指针,指向的内存地址存放的是一个整数
指针的大小
指针的大小与系统的体系结构(也称为字长)密切相关:
32 位系统
:在 32 位系统中,指针的大小通常是4 个字节(32 位)
,因为 32 位系统的内存地址空间是 4GB,地址需要 32 位来表示。64 位系统
:在 64 位系统中,指针的大小通常是8 个字节(64 位)
,因为 64 位系统可以访问更大的内存地址空间,地址需要 64 位来表示。
因此,在 64 位系统中,任何类型的指针(无论是 char*、int* 还是 double*)的大小都是 8 个字节,因为它们都存储内存地址,而地址在 64 位系统中占 64 位(即 8 字节)。
* 运算符
*
这个符号除了表示指针以外,还可以作为运算符,用来取出指针变量所指向的内存地址里面的值
。
void increment(int* p) {
*p = *p + 1;
}
上面示例中,函数increment()
的参数
是一个整数指针p
。函数体里面,*p就表示指针p所指向的那个值
。对*p赋值,就表示改变指针所指向的那个地址里面的值
。
上面函数的作用是将参数值加1。该函数没有返回值,因为传入的是地址,函数体内部对该地址包含的值的操作,会影响到函数外部,所以不需要返回值。事实上,函数内部通过指针,将值传到外部,是 C 语言的常用方法
。
变量地址而不是变量值传入函数,还有一个好处。对于需要大量存储空间的大型变量,复制变量值传入函数,非常浪费时间和空间,不如传入指针来得高效。
& 取地址符
&
运算符用来取出一个变量所在的内存地址。
int x = 1;
printf("x's address is %p\n", &x);
上面示例中,x是一个整数变量,&x
就是x的值所在的内存地址
。printf()的%p是内存地址的占位符,可以打印出内存地址。
上一小节中,参数变量加1的函数,可以像下面这样使用。
void increment(int* p) {
*p = *p + 1;
}
int x = 1;
increment(&x);
printf("%d\n", x); // 2
上面示例中,调用increment()函数以后,变量x的值就增加了1,原因就在于传入函数的是变量x的地址&x。
&运算符与*运算符互为逆运算
,下面的表达式总是成立。
int i = 5;
if (i == *(&i)) // 正确
指针变量的初始化
声明指针变量之后,编译器会为指针变量本身分配一个内存空间,但是这个内存空间里面的值是随机的, 也就是说,指针变量指向的值是随机的。 这时一定不能去读写指针变量指向的地址,因为那个地址是随机地址,很可能会导致严重后果。
int* p;
*p = 1; // 错误
上面的代码是错的,因为p指向的那个地址是随机的,向这个随机地址里面写入1,会导致意想不到的结果。
正确做法是指针变量声明后,必须先让它指向一个分配好的地址,然后再进行读写,这叫做指针变量的初始化。
int* p;
int i;
p = &i;
*p = 13;
上面示例中,p
是指针变量,声明这个变量后,p
会指向一个随机的内存地址。 这时要将它指向一个已经分配好的内存地址,上例就是再声明一个整数变量i
,编译器会为i
分配内存地址, 然后让p
指向i
的内存地址(p = &i;)
。完成初始化之后,就可以对p
指向的内存地址进行赋值了(*p = 13;)
。
为了防止读写未初始化的指针变量,可以养成习惯,将未初始化的指针变量设为NULL
。
int* p = NULL;
NULL
在 C 语言中是一个常量
,表示地址为0的内存空间
,这个地址是无法使用的,读写该地址会报错。
例子
#include<iostream>
using namespace std;
void test(int *p)
{
int a=1;
p=&a;
cout<<p<<","<<*p<<endl; // 输出 0x22ff44,1
}
int main(void)
{
int *p=NULL;
test(p);
if(p==NULL)
cout<<"指针p为NULL"<<endl; // if中的p == null, 输出 指针p为NULL
system("pause");
return 0;
}
重点在p为什么是null? 事实上,在main函数中声明了一个指针p,并赋值为NULL,当调用test函数时,事实上传递的也是地址,只不过传递的是指针地址。 也就是说将指针作为参数进行传递时,事实上也是值传递,只不过传递的是地址
。 当把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参, 即上面程序main函数中的p为何与test函数中使用的p不是同一个变量
,存储2个变量p的单元也不相同(只是2个p指向同一个存储单元), 那么在test函数中对p进行修改,并不会影响到main函数中的p的值。