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");
}
`