目录
一、字符指针变量
二、数组指针变量
三、二维数组传参的本质
四、函数指针变量
五、typedef 类型重命名
六、函数指针数组
一、字符指针变量
我们常见的字符指针变量是这样的:
char a = 'w';
char* p = &a;
char arr[] = "abcd";
char* pa = arr;
很容易理解,但字符指针变量还有另一种形式:
char* pc = "abcdef";
printf("%c\n" ,*pc);
printf("%s\n" , pc);
"abcdef" 是常量字符串,本质上 pc 中存放的是首字符 a 的地址,从中我们也可以看出,%c 要的是变量。而%s 要的是地址
二、数组指针变量
数组指针变量不是指针数组,数组指针变量重点放在指针上,意思是存放的是数组的地址,能够指向数组的指针变量。
语法形式:
int arr[10] = {0};
int (*p)[10] = &arr;
其中,p是数组指针的名字,int (*)[10] 就是该数组指针变量的类型
注意:因为[ ]的优先级高于 * ,所以要给 * 带括号,10 代表着 p 指向数组的元素个数
要想通过数组指针来遍历数组也很简单:
for(int i = 0; i<10;i++)
{
printf("%d " , (*p)[i]);
}
三、二维数组传参的本质
二维数组传参,形参可以写成二维数组的形式,那么还有没有其他形式呢?
二维数组的首元素其实是他的第一行,数组名表示首元素的地址,也就是第一行的地址
所以二维数组传参也可以写成指针的形式:
void Fun_arr(int (*p)[10] ,int m)
{
//........
}
把每一行看做一个数组,再把指针数组传过去就可以了
四、函数指针变量
函数指针变量就是存放的是函数地址的变量。
我们可以先写一个加法函数:
int Add(int x,int y)
{
return x+y;
}
你现在可以尝试以下打印函数的地址:
printf("%p\n" ,&Add);
printf("%p\n", Add);
这证明,函数名也是一个地址,那么需要存放这个函数地址,就需要用到函数指针变量了
语法形式如下:
int (*pf)(int, int) = &Add;
那么,如何通过函数指针来调用函数呢,很简单:
int s = (*pf)(10,20);
好了,下面我们来看一道很绕的题目:
(*(void(*)())0)();
这其实是一个函数声明。
五、typedef 类型重命名
C语言类型有整型,字符型,无符号整型等等,但是无符号整型 unsigned int 太长了,每次使用很不方便,又或者是方便元素类型修改,我们可以对类型重命名
语法形式如下:
typedef unsigend int uint;
这里说明以下:
typedef int* pint;
int* a,b;
pint* c,d;
第一行,a是指针,但b只是一个整型变量;第二行的c和d都是指针
当然,你也可以对数组指针,函数指针重定义:
typedef int(*parr_t)[10];
//parr_t就是数组指针类型了
int (*p1) = &arr;
parr_t p2 = &arr;
//二者效果是一样的
要值得注意的是,重命名后的名字不能再放到最后面了,而是要放在(*)里,同理,函数指针也是如此。
typedef int(*pf_t)(int,int);
//pf_t就是函数指针类型了
int (*pf)(int ,int) = &Add;
pf_t pf2 = &Add;
//二者效果是一样的
六、函数指针数组
函数指针数组就是用来存放函数指针的数组
例如:
int (*parr[])(int,int) = {Add,Sub,Mul,Div};
需要注意的就是函数指针的类型是把名字去掉后的那部分:int (*)(int,int)