http://www.fortystones.com/tips-to-make-c-program-effective/
代码之美不仅在于能够寻求一种合理的解决方案,更在于其简洁、高效与紧凑。代码的设计往往比实际的代码编写要难。因此,每一个程序员在代码编写的过程中,需要在头脑中时常保持一些基本的原则。
这里有10种使你的C程序更加高效的方法:
1.避免不必要的函数调用
考虑下面两个函数调用:
Voidstr_print(char*str)
{
intI;
for(I=0;I<strlen(str);i++){
Printf(“%c”,str[i]);
}
}
这段代码在循环的过程中不停地调用函数strlen(str),而实际上只需要一次调用即可:
Voidstr_print(char*str)
{
IntI;
Intlen=strlen(str);
For(I=0;I<len;i++){
Printf(“%c”,str[i]);
}
}
2.避免不必要的指针引用:
考虑下面两个函数调用:
Intmultiply(int*num1,int*num2)
{
*num1=*num2;
*num1+=*num2;
Return*num1;
}
Intmultiply(int*num1,int*num2)
{
*num1=2**num2;
Return*num1;
}
第一个例子中有5处指针引用,而第二个例子中只有三处指针引用,你觉得哪一个会更好一些呢?
3.
考虑下面两个结构体:
Struct{
Charc;
IntI;
Shorts;
};
Struct{
Charc;
Shorts;
IntI;
};
假设一个char需要1byte的内存空间,一个short占2byte的内存空间,一个int占4个字节的内存空间。
首先,我们会认为这两个结构体占据相同大小的内存空间,然而,而str_1占用12个字节的第二个结构体只需要8个字节?这怎么可能呢?
内存对齐规则:
①对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragmapack()指定的数,这个数据成员的自身长度)的倍数。
②在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragmapack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
4.
如果你知道某个值永远为正,使用unsignedint而不是int,因为某些处理器处理unsignedint类型的数据比int要快得多。
5.
在逻辑语句中把常量放在运算符的左侧,防止出现拼写错误的情况。
比如:
If(a=3)
{
a++;
}
与
If(3=a)//CompilationError
{
a++;
}
6.
更多得使用typedef而不是宏,虽然有时宏是不可取代的。Typedef能使程序更加直观。
typedefint*INT_PTR;
INT_PTRa,b;
#defineINT_PTRint*;
INT_PTRa,b;
在这个宏定义中,a是指向int的指针,而b只是int。使用typedef,a、b都是整型指针。
7.
尽量把函数定义为static型除非你希望在其它的文件中调用该函数。Static函数是指只在当前文件中有效的函数。Static型的函数能够有效地限定对函数的访问,这样我们就不需要创建特殊的头文件来存放内部的函数。这样做的好处有:
A).在不同的文件中可以将static函数以相同的名字命名。
B).编译开销减少因为没有外部文件符号处理。
//first_file.c
Staticintfoo(inta)
{
//Whateveryouwanttointhefunction
}
//second_file.c
Intfoo(int);
Intmain()
{
Foo();
//Thisisnotavalidfunctioncallasthefunctionfoocanonlybecalledbyanyotherfunctionwithinfirst_file.cwhereitisdefined.
Return0;
}
8.
使用记忆,避免递归过程的重复计算。
以Fibonacci数列为例:
常规的递归方法是:
Intfib(intn)
{
If(n==0||n==1){
Return1;
}
Else{
Returnfib(n-2)+fib(n-1);
}
}
从递归树中可以发现,在计算fib(5)时,我们计算fib(3)函数2次,fib(2)函数3次。这是相同函数的重复计算。如果n非常大,fib<n(i)函数增长i<n。解决这一问题的快速方法将是计算函数值1次,存储在一些地方,需要时计算,而非一直重复计算。
intcalc_fib(intn)
{
intval[n],i;
for(i=0;i<=n;i++){
val[i]=-1;//Valueofthefirstn+1termsofthefibonaccitermssetto-1
}
val[0]=1;//Valueoffib(0)issetto1
val[1]=1;//Valueoffib(1)issetto1
returnfib(n,val);
}
intfib(intn,int*value)
{
if(value[n]!=-1){
returnvalue[n];//Usingmemoization
}
else{
value[n]=fib(n-2,value)+fib(n-1,value);
//Computingthefibonacciterm
}
returnvalue[n];//Returningthevalue
}
9.
避免野指针与悬挂指针。
养成在释放空间之后将指针赋空的习惯。
10.
及时释放内存。
Thebeautyofanycodeliesnotonlyinfindingthesolutiontoagivenproblembutisinitssimplicity,effectiveness,compactnessandefficiency(memory).Designingthecodeisharderthanactuallyimplementingit.Henceeveryprogrammershouldkeep
acoupleofbasicthingsinmindwhileprogramminginC.Hereweintroduceyoutosuch10waysofstandardizingyourCcode.
1.Avoidunwarrantedfunctioncalls
Considerthefollowingtwofunctions:
1
| voidstr_print(char*str)
|
2
|
| |
7
| for (i=0;i<strlen (str);i++){
|
8
|
|
viewsource
print?
1
| voidstr_print1(char*str)
|
2
|
|
Noticethesimilarityinfunctionofthetwofunctions.Howeverthefirstfunctioncallsthestrlen()multipletimeswhereasthesecondfunctiononlycalls
thefunctionstrlen()asingletime.Thusperformanceofthesecondfunctionisobviouslybetterthanthefirstone.
2.Avoidunnecessarymemoryreferences
Againletstakeacouplemoreexamplestoexplainthis.
1
| intmultiply(int*num1,int*num2)
|
2
|
|
11
| }
|
1
| intmultiply1(int*num1,int*num2)
|
2
|
|
Againthesetwofunctionshavesimilarfunctionality.Thedifferenceisthereare5memoryreferencesinthefirstfunction(1forreading*num1,2forreading*num2and2forwritingto*num1)whereasinthesecondfunctionthereisonly2memoryreferences
(oneforreading*num2andoneforwritingto*num1).
Nowwhichonedoyouthinkisbetterofthetwo?
3.Savingmemoryused(conceptofMemoryAlignmentandPadding)
viewsource
print?
viewsource
print?
Assumethatachartakes1byte,shorttakes2bytesandinttakes4bytesofmemory.Atfirstwewouldthinkthatboththestructuresdefinedabovearethesameandhenceoccupythesameamountofmemory.Howeverwhereasstr_1occupies12bytesthesecond
structuretakesonly8bytes?Howisthatpossible?
Noticeinthefirststructurethat3different4bytesneedtobeassignedtoaccomodatethethreedatatypes(aswehaveintdeclarationbetweencharandshort).Whereasinthesecondstructureinthefirst4bytesbothcharandshortcanbeaccomodated
henceintcanbeaccomodatedinthesecond4bytesboundary(thusatotalof8bytes).
4.Useunsignedintsinsteadofintsifyouknowthevaluewillneverbenegative.Someprocessorscanhandleunsignedintegerarithmeticconsiderablyfasterthansigned(thisisalsogoodpractise,andhelpsmakeforself-documentingcode).
5.Inalogicalconditionalstatementalwayskeeptheconstantitemofthecomparisononthelefthandside
viewsource
print?
7
| printf("%d",x);//Outputis3
|
8
|
|
viewsource
print?
7
| printf("%d",x);//Compilationerror
|
8
|
|
Usingthe“=”assignmentoperatorinsteadofthe“==”equalitycomparisonoperatorisacommontypingerrorwecan’tmakeoutuntilexecution.Puttintheconstanttermonthelefthandsidewillgenerateacompile-timeerror,lettingyoucatchyourerror
easily.
Note:‘=’istheassignmentoperator.b=1willsetthevariablebequaltothevalue1.
‘==’istheequalityoperator.itreturnstrueiftheleftsideisequaltotherightside,andreturnsfalseotherwise.
6.Wheneverpossibleusetypedefinsteadofmacro.Sometimesyoujustcannotavoidmacrosbutusingtypedefisbetter.
viewsource
print?
Hereinthemacrodefinitionaisapointertoanintegerwhereasbisdeclaredasonlyaninteger.Usingtypedefbothaandbareintegerpointers.
Inaddition,debuggingwithtypedefismoreintuitivecomparedtomacros.
7.Alwaysdeclareanddefinefunctionsasstaticunlessyouexpectthefunctiontobecalledfromdifferentfiles.
Functionsthatarevisibleonlytootherfunctionsinthesamefileareknownasstaticfunctions.
Itrestrictothersfromaccessingtheinternalfunctionswhichwewanttohidefromoutsideworld.Nowwedon’tneedtocreateprivateheaderfilesforinternalfunctions.Othersdon’tseethefunctionandsotheyhdon’tusethemthereforedon’tcastthose
functiondefinitioninconcrete.
Advantagesofdeclaringafunctionstaticinclude:
a)Twoormorestaticfunctionswiththesamenamecanbeusedindifferentfiles.
b)Compilationoverheadisreducedasthereisnoexternalsymbolprocessing.
Let’sunderstandthisbetterwiththeexamplesbelow:
viewsource
print?
7
| /*Whateveryouwanttointhefunction*/
|
8
|
|
19
| foo();//Thisisnotavalidfunctioncallasthefunctionfoocanonlybecalledbyanyotherfunctionwithinfirst_file.cwhereitisdefined.
|
20
|
|
8.UsememoizationtoavoidrepititiouscalculationinRecursion
ConsidertheFibonacciproblem;
TheFibonacciproblemcanbesolvedbysimplerecursiveapproach:
viewsource
print?
13
| return fib(n-2)+fib(n-1);
|
14
|
|
Note:Hereweareconsideringthefibonacciseriesfrom1.Thustheserieslookslike:1,1,2,3,5,8,…
Noticefromtherecursivetreethatwehavecalculatedthefib(3)function2timesandfib(2)function3times.Thisisrepeatedcalculationforthesamefunction.Ifnisextremelylargethecalculationofthefib(i)functionincreasesfori<n.A
fasterwayofsolvingthisproblemwouldbetocomputethevalueofthefunctiononce,storeitinsomeplaceandretrieveitwheneverneededratherthanrecomputingitalloveragain.Thissimpletechniqueiscalledmemoizationwhichcanbeusedwithrecursion
toenhancethespeedofcomputation.
Thememoizedcodefortheabovefibonaccifunctionwouldlooksomethinglikethis:
viewsource
print?
9
| val[i]=-1;//Valueofthefirstn+1termsofthefibonaccitermssetto-1
|
10
|
|
13
| val[0]=1;//Valueoffib(0)issetto1
|
14
|
|
15
| val[1]=1;//Valueoffib(1)issetto1
|
16
|
|
21
| intfib(intn,int*value)
|
22
|
|
27
| return value[n];//Usingmemoization
|
28
|
|
33
| value[n]=fib(n-2,value)+fib(n-1,value);//Computingthefibonacciterm
|
34
|
|
37
| return value[n];//Returningthevalue
|
38
|
|
Herethecalc_fib(n)functioniscalledfromthemain().
9.Avoiddanglingpointersandwildpointers
Apointerwhosepointingobjecthasbeendeletedisknownasadanglingpointer.
Ontheotherhand,wildpointersarethosepointerswhicharenotinitialized.Notethatwildpointersdonotpointanyspecificmemorylocation.
viewsource
print?
5
| int*dp=malloc(sizeof(int));
|
6
|
|
9
| free(dp);//dpisnowadanglingpointer
|
10
|
|
11
| dp=NULL;//dpisnolongeradanglingpointer
|
12
|
|
viewsource
print?
5
| int*ptr;//Uninitializedpointer
|
6
|
|
Theprogramusuallyshowsweirdbehaviourwhenthesepointersareencountered.
10.Alwaysremembertofreewhatevermemoryyouhaveallocatedinyourprogram.Noticeintheexampleabovehowwefreedthedppointerwhichweallocatedusingthemalloc()functioncall.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理