
文章插图

文章插图
有的时候,我们通过指针传递数据给函数不是为了在函数中改变他指向的对象 。
相反,我们防止这个目标数据被改变 。传递指针只是为了避免拷贝大型数据 。
考虑一个结构体类型Student 。我们通过show函数输出Student变量的数据 。
typedef struct{ char name[31]; int age; float score;}Student;//打印Student变量信息void show(const Student * ps){ printf("name:%s , age:%d , score:%.2f",ps->name,ps->age,ps->score); }
我们只是在show函数中取读Student变量的信息,而不会去修改它,为了防止意外修改,我们使用了常量指针去约束 。
另外我们为什么要使用指针而不是直接传递Student变量呢?
从定义的结构看出,Student变量的大小至少是39个字节,那么通过函数直接传递变量,实参赋值数据给形参需要拷贝至少39个字节的数据,极不高效 。
而传递变量的指针却快很多,因为在同一个平台下,无论什么类型的指针大小都是固定的:X86指针4字节,X64指针8字节,远远比一个Student结构体变量小 。
函数的指针
跟普通的变量一样,每一个函数都是有其地址的,我们通过跳转到这个地址执行代码来进行函数调用,只是,跟取普通数据不同的在于,函数有参数和返回值,在进行函数调用的时候,首先需要将参数压入栈中,调用完成后又需要将参数压入栈中 。既然函数也是通过地址来进行访问的,那它也可以使用指针来指向,事实上,每一个函数名都是一个指针,不过它是指针常量和指针常量,它的值是不能改的,指向的值也不能改 。
(关于常量指针和指针常量什么的,有时间在专门开辟一章来说明const这个东东吧,也是很有讲头的一个东东 。。。)
函数指针一般用来干什么呢?函数指针最常用的场合就是回调函数 。回调函数,顾名思义,就是某个函数会在适当的时候被别人调用 。当期望你调用的函数能够使用你的某些方式去操作的时候,回调函数就很有用,比如,你期望某个排序函数在比较的时候,能够使用你定义的比较方法去比较 。
有过较深入的C编程经验的人应该都接触过 。C的标准库中就有使用,例如在strlib.h头文件的qsort函数,它的原型为:
void qsort(void*__base, size_t __nmemb, size_t __size, int(*_compar)(const void *, const void*));
其中int(*_compar)(const void *, const void *)就是回调函数,这个函数用于qsort函数用于数据的比较 。下面,我会举一个例子,来描述qsort函数的工作原理 。
一般,我们使用下面这样的方式来定义函数指针:
typedef int(*compare)(const void *x, const void *y);
这个时候,compare就是参数为const void *, const void *类型,返回值是int类型的函数 。例如:

文章插图

文章插图
用typedef来定义的好处,就是可以使用一个简短的名称来表示一种类型,而不需要总是使用很长的代码来,这样不仅使得代码更加简洁易读,更是避免了代码敲写容易出错的问题 。强烈推荐各位在定义结构体,指针(尤其是函数指针)等比较复杂的结构时,使用typedef来定义 。
每一个函数本身也是一种程序数据,一个函数包含了多条执行语句,它被编译后,实质上是多条机器指令的合集 。
在程序载入到内存后,函数的机器指令存放在一个特定的逻辑区域:代码区 。
既然是存放在内存中,那么函数也是有自己的指针的 。
C语言中,函数名作为右值时,就是这个函数的指针 。
void echo(const char *msg){ printf("%s",msg);}int main(void){ void(*p)(const char*) = echo; //函数指针变量指向echo这个函数
p("Hello "); //通过函数的指针p调用函数,等价于echo("Hello ") echo("World"); return 0;}
const和指针
const到底修饰谁?谁才是不变的?
如果const 后面是一个类型,则跳过最近的原子类型,修饰后面的数据 。
(原子类型是不可再分割的类型,如int, short , char,以及typedef包装后的类型)
如果const后面就是一个数据,则直接修饰这个数据 。
int main(){ int a = 1;
int const *p1 = &a; //const后面是*p1,实质是数据a,则修饰*p1,通过p1不能修改a的值 const int*p2 = &a; //const后面是int类型,则跳过int,修饰*p2,效果同上
推荐阅读
- 超炫酷技巧!C语言代码优化的技巧
- C语言访问字符串数组元素的方式
- C语言关键字const和指针结合的使用
- 头昏脑胀怎么治疗?
- C语言厉害在哪?
- C语言、嵌入式重点知识:回调函数
- C语言指针经典知识汇总
- 移动应用开发的六大编程语言
- 用C语言编写CPU使用率限制程序
- 跨平台的C语言网络框架库acl
