指针
在c语言中,我们会频繁的使用指针,那么什么是指针?首先我们来看一段代码。
#include <stdio.h>
int main()
{
int a = 10;//在内存中开辟一块空间
int *p = &a;//将a的地址存放在指针变量p中
return 0;
}
假如创建的变量a的地址为0x0000ff11,那么指针变量指向变量a,存放的是变量a的地址。
总结:指针就是地址,指针变量是变量,指针变量是用来保存地址的变量。存放在指针变量中的值都会被当做地址来处理。在32位机器上指针变量的大小为4个字节,在64位机器上指针变量的大小为8个字节。
指针数组
指针变量也是变量,那么就可以像创建整型数组一样,创建一个指针组。首先指针数组是数组,在这个数组内的元素的类型为指针。如下所示定义了一个数组p,p的元素类型为int *,即该数组的每个元素为指向整型的指针。
int *p[10];
数组指针
int (*p)[10];
()的优先级比[]高,因此p先与*结合,p为一个指针,指向的是一个包含10个整型变量的数组,所以p是一个指向数组的指针,叫数组指针。那么数组的地址如何存放?
int arr[10] = {0};
int *p1 = &arr;
int (*p2)[10] = &arr;
int (*p3)[10] = arr;
&arr表示整个数组的地址,arr表示数组首元素的地址。显然,p1为整型指针,p2、p3为数组指针。在c语言中,“=”两边的类型必须相同。
p1左边是整型指针,右边是指向数组的指针,两边的类型不同,变量p1不能用来存放数组的地址。
p2两边都是指向数组的指针,可以用来存放数组的指针。
p3左边为指向数组的指针,右边为指向数组首元素的指针,两边类型不同。
因此p2用来存放数组的地址比较合适。
函数指针
函数指针,从字面意思理解就是一个指针,这个指针指向的是一个函数。先来看一段代码。
#include <stdio.h>
void test()
{
printf("test\n");
}
int main()
{
printf("%p\n",test);
printf("%p\n",&test);
return 0;
}
函数名代表地址,和&函数名相同,函数名具有只读属性。那么函数的地址怎么保存?
char *(*pfun1)(char *p1,char *p2);
char **pfun2(char *p1,char *p2);
char *pfun3(char *p1,char *p2);
显然,pfun3是函数名,该函数有两个char *类型的参数p1和p2,返回值为char *类型。
pfun2这个表达式与pfun3表达式很相似,唯一不同的是pfun2的返回值为char**类型。
在这里pfun1不是函数名,它是一个指针变量,指向的是一个函数,该函数的返回值为char *类型,函数有两个参数p1和p2其类型为char*。
(*(void(*)())0)();
void (*signal(int,void(*)(int)))(int);
代码1:void(*)()为函数指针类型,(void(*)())0将0强转为函数指针,*(void(*)())0对函数指针解引用得到函数,(*(void(*)())0)()调用该函数。因此,代码1实现的是函数调用。
代码2:首先signal为函数;函数的参数有两个,第一个是int类型,第二个是函数指针,该函数指针指向的函数有一个整型参数,返回类型为void;signal函数的返回类型为函数指针,该指针指向的函数有一个int类型的参数,返回值为void。
代码2太过复杂,不便于阅读,我们可以对其进行简化。我们可以将重复使用的void(*)(int)函数指针类型重定义,这样可以使代码更易阅读。
typedef void (*pfun_t)(int);
pfun_t signal(int,pfun_t);
指向函数指针数组的指针
指向函数指针数组的指针是一个指针,该指针指向的是一个数组,这个数组的元素类型为函数指针。这个知识点我们平时不太用,只要了解、认识即可。
void test(int x)
{
printf("%d\n",x);
}
int main()
{
//定义一个函数指针pfun,该函数的返回值类型为void,有一个参数,参数类型为整型
void (*pfun)(int) = test;
//定义一个函数指针数组pfunArr[10]
void (*pfunArr[10])(int);
//函数指针数组的第一个元素指向函数指针pfun
pfunArr[0] = test;
//定义一个指向函数指针数组pfunArr的指针ppfunArr
void (*(*ppfunArr[10]))(int) = &pfunArr;
return 0;
}