前言
了解了指针的基础知识,进阶一下~~~
1.字符指针
字符指针除了定义一个字符,把字符的地址存入字符类型的指针变量中这种简单的形式以外,还有一些较为复杂的形式。
我们通过一个题目来了解字符指针。
先看运行结果:
为什么会产生这样的结果???
有很多初学者会把3和4这种类型理解为把“hello pig”放入了str里,但是本质里是把首字符'h'的地址放入了str里,同时这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当 几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4不同。
2.数组指针
数组指针顾名思义就是数组类型的指针。
整型指针:int*指向整型数据的指针。
浮点型指针:float*指向浮点型数据的指针
那么举一反三:
int arr[10];int(*p)[10] = &arr;//数组指针的表示方法
//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。
数组指针的使用(一维数组和二维数组的遍历为例):
一维数组arr2存储的int型的数据,它的数组名传参作为地址就由int*的指针变量接收。在图中可以看到二维数组数组名传参由数组指针类型的指针变量接收。这里可以这样理解一维数组的数组名是数组的首元素地址(sizeof(arr)和&arr除外),那么二维数组的数组名则是第一行数组的地址,那么这样来看,二维数组的一行其实可以理解为一个一维数组,那么一行的数组就由数组指针来接收。
明白了这个知识,那对于图中的解引用就迎刃而解了。*(p+i)代表第几行,再+j就代表第几列。
3.函数指针
我们在编写的函数是存在地址的,如果想要存储函数的地址,我们应该怎么办呢???
这个时候我们就要用到函数指针。
类比数组指针
假设一个函数:
int Add(int x,int y);那么它的函数指针就是:
int (*p)(int ,int);
//解释:p先和*结合,说明p是指针,指针指向的是一个函数,指向的函数参数是两个int,返回值类型为int。
那么我们就可以用指针调用相应的函数:
4.函数指针数组
指针数组是存放指针的数组,那么函数指针数组如何定义?
int(*parr1)();//假设有10个相同类型的函数指针
int (*parr1[10])();//解释:parr1 先和 [] 结合,说明 parr1是数组,数组的内容是什么呢?
是 int (*)() 类型的函数指针。
函数指针数组的用途:转移表
案例(简单计算器):
5.指向函数指针数组的指针
有了上面的经验,这个东西就是指针。指针指向一个数组,数组存储元素类型是函数指针。
如何定义?void test(const char* str){printf("%s\n", str);}int main(){//函数指针pfunvoid (*pfun)(const char*) = test;//函数指针的数组pfunArrvoid (*pfunArr[5])(const char* str);pfunArr[0] = test;//指向函数指针数组pfunArr的指针ppfunArrvoid (*(*ppfunArr)[5])(const char*) = &pfunArr;return 0;}
6.回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
大白话就是在一个函数里利用其他函数传进来的地址,来调用其他函数。
我们俩看看qsort函数的使用:
我们可以看到qsort函数是用来排序的,传4个参数,第一个参数的类型是void*代表需要排序数组第一个元素的地址,第二个代表元素数量,第三个代表元素类型大小,它们的参数类型都是size_t,第四个是一个函数指针,返回值是int(>0代表前者大于后者=0代表等于<0代表小于)。举个例子:
那么我们可以试试自己实现一个qsort(排序部分用冒泡排序):
分享结束~