提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
指针进阶讲解
提示:以下是本篇文章正文内容,下面案例可供参考
一、指针是什么?
二、指针的分类
1.字符指针
在指针的类型中我们知道有一类指针类型为字符指针——char* ;
一般的使用:
int main()
{
char ch='w';
char* pc=&ch;//pc为字符指针
*pc='w';
return 0;
}
在这里pc就是字符指针
当然,这里还有另外一种写法:
int main()
{
const char *pstr="hello bit ";//这里是把一个字符串放入了pstr中了吗?
printf("%s\n",pstr);
return 0;
}
在这里有大部分的同学都会认为我们是把hello bit 放入了字符指针中,但是本质上是把字符串hello bit 的首位字符的地址放到了字符指针pstr中。
当然还有一些同学会将const省略掉,当然我们最好不要讲其省略掉,在这里的字符串hello bit是常亮字符串,是存储在内存的静态区的,它的地址是不变的,所以我们需要加一个const来修饰指针pstr。请一定要注意,这里的const所修饰的是*pstr,而不是pstr。
在这里的输出结果是什么呢?
我们来进行分析:
首先我们讲字符串hello bit 放入了字符数组str1和str2,同时我们将字符串的首个元素的地址放入了字符指针str3和str4中,在这里我们需要判断的条件是str1与str2是否相等,首先我们需要明白这里的str1和str2代表的意义是什么,我们在指针的初级讲解的时候说过,数组的名字代表了数组的首元素地址,而这里的两个数组中放入的内容都是hello bit 那么结果是相同吗?不,并不是,请同学们仔细看,我们将hello bit 放入了两个数组中,在这里我们是开辟了两个空间,也就是这两个数组的空间,那么,两个不同的空间的地址会相同吗?所以这里的答案是不同。 第二个所需判断的条件是str3和str4是否相等,在这里str3与str4所代表的是什么?你是否明白,这里我们是将hello bit 放入字符指针str3和str4中,str3和str4代表的是其首元素的地址,那么可能有人要说了,这里的结果肯定是不一样,这不跟上一个条件是一样的嘛。那么我告诉你,错了,我们来看看,这里我们到底是将什么放入了str3和str4,看好了,这里的str3和str4都代表指针,所以放入的内容肯定是指针,这里我们放入的是常量字符串,而常量字符串是在静态区是不能改变的,所以,电脑也就没有再拷贝一个字符串,就只留一个,所以str3和str4所指向的是同一个地址,所以str3==str4
2.指针数组
指针数组是什么?
指针数组就是一个存放指针的数组。
我们来类比一下,我们知道有整形数组,字符数组,其对应的就是存放整形的数组,存放字符的数组,那么指针数组就是存放指针的数组,
int main()
{
int* p[10];//整形指针数组
char*p[10];//一级字符指针数组
char**p[10];//二级字符指针数组
return 0;
}
这里我们来使用指针数组来模拟实现二维数组
这里的指针数组下标就代表了一维数组arr1 ,arr2,arr3,而一维数组中还有各自的元素 ,这样就模拟了二维数组,但是这并不是真正的二维数组,请大家记住,我们这是模拟实现二维数组。
3.数组指针
数组指针是数组还是指针?
答案是:指针
我们已经了解了
整形指针:也就是指向整形 变量的指针,存放整形变量地址的指针
字符指针:指向字符变量的指针,存放字符变量地址的指针
那么数组指针不就是指向了数组的指针,存放的是数组的地址
我们来简单的分析一下:
int *p1[10];
int (*p2)[10];
//哪一个是数组指针
我们首先分析第一行,int *p1[10],方括号[]的优先级高于*,所以p1先和方括号结合,而p1与方括号结合之后,p1就变成了数组,*就和int结合,变成了数组的类型,也就是指针,所以第一行是指针数组,第二行,*和p2被括号包围,所以p2与*结合,p2变成指针,这时int与[10]结合变成整形数组 ,所以第二行是数组指针。
讲到这里了,大家可能会有点晕,最为方便的辨识方法呢,就是看p1,p2,你只需要观察它们到底是与谁结合,变成了什么,而余下的就是它们的类别。
那么,我们如何使用数组指针呢?
以前,我们在使用二维数组时,所传的形参,写的是数组,但是实际却是指针,那么,当我们学习了数组指针后,我们就能更为深入的理解二维数组传参。
比如说我们想要实现打印二维数组的函数:
void Printf(int(*arr)[4], int r, int c)
{
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < 4; i++)
{
printf("%d", (*(arr + j))[i]);
}
printf("\n");
}
}
int main()
{
int arr[2][4] = { 1,2,3,4,5,6,7,8 };
Printf(arr, 2, 4);
return 0;
}
3.函数指针
我们在经过上面的学习后知道了数组指针是代表了指向数组的指针,那么函数指针就是指向函数的指针。
我们来看下面的代码:
从这段代码中我们可以看出Add函数的函数名和&Add的效果是一样的,所得到的结果都是相同。
所以我们可以得出结论,函数的函数名具有和数组名一样的效果,都代表了自己的地址。
那么函数指针的基本格式是什么呢?
这里的pf就是函数指针,我们通过将Add的函数地址交给pf,然后将Add函数运算的结果给m,然后打印出m的值。
当然有了解的同学可能知道,m中,(*pf)(4,5)可以写成pf(4,5),这是为什么呢?
来看看,当我们将Add的地址放入了pf之后,此时的pf是不是就相当于Add,我们可以通过地址来直接调用函数,那么我们是不是可以直接通过pf来实现函数的使用,所以这就是原因。
接下来 我们来看一段代码:
(*(void(*)())0)();
这里看着是不是很复杂,这里我们需要从0开始入手,void(*)()是函数指针类型,而在0前面加上类型,就是强制转换,这里将0强制转换成函数指针类型,然后在进行解引用。
总结
到这里,我们总共讲了不少的内容了,本篇讲解了一下指针的理解,但大家还是要多上手练习一下,听和写是两件事情。