1. 指针是什么?
指针理解的 2 个要点:
1. 指针是内存中一个最小单元的编号,也就是地址(&)
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
总结:指针就是地址,口语中说的指针通常指的是指针变量。
那我们就可以这样理解:
内存(如图所示):
1.1指针变量
我们可以通过
&
(取地址操作符)取出变量的内存起始地址,把地址可以存放到一个变量中,这个
变量就是指针变量
![int main() { int a = 10;//在内存中开辟一块空间 int* p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。 //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量 //中,p就是一个之指针变量。 return 0; }](https://i-blog.csdnimg.cn/direct/03041f505a674d46ae9b59a7a5e150d8.png)
总结:
指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
2. 指针和指针类型
我们都知道,在c语言中变量有不同的类型,整形,浮点型等。那指针有没有类型呢?准确的说:有的!
当有这样的代码:
int num = 10 ;p = & num ;
要将
&num
(
num
的地址)保存到
p
中,我们知道
p
就是一个指针变量,那它的类型是怎样的呢?
我们给指针变量相应的类型。
char * pc = NULL ;int * pi = NULL ;short * ps = NULL ;long * pl = NULL ;float * pf = NULL ;double * pd = NULL ;
这里可以看到,指针的定义方式是:
type + *
其实:
char*
类型的指针是为了存放
char
类型变量的地址。
short*
类型的指针是为了存放
short
类型变量的地址。
int*
类型的指针是为了存放
int
类型变量的地址。
那指针类型的意义是什么?
2.1 指针+-整数
总结:
指针的类型决定了指针向前或者向后走一步有多大(距离)
2.2 指针的解引用
![](https://i-blog.csdnimg.cn/direct/4ad24a5534a3401d873bb9995f6bfd82.png)
总结:
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)
比如:
char*
的指针解引用就只能访问一个字节,而
int*
的指针的解引用就能访问四个字节。
3. 野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
3.1 野指针成因
1. 指针未初始化
![](https://i-blog.csdnimg.cn/direct/a8710b3782504f1d9ef05d8c670f6a10.png)
注意:在vs2022上是打印不出来随机值的,在Dev,小熊猫编译器上可以打印出随机值 知道即可!
2. 指针越界访问
![](https://i-blog.csdnimg.cn/direct/e84388988f634411a023bf25e82a8889.png)
如图所示,超出了数组的范围,就找不到啦!!!
3.2 如何规避野指针
1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放,及时置
NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性
![](https://i-blog.csdnimg.cn/direct/fa73536bbe0a4da9a19f17c8648984eb.png)
4. 指针运算
-
指针 +- 整数
-
指针 - 指针
-
指针的关系运算
4.1 指针+-整数
#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}
4.2 指针-指针
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s;
}
4.3 指针的关系运算
for(vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}
代码简化
,
这将代码修改如下:
for ( vp = & values [ N_VALUES - 1 ]; vp >= & values [ 0 ]; vp -- ){* vp = 0 ;}
实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证 它可行。
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与 指向第一个元素之前的那个内存位置的指针进行比较。
5. 指针和数组
看一个示例:
看到运算结果,我们可想而知
可见数组名和数组首元素的地址是一样的。
结论:
数组名表示的是数组首元素的地址
。
那么这样写代码是可行的:
int arr [ 10 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 };int * p = arr ;
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。
例如:
#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr)/sizeof(arr[0]);
for(i=0; i<sz; i++)
{
printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i);
}
return 0;
}
运算结果如下:
所以
p+i
其实计算的是数组
arr
下标为
i
的地址。
那我们就可以直接通过指针来访问数组。
如下:
![](https://i-blog.csdnimg.cn/direct/b7c953453f60416283c60c17dfce37a5.png)
6. 二级指针
想一个问题:
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
想到了嘛?
这就是
二级指针 !
如图所示:
![](https://i-blog.csdnimg.cn/direct/c6cd25f27d5b4320ae97d51c1539d5d8.png)
看图得出,
a的地址存放在*pa里面,*pa的地址存放在**ppa中
对于二级指针的运算有:
*ppa
通过对
ppa
中的地址进行解引用,这样找到的是
pa
,
*ppa
其实访问的就是
pa
.
int b = 20 ;* ppa = & b ; // 等价于 pa = &b;
**ppa
先通过
*ppa
找到
pa
,
然后对
pa
进行解引用操作:
*pa
,那找到的是
a
.
** ppa = 30 ;// 等价于 *pa = 30;// 等价于 a = 30;
懂?
7. 指针数组
指针数组是指针还是数组?
答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组。
int arr1 [ 5 ];char arr2 [ 6 ];
![](https://i-blog.csdnimg.cn/direct/9f2dd7cf8039457e9cd9dbf10ee9870c.png)
那指针数组是怎样的?
int* arr3 [ 5 ]; // 是什么?
arr3
是一个数组,有五个元素,每个元素是一个整形指针。
![](https://i-blog.csdnimg.cn/direct/8c8c71b85c644a4f84e31d6759cdb37e.png)
数组指针详情待下篇分享!!
本篇文章到此就结束啦!
小磊在此问候大家 还请各位大佬三连!!!丞退了
![](https://i-blog.csdnimg.cn/direct/4a6b48742e5f4d99859db7c2212cca41.webp)