本篇主要介绍一下数组指针、指针数组、函数指针数组和指向函数指针数组的指针。希望能和大家一起学习,互相交流。(所讲内容的操作均在32位系统下进行)
指针数组:形如:int *p1[5];(p1为数组名)
首先我们要知道“[ ]”的优先级比“ * ”高,现在,我们不难理解,p1先与“[ ]”结合构成一个数组,然后在与“ * ”结合,说明数组的元素是指针类型,最后与“ int ”结合,说明指针指向的内容是int型的;因此,p1是一个由返回int型数据的指针所构成的数组。
数组指针:形如:int(*p2)[5];
p2先与“ * ”结合,说明p2是一个指针,再与“[]”结合,说明该指针指向一个数组,最后与“int”结合,说明,该数组的元素为整型;因此,p2是一个指向由5个int类型数据组成的数组的指针。
举个例子:
int main()
{
int arr[5] = {1,2,3,4,5};
int(*p1)[5] = &arr;
int(*p2)[5] = arr;
printf("%p\n",p1);
printf("%p\n", p2);
printf("%d\n",**p1);//使用指针
system("pause");
return 0;
}
输出结果:
我们可以看到p1和p2的值是一样的,但是要注意的是,虽然两个结果相同,但是它们的意义是不同的,p1是指向整个数组的地址,而p2是指向数组的首元素地址;
我们再看看编译的结果:
可以发现,对于int(*p2)[5] = arr;“=”左边的类型是指向整个数组的指针,“=”右边的类型是指向一个元素的指针。所以我们在使用的时候需要注意。(一会儿在文章最后,我会为大家总结一下怎样辨别指针的类型和指针所指向的类型)
函数指针:形如:char* (*fun)(char* str1);(这是返回值类型为char*类型)
“*fun”表示这是一个指针,再与“ ()”结合表示该指针指向一个函数,这个函数参数为str1,且返回值类型为char*。
举个简单的例子:
#include<stdio.h>
#include<stdlib.h>
char* test1(char* str1)
{
return str1;
}
char* test2(char* str2)
{
return str2;
}
int main()
{
char* (*fun)(char *str);
char *str1 = "hello girl!";
char *str2 = "hello boy!";
//fun = test1;
fun = &test1;//函数名可以做地址或者也可以 &+函数名,这两种写法一样
printf("%s\n",(*fun)(str1));
fun = test2;
printf("%s\n", (*fun)(str2));
system("pause");
return 0;
}
测试结果:
接下来再看几个例子:
A) char* (*fun1)(char* p1,char* p2);
B) char* *fun2(char* p1,char* p2);
C) char* fun3(char* p1,char* p2);
B) char* *fun2(char* p1,char* p2);
C) char* fun3(char* p1,char* p2);
大家可以尝试着分析。
对于C,首先这是一个函数,该函数有两个char*类型的参数p1,p2,函数返回值类型为char*;
对于B,fun2也是一个函数,相较于C而言,唯一不同的是fun2的返回值类型为char**;
对于A,要注意的是fun1它不是函数名,它是一个指针变量,该指针指向一个函数,该函数有两个char* 类型的参数
该函数的返回值类型也是一个char* 。
还有这样一段代码:
#include<stdio.h>
#include<stdlib.h>
void Function()
{
printf("hello girls!\n");
}
int main()
{
void (*p)();
*(int*)&p = (int)Function;
(*p)();
system("pause");
return 0;
}
运行结果:
首先定义一个函数指针p,p指向一个函数,该函数无参且返回值类型为void;
(int)Function是将这个函数的入口地址强制转化为一个int类型的数据;
&p是获取指针p本身的地址,然后(int *),将其强制转化为一个指向整型数据类型的指针;
再将这个整型数据赋值给这个指针;
那么(*p)(),就是表示对函数的调用;
最后再看一个例子:(*(void(*) ())0)()
分析一下:①void(*)(),首先这是一个函数指针类型,该函数无参且无返回值;
②void(*)()0,这是将0强制转化为函数指针类型,0成为了一个地址,换句话说有一个函数存在了首地址为0的一段内存区域中;
③(*(void(*) ())0)表示取得这段内存区域的内容,也就是获得保存在该地址中的函数;
④
(*(void(*) ())0)(),表示函数调用。
函数指针数组:形如:char* (*pf[3])(char* p);
首先明白这是一个数组,pf是数组名;数组里存储了三个元素,每个元素是一个函数指针,指针指向了一个函数,该函数的参数为char* 类型,返回值也为char*。
我们可以用它和函数指针做个比较:
函数指针
:char* (*pf)(char* p);现在我们要把它存储在数组里,这样就变成了char* (*pf[3])(char* p);
举个例子:
#include<stdio.h>
#include<stdlib.h>
char *fun1(char* p1)
{
printf("%s\n",p1);
return p1;
}
char *fun2(char* p2)
{
printf("%s\n", p2);
return p2;
}
char *fun3(char* p3)
{
printf("%s\n", p3);
return p3;
}
int main()
{
char* (*pf[3])(char* p);//定义一个函数指针数组
pf[0] = fun1;//将函数地址存入数组中
pf[1] = fun2;
pf[2] = fun3;
pf[0]("hello girl!");//函数调用
pf[1]("hello boy!");
pf[2]("hello bit!");
system("pause");
return 0;
}
运行结果:
函数指针数组的指针:形如char* (*(*pf)[3])(char* p);
这里的
pf是一个指针,
指针指向了一个包含了三个元素的数组,元素是一个函数指针,指针指向了一个函数参数类型为char* ,返回值为char* 的函数。
再把它和函数指针数组做比较:
函数指针数组:char* (*pf[3])(char* p);那么函数指针的数组的指针,就要加一个“ * ”,即char* (*(*pf)[3])(char* p);
举个例子:
#include<stdio.h>
#include<stdlib.h>
char *fun1(char* p1)
{
printf("%s\n", p1);
return p1;
}
char *fun2(char* p2)
{
printf("%s\n", p2);
return p2;
}
char *fun3(char* p3)
{
printf("%s\n", p3);
return p3;
}
int main()
{
char* (*pf[3])(char* p);//定义一个函数指针数组
char* (*(*ptr)[3])(char* p);//定义一个函数指针数组的指针
//将函数地址存放于数组中
pf[0] = fun1;
pf[1] = fun2;
pf[2] = fun3;
ptr = &pf;//将函数指针数组的地址存放于指针中
//使用函数指针数组指针进行函数访问,接着进行函数调用
//第一种使用数组下标访问
ptr[0][0]("hello girl!");
ptr[0][1]("hello boy!");
ptr[0][2]("hello bit!");
//第二种指针访问
(*(*ptr + 0))("hello girl!");
(*(*ptr + 1))("hello boy!");
(*(*ptr + 2))("hello bit!");
system("pause");
return 0;
}
测试结果:
接下来为大家分享一下我自己辨别指针类型和指向指针类型的方法,希望能为大家带来帮助:
指针类型:
①int* ptr;指针的类型是int*;
②char* ptr;指针的类型是char*;
③int** ptr;指针的类型是int**;
④int (*ptr)[3];指针的类型是int (*)[3];
指针所指向的类型:
①int* ptr;指针所指向的类型是int;
②char* ptr;指针所指向的类型是char;
③int** ptr;指针所指向的类型是int*;
④int (*ptr)[3];指针所指向的类型是int ()[3];
希望这篇文章能为大家带来帮助,如果有错误的地方欢迎指正,大家一起交流学习!