指针的声明
int j = 49;
int *i = &j;
# 更好的声明方式
int* i = &j;
只要声明的时候,加了*
号,这个变量就是指针变量
,比如这个 i 就是一个指针类型的变量
,而不是一个int类型的变量
那这个int在这里的作用是什么?
先说结论:这个int,表明了从指针指向的头地址开始,需要往后取多少位长度的数据。
我们首先要知道,各个基础类型,都有自己的长度,如int型是32位,long型是64位。而指针类型也有自己的长度,它的值存放的是一个内存地址,即寻址长度。在32位系统中,指针类型的长度是32;在64位系统中,指针类型的长度为64。
由于指针存放的是一个内存地址,它指向的是内存中的某个比特位,即所谓的头地址。如果单看头地址的这个比特位,并没有什么实际意义,因为它只能包含0/1两种信息。而int* i
这样声明指针类型的话,实际是在指导机器不止要看头地址,而且还要往后取32位,才能完整的把int类型的数据取出来。总结来说,单纯的指针类型变量只包含了某个内存地址(头地址)指向的那一个bit的信息,并无实际意义,只有带上具体的类型,指针类型变量才具有意义。
指针的使用
假如当前声明了一个指针变量int* i
,一个普通变量int j
i
表示内存地址,类型为指针类型
*i
表示真正的数据,类型为具体声明的类型,如int
&j
表示变量 j 的内存首地址,类型为指针类型
&
也可以用在指针类型上,如:&i
得到的是指针类型的
变量i
的内存首地址
示例:
cout << i
可以的得到指针变量
对应的值(即某内存地址)cout << *i
可以可以得到真正的数据,通过头地址+类型长度
获取
指针类型变量存在栈中还是堆中
指针类型的变量,以int* i
为例,它可能存在于方法栈的内存空间中,也可能存在堆空间中(通过malloc函数)。
为什么要有堆内存?
局部变量在方法栈中分配空间,当方法执行结束、方法栈弹出之后它也会跟着被清除。此时哪怕把局部变量的指针返回出去,外部拿到的指针对应的值也是空的。只有在堆中分配的内存空间,才不会随着方法结束出栈而被清理,此时对应的指针在外部就依然能够正常获取数据。
堆内存的局限在于需要开发者手动回收,不然程序长时间运行可能会导致内存溢出。当然很多语言自带的GC也是一种优雅手段。
#include <iostream>
int* b();
int main(){
int j = 43;
int* i;
std::cout << "hello world" << std::endl;
i = b();
std::cout << i<< std::endl;
std::cout << *i<< std::endl;
for (int z = 0; z < 100; z++)
{
/* code */
}
std::cout << i<< std::endl;
}
int* b(){
int j = 49;
// int* i = &j;
int* i = (int*)malloc(1);
*i = 256;
std::cout << "in b:" <<*i<< std::endl;
return i;
}