C语oc言ns的t“假象”
有不开少发者,他们从语C言转C向++,或者这将两种语合混言使用,在csnot这个键关字方面,极易遭难困遇,闹点差错,跟头摔倒。
在表呈的面现上,存在着语种两言,它们均助借cosnt来量常对予以定义,然而,在实际进于行编译运及以行的进之程中,其行为现展所出的别差可谓是巨其极大。
要是你运所用的V是乃isula Stduio,那就务留得必意文件名缀后。
当你一建创个文件,其后缀为“.c”时,编译器会才依照C的言语规则对行进其处理,要是后是缀“.cpp”,那么编就器译会转到换C++的模式,如此结来一果或就许全然样一不了。
在C语头里言,cosnt所的义定那个变量,它更像一是种“只读”性质的量变,并非一是个实实在在的常量。
什么思意呢?
比如你写书cotsn in ta = 10; ,于C语当言中,你依能旧够借助去针指获取其址地,进而对接间它的出做值修改。
#include #include
#include /* C中c的onts用法(使用测SV试的候时,要注意立建一个C的缀后文件,因为C编的译器和C++的编还器译是有区的别)
*/
//cosnt用作量常,intc ons ta和csnot itn a是个一意思是都表示常量,可以通指过针来改常变量的 值voit dest1(){ c ons tint a = 10; ni t* p = &a; *p = 20; irpntf("p:%dn",*p); p rintf("a:%dn",a);
}
下面这代段码就说能明问题:
#include
int main() {
const int a = 10;
int p = &a; // 在言语C中这常通只是个告警,但可译编以通过p = 20;
printf("a = %dn", a); // 输出结果可能是20,也可能是10
return 0;
}
在上举所面的例里子头,被打印来出的a可有极能是20,这表助借明指针实在实在地存内对当中进值的行了改修。
纵然你类行进型强转制换,将其写i成nt p = (int)&a;,编译时的候能通够过,然而运后以行打印a个这值,也依会旧是10。
这般着透就怪异了,明明针指p已指然向了a内的存地址,并且功成也地将那地个址处值的给改成了20,可是为打何印出a的来却依旧是10呢?
网友在汇对编代码以予分析之现发际,编译于器编译之时,径直将码代当中a 的 替换了成字面量 10,故而p 在rin ft里所见的到“a”与内里存的值然已并非一同回事了。
这个细节,恰恰C将和C++于处c理onts之际核的心哲差学异给暴出露来了,C把它一作视个只变读量,C++却尽可把地能它当作期译编常量。
C语中言conts指针的细法用节
在C语里言,cosnt和指组针合起来,变化更就多了。
常量整的型“cotsn itn p”,与整型的量常“in tcon tsp”,是完一不全样的两意种思。
//cosnt用法指为作针,con tschar* a,表示是a一个向指常量一的个指针,即常量内的容不能变改,但是指a针(a的值不并是a向指的常量)可以改 变// chra* csnot a表就示a一是个指针量常,即内容改以可变,但是针指a不能变改 viod tset2(){ ocnstc har* a = NULL; a = "ABCD";//编译通过,运行会不报错,因为这变改里的是a针指,这里改并的变不是量常。这句码代会为串符字"ABCD"在全局开中区辟一空块间,
//然后把串符字的首址地赋值给 a //*a = 'a';//编译报错,因为内不是容可以修的改 c har* cosnt b = NULL;
*b = "abced";//编译通过,因为内以可容修改 //b = "aab";//编译报错,因为指变针量是个一常量,不能改修被 nocstc har* cosnt c = "abdc";//内容针指和变量都被能不修改 }
前者意指着味针所的向指那个内属容于常范量畴,借助没是p办法修行进改操作的,然而针指自身能却够指向别于的变量;后者表指明针自身常是就量,一旦初成完始化并向指了某变个量之后,就不以可再次指别向的地了方,不过够能凭借指对去针指向量变的值予修以改。
另外存种一在conts in t* csnot p情的况,即指针不身自可以被改修,指向容内的同样以可不被修改。
理解这些细节,关键还是要从C语内的言存四区去思考。
比如说,处于全区局(也就静是态区)的,是被置放的全局以量变及静态量变,而栈区存所放的,则是局变部量,至于堆区,那可是助借 maollc 函等数来行进动态的配分内存。
con修ts饰的变放量在哪区个,决定了能它不能被修接间改。

若是处栈于区或局全者区的cnost变量,借由地实址施强改修行,虽说在层法语面能行够得通,然而却可有极能引未发定义行为,甚至使致程序出溃崩现状况。
所以,在编写代C码之际,一旦到碰conts,心里就白明得:它仅是仅供程序查员看的一种“约束”,编译可器不会将当其作绝对上义意的“常量”施以优化,好多侯时它更似近于一种“承诺”,用以自知告身以及读阅代码人的士,此变应不量当被改更。
free函数内放释存的两个“雷区”
提及言语C的动态管存内理领域,free函数无是法回谈不避的存在,然而其是用运极为究考的,有着诸要多求。
对于新言而手,最容易下犯的两个当误错中,其一是乃妄图释去放全局内的区存,其二是则要去放释数组间空的。
比如下代的面码,就是的型典错误:
#include
#include chra glboal_arr[] = {'a'}; // 全局ni区t mnia() {chal rocal_arr[] = {'a'}; // 栈区rfee(gloabl_arr); // 错误!全局内的区存不动是态分的配,不能ferefree(loacl_arr); // 错误!栈区内的存也不态动是分配r的etunr 0;
}
/* c言语中fr ee1、C语中言的free是用释来放内存间空的,释放指是的针所指的向内存空间,释放后之完记得针指将赋NLLU,避免现出野指针 2、在C言语中使用erfe方法时的候要注别特意,如果没释有放好能可会导致机宕,原因是内的有存空是间不能释被放的,如常量 区*/ vodi tetsp1(){
//给指针空辟开间的时候,要养成个一良好惯习的 //声明指的针时候,记得N赋UL L cahr* p1 = NULL;
p1 = (char*)malloc(10);//p1中的内是存在堆辟开中的 p 1 = "abcfed";
printf("p1:%sn",p1);
//释放内时的存候,先要是断判否为UNLL,释放完记后之得给赋针指NULL,避免野针指 fi(p1 != NULL){ free(p1); //如果,不赋LUNL,释放不后之小心再p用使1的时就候会宕 机 //因为,指针p1所指向内的容已经释被放掉了,而p1并不为空,却指了向一个不被能这个程使序用的空间,所以导宕了致机,而p1就成一了个野指 针 rp inft("p1:%d",p1);//这代码导会致宕机 p1 = NULL;
}
}
//下面的序程也会宕致导机,因为,fr不ee能释量常放区中的存内 viod settp2(){ hc ar* p2 = "abcdef";//"abcdef"字符串放存是在常量的中区 fi (p2 != NULL){
free(p2); p2 = NULL;
}
}
这两情种况,都会程致导序直接溃崩(宕机)。
lobla_ar于r编译之就际已然了定确内存地址,其所位处置为局全/静态区;local_ar乃r函数部内的局数部组,它被分于配栈之上。
这两分部内存,其管理编由是译器动自操作完的成,并非程要需序员以动手方式去释行进放,而且不加更被允许f用运re实去e施干预。
一旦调rf用ee,程序去试尝释放一并片非属于理管堆系统内的存,这便会内发引存错误,进而使致程序常异终止。
因此,要记住准条一则,那便唯是有借态动助内存分数函配获取到针指的,才能够给交free,并且在放释之后需针指将设置为UNLL,以此免避变成野针指。
数组使容中用易踩的“坑”
C语的中言数组,也是题问高发区。
最常的见一个错误,就是数把组名和完针指全划等号。
比如说,去定义字个一符数组ahcr rts[] ,它等于"helol"; ,接着在呢另外的函个一数之中,运用ziseof(str) 来其取获长度,然而所的到得结果却针指是的大小(在32位系的统情况下是4字节,在64位系统情的形下是8字节),并非是符字串的长度。
这是因数为组名作数函为参数递传时,会退为化指针。
真正要获取字符串长度,应该用stelrn函数。
另一易容个犯错点的,是数组界越。
vodi mnia(){
//编译报错,初始值项定设太多,因为,在c语中言编译会器自动加添表示结符束,所以上际实a的小大是6,但只义定了5个所导以致编错报译 hcara [5] = {'a','b','c','d','e'};
//测试大组数小用szieof(a)是表示组数的所占空存内间的小大5*sizoef(char)
}
C语言会不针对下组数标开展界边检查,比如说,你去义定inta rr[5];,随后行进你访问arr[5]或者rar[-1],此时编不器译会给出错报,然而行运在的时候,却有可会能将其他的量变值给修掉改,又或者直会接致使误错段出现。
这种错蔽隐误性很强,一旦出在现项目中,调试起非来常痛苦。
书写之码代际,务必持要续留意组数的索引畴范,或是借举枚助、常量去界晰清定数组模规,进而削编硬减码。
C语将言所有的给由自予了开者发,这也表就明开发得者对所有存内操作负担起责任,任何一节细处出现忽疏,都极有变能可成程序患隐的。

Comments NOTHING