一,什么是指针
指针就是地址,是内存中最小单元的编号。内存中最小单元的大小是一个字节,八个比特位。
这里需要注意的是,指针就是地址(是由十六进制组成),而口语上我们经常说到的指针是指针变量。
指针的大小是由平台决定的,32位平台是4个字节大小,64位平台是8个字节大小。
32位就是指计算机中有32根物理线,通过高电压和低电压,实现1和0。
那么就有
00000000000000000000000000000000
00000000000000000000000000000001
......
11111111111111111111111111111111
一共有2^32中排列方式,所以就有这么多的地址编号。
而一个地址编号是由32个1或0组成的,就相当于32个比特位。32/8=4
所以一个地址的大小位4个字节。
64位平台同理
二,指针和指针类型
上面讲到,指针的大小都是一样的,那么还需要类型吗???
当然需要,指针类型的意义并不在于指针本身的大小。
1,决定了指针向前或者向后走一步有多大(移动一下,跨过几个字节)
如:
int* a;
char* b;
a+1//从该地址向后移动四个字节
b+1//从该地址向后移动一个字节
2.在解引用的时候,决定了能访问多大的权限
如:
int* a;//a解引用能访问4个字节
char* b;//b解引用能访问1个字节
注意:
int* a=100;
float* a=100.0;
虽然int* 和float*都是解引用后引用4个字节,+1都是跳过4个字节。
但是这两个不能通用。
因为int* a=100;//是以整型的形式存入的,
float* a=100.0;//是以浮点型的形式存入的。
解释:指针变量的大小和它指向的内存空间大小的关系。
没有关系,它指向的内存空间的大小和指针变量的类型有关,和它本身的大小(即它自身编号的大小)没有关系。
三,野指针
概念:就是指针指向的位置是不可知的。(随机的,不正确的,没有明确限制的)
成因:
1,指针未初始化
如:int* p;//未初始化
*p=10;//给未初始化的指针变量赋值
2,越界访问
int arr[10]={0};
for(int i=0;i<=10;i++)//下标索引超出数组的范围
{
arr[i]=i;
}
3,指针指向的空间释放
int* test()
{
int a=10;//创建临时变量并赋值
return &a;//返回临时变量的地址,并且系统将消除a并且回收a所占用的内存
}
int main()
{
int* p=test();//调用test()函数
printf("%d",*p);//因为内存的编号不会改变所以地址还是当时a的地址,但是该地址的原来的内容不存在了。
return 0;
}
避免野指针的出现
1,初始化:如果确定初始化的值时,一定要初始化。如果不确定,将指针设置为空指针如:int* a=NULL。注意:空指针没有空间,没有访问权限。在int*aNULL的前提下,进行*a=10;这样是错误的。
2,小心指针越界
3,指针指向空间释放时,要及时设置NULL
当不再需要使用通过动态分配得到的内存时,应该使用 free
函数释放内存,并将指针置为 NULL
,以防止出现野指针。
4,避免返回局部变量的地址
5,指针使用前检查有效性
四,指针运算
1.指针+ - 整数
通过给数组每个元素都赋值的例子来理解
int arr[10]={0};
int* p=arr; //数组名就代表数组首元素地址
sz=sizeof(arr)/sizeof(arr[0];
for(int i=0;i<sz;i++0
{
*p++=1;//先*p=1,再p++ 等效于*(p++)=1;
}
2.指针 - 指针
两者相减的绝对值就是两者之间元素的个数。(不是所有的指针都能相减,只有指向同一块空间的才能相减)
int arr[10]={0};
printf("%d",&arr[9]-&arr[0]) //打印出来的是9
printf("%d",&arr[0]-&arr[9]) //打印出来的是-9
用法:可以计算字符串的长度
用“/0”的地址减去首元素的地址。
3.指针的关系运算(比较大小)
因为地址是按顺序排列的所以可以比较大小。靠后的地址为大。
注意:允许指向数组元素的指针与指向数组在最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
五,指针和数组
数组名和数组的首元素地址相同,把数组名当成地址放在指针中就能使用指针访问数组。
int* p;
int arr[10]={0};
p=arr;//指针初始化,就是把数组arr的首元素地址赋值给p
六,二级指针
二级指针是用来存放一级指针变量的位置的。
int a=0;
int* pa=&a;//pa是一级指针变量
int** ppa=&pa;//ppa是二级指针变量
引用和赋值
*pa=20;
**pa=20;
int * pa 中的 * 第一说明pa是指针变量,第二说明pa指向的对象是int类型
int* * ppa中的 * 第一说明ppa是指针,第二说明ppa指向的对象是int*类型
七,指针数组
存放指针的数组就是指针数组
int* a=1;
int* b=2;
int* c=3;
int* parr[10]={&a,&b,&c};
*(parr[0]);//解引用的a的值;parr[0]得到的是指针数组的第一个元素的值,即地址,在对地址解引用,就得到该地址的内容。