C语言深度解剖 (五)
原文链接: C语言深度解剖 (五)
前言
C语言的水深不见底,好在一些前辈们已经将很多雷区探了一遍
这里分享一下我在学习 《C语言深度解剖》 过程中的一些笔记和心得
概要
- TOC
{:toc}
数组参数与指针参数
C语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素的地址指针
数组 | 数组参数 | 指针 | 等效的指针参数 |
---|---|---|---|
数组的数组 | char a[3][4] | 数组的指针 | char (*p)[4] |
指针数组 | char *a[10] | 指针的指针 | char **p |
当数组超过一维时,将第一维改写为指向数组首元素首地址的指针之后,后面的维度也不可改写
比如 a[4][5][6]
作为参数时可以被改写为 (*p)[4][5]
函数指针
char *(*fun1)(char *p1,char *p2)
char **fun2(char *p1,char *p2)
char *fun3(char *p1,char *p2)
第一条是定义一个函数指针,此函数返回值为一个字符型指针
第二条是定义一个函数,此函数返回值为一个字符型的二级指针
第三条是定义一个函数,此函数返回值为一个字符型的指针
Tip: 对于函数指针
char (*fun)(char *p1,char *p2)
,可以这么理解char (*)(char *p1,char *p2) fun
,对于数组指针char (*p)[5]
也可以这么理解char (*)[5] p
char fun(char *p1,char *p2); //声明或定义函数
char (*pf)(char *p1,char *p2); //定义一个函数指针
pf=&fun; //给函数指针赋值,与函数绑定
(*pf)("xx","yy"); //使用指针来调用函数
*(int*)&p
函数指针与普通指针没什么差别,只是指向的内容不同而已
#include <stdio.h>
void function()
{
printf("Call Function!\n");
}
void main()
{
void (*p)();
*(int*)&p=(int)function;
(*p)();
}
使用函数指针的好处在于,可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期维护,系统结构更加清晰
便于分层设计,利于系统抽象,降低耦合度以及使接口与实现分开
(*(void(*)())0)()
void(*)()
函数指针类型
(void(*)())0
将0强制转换为函数指针类型
(*(void(*)())0)
取0地址开始的一段内存里面的内容
(*(void(*)())0)()
函数调用
函数指针数组
这是在定义一个函数指针数组
char *(*pf[3])(char *p)
以下为用法
#include <stdio.h>
char * fun1(char *p)
{
printf("%s\n",p);
return p;
}
char * fun2(char *p)
{
printf("%s\n",p);
return p;
}
char * fun3(char *p)
{
printf("%s\n",p);
return p;
}
void main()
{
char *(*pf[3])(char *p);
pf[0]=fun1; //因为fun的值就是函数首地址
pf[1]=&fun2;
pf[2]=&fun3;
pf[0]("fun1");
pf[1]("fun2");
pf[2]("fun3");
}
函数指针数组的指针
这是在定义一个函数指针数组的指针
char *(*(*pf)[3])(char *p);
pf是一个指针,而非数组名
#include <stdio.h>
char * fun1(char *p)
{
printf("%s\n",p);
return p;
}
char * fun2(char *p)
{
printf("%s\n",p);
return p;
}
char * fun3(char *p)
{
printf("%s\n",p);
return p;
}
void main()
{
char *(*a[3])(char *p); //a是一个数组名
char *(*(*pf)[3])(char *p)=&a; //pf是一个指针
a[0]=fun1;
a[1]=&fun2;
a[2]=&fun3;
pf[0][0]("fun1");
pf[0][1]("fun2");
pf[0][2]("fun3");
}