static的滥用与变态的阉割
什么情况下需要用局部静态变量呢?需要保留函数上一次调用结束时的值时,例如可以用下面的方法求n!。
例7.17 输出1到5的阶乘值。
#include <stdio.h>
int main( void )
{int fac(int n);
int i;
for(i=1;i<=5;i++)
printf("%d!=%d\n" ,i,fac(i) );
return 0;
}
int fac(int n)
{static int f=1;
f=f*n;
return(f);
}
————谭浩强 ,《C程序设计》(第四版),清华大学出版社, 2010年6月,p207
这段程序的输出结果是:
1!=1
2!=2
3!=6
4!=24
5!=120
看起来似乎没有问题,然而稍微仔细思考一下就不难发现,如果若问题再补充一个要求时,比如在求完1到5的阶乘后再重新求3的阶乘时,那个fac()函数彻底报废、毫无用处。而造成这种结局的原因则是fac()函数对static莫名其妙的滥用,亦即在不该使用static局部变量时使用了static局部变量。
为了进一步分析这种写法的荒谬,下面把fac()函数的内容等价地还原到调用者main()函数中,这样代码就变成了
#include <stdio.h> int main( void ) { int i; for ( i = 1 ; i <= 5 ; i++ ) { static int f = 1 ; f *= i ; printf ( "%d!=%d\n" , i , f ); } return 0; } |
这段代码与样本中代码在功能上是等效的,但却没有样本代码的毛病。从这段代码中不难看出代码段
for ( i = 1 ; i <= 5 ; i++ ) { static int f = 1 ; f *= i ; printf ( "%d!=%d\n" , i , f ); } |
是一个有机的功能整体,其中i的取值顺序、static局部变量f及求阶乘的运算“f *=i”三者之间互相依赖,唇齿相依。
样本代码的荒谬则在于把紧密依赖、三位一体的东西变态地阉割出一部分来,并把阉割出的部分写成了只能一次性使用的“残疾”函数。由于阉割出的部分包含static局部变量,fac()函数的行为对调用次序具有强烈的依赖性,函数就其本性来说根本不应该具有这种娇生惯养的依赖性。在大多数情况下,只要函数的调用者提供正确的实参,函数都应该产生正确的副效应和返回值,这才是函数的本分。它与调用者之间只应该存在必要的联系,所谓“必要”就是不多也不少的参数,除此之外不应该再有什么别的联系,这就是所谓的“低耦合”的含义。一旦违背了这个原则,比如样本代码那样阉割不可分的功能,就必然导致变态的强耦合联系方式。在不满足这种苛刻的强耦合条件下,函数就会变得毫无用处。这就好比把一个完整的计算机主板掰成两半,再用胶水粘合在一起,摆摆样子可以,但主板被分开的任何一部分都已经成了废品。在函数中滥用static局部变量,最终的效果多半如此。
那么,是否static局部变量绝对不可以使用呢?倒也不是。但总的来说static局部变量的适应范围较窄。下面的例子中对static局部变量的使用就非常恰当,无论是把数组name设置为局部还是把它设定为static存储类别都非常恰到好处。
#include <stdio.h> char * month(unsigned) ; int main( void ) { puts ( month(10) ); return 0; } char * month(unsigned m) { static char * const name[12] = { "Jan" , "Feb" , "Mar" , "Apr" , "May" , "Jun" , "Jul" , "Aug" , "Sep" , "Oct" , "Nov" , "Dec" ,}; return name[m-1]; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库