1.指针的基本运算
指针的基本运算有三种:
1.指针+-整数
2.指针-指针
3.指针的关系运算
1.1针+-整数
我们在上篇已经说过这里就不再详细的进行说明,这里只说一个重要的点,当指针进行+-整数的时候,它所访问的空间就会跳过,指针类型所对应的字节乘以整数个字节。举个例子:
# include<stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
int *p = &arr[0];
for(i = 0;i < sz;i++)
{
printf("%d",*(p+i));
}
}
这里的p+i就是当i=1的时候p跳过4个字节那么*p就是2
1.2指针-指针
拿上面的例子来说指针1+1 == 指针2 指针1+5 == 指针2.那么指针2 - 指针1 == 5
所以根据上面我们可以得指针减去指针得到的就是指针和指针之间的元素个数 这里再给举个例子:
这样打印出来是9和-9懂了没有,但是指针 - 指针的前提是两个指针指向了同一块空间。
那为什么要弄明白指针之间的减法运算呢?别急接下来就明白哦:
假如有一个字符串,想求这个字符串的长度怎么办?这里给个简单的代码
用strlen这个库函数就可以求字符串的长度这里的“长度”指的是字符数组中存储的字符数量。但是这个你要包含头文件就是#include<string.h> strlen求字符串长度时候,统计是\0之前的字符个数,就是这样 a b c d e f \0一共六个。arr的数组内容就是这样的。
但是如果我们能拿到a前面的地址的话p = &a,那么我们将p解引用就是a这个字符当*p不是\0的时候p++就像下面的这串代码:
这串代码的结果也是6,那还有其它的办法吗?有的,就是我们刚说的指针 - 指针还是arr这个数组里面的内容是a b c d e f \0如果我们知道a的地址还知道\0的地址用这两个相减不就是这个中间的字符个数嘛。
代码如下:
这就是我们所说的指针 - 指针的作用
1.3指针关系运算
什么是指针关系运算?指针的关系运算就是两个指针比较大小,那这里给用一下
这里的p < arr + sz 就是使用了指针关系运算。
2.野指针
2.1野指针成因
1.指针未初始化:
2.指针越界访问
当指针指向的范围超出数组arr的范围时,p就是野指针。
这里的i<=11导致*(p++)=i的范围超出数组arr
3.指针指向的空间释放
这里通俗讲一下:因为内存栈区原因变量是不断创建和销毁的,栈用来存储函数内部的变量(包括main()函数)。每当一个函数声明一个新的变量它将被压入栈中。当一个函数运行结束后,这个函数所有在栈中相关的变量都将被删除,而且它们所占用的内存将会被释放。这就产生了函数内部的局部变量。
这里就会用到这点知识:main函数想要调用这个tes,就会向上调用这个test函数,在这个test函数里面创建了一个局部变量n,但这个局部变量n会在出这个函数的时候就销毁。这里把n赋值为100,然后返回&n,这个地址能不能带回main函数吗?能,n的的地址是0x0012ff40带回main函数把他存到p这个指针变量里面去这是p里面存的地址就是n的地址,但是n在完成之后出了这个函数就会销毁这时n的地址也就销毁了。但是如果printf还想通过p里面的地址去解引用访问这个空间那肯定就是不行了,因为这个空间再出这个函数的时候就销毁了,找不到了,这就是指针指向的空间释放。
2.2如何规避野指针
2.2.1指针初始化
一定要明确指针的地址,如果明确知道指针指向哪里就直接赋值地址,如果不知道指针应该指向哪里可以给指针赋值NULL 。
NULL是C语言中定义的一个标识符,值是0,0也是地址,这个地址是无法使用的,读写该地址会报错。
这就是初始化:
#include <stdio.h>
int main()
{
int num = 10;
int*p1 = #
int*p2 = NULL;
return 0;
}
2.2.2 小心指针越界
这个就是指针越界访问形成野指针,要保证指针不能越界就行 。倒是没啥可说的。
2.2.3避免返回局部变量地址
这个其实也是形成野指针的第三个问题,根据问题找解决方案。
2.2.4指针变量不再使用时,及时置于NULL,指针使用之前检查有效性
当指针变量指向一块区域的时候,我们可以通过指针访问这块空间,后期如果不访问这块空间了就可以把指针置为NULL,如果下次要用的话还必须要让指针变量重新访问地址并且还要判断是否为NULL。
,
每篇小结:
这便是今天所学习内容,有所收获,再接再厉!!!