C語言的設(shè)計哲學(xué):
一切工作程序員自己負(fù)責(zé)。
語言中的所有特性都不需要隱式的運行時支持。
程序員所做的都是對的。
程序員應(yīng)該知道自己在干什么,并保證自己的所作所為是正確的。
第1章-- C: 穿越時空的迷霧
小即是美。事物發(fā)展都有個過程,由簡入繁,不能一開始就想得太復(fù)雜,Multics, IBM的OS/360都是因此而失敗。
C語言的許多特性是為了方便編譯器設(shè)計者而建立的。----唉,怎么這個樣子
C語言的基本數(shù)據(jù)類型直接與底層硬件相對應(yīng)。----確實如此
register關(guān)鍵字,這個設(shè)計可以說是一個失誤,如果讓編譯器在使用各個變量時自動處理寄存器的分配工作,顯然比一經(jīng)聲明就把這類變量在生命周期內(nèi)始終保留在寄存器里要好,使用register關(guān)鍵字,簡化了編譯器,卻把包袱丟給了程序員。
C編譯器不曾實現(xiàn)的一些功能必須通過其他途徑實現(xiàn)----標(biāo)準(zhǔn)I/O庫和C預(yù)處理器。
在宏擴展中,空格會對擴展的結(jié)果造成很大的影響。宏后面不可加';',它不是C語句。宏最好只用于命名常量,并為一些適當(dāng)?shù)慕Y(jié)構(gòu)提供簡捷的記法。宏名應(yīng)該大寫這樣便很容易與函數(shù)調(diào)用區(qū)分開來。
const關(guān)鍵字原先如果命名為readonly就好多了。
const int *p;是指不能夠通過通過p來改變int的值,即:*p = 30和p[3] = 4都是錯誤,但p是可以改變。
const int *與int *是相容的,都是指向int的指針;const int **與int **不相容,前者是指向const int *的指針,int **是指向int *的指針。
盡量不要在你的代碼中使用無符號類型,以免增加不必要的復(fù)雜性。只有在使用位段和二進制掩碼時,才可以使用無符號數(shù)。應(yīng)該在表達(dá)式中使用強制類型轉(zhuǎn)換,使操作數(shù)均為有符號數(shù),或者無符號數(shù),這樣就不必由編譯器來選擇結(jié)果的類型。有個例子,在ANSI C中,-1 < (unsigned char)1為真,而-1 < (unsigned int)1 為假。
第2章-- 這不是Bug,而是語言特性
進步——是計算機軟件工程和編程語言設(shè)計藝術(shù)逐步發(fā)展的重要動因。這也是為什么C++語言令人失望的原因:它對C語言中存在的一些最基本問題沒有什么改進,而它對C語言最重要的擴展(類)卻是建立在脆弱的C類型模型上。
按照C語言的理念,程序員應(yīng)該知道自己在干什么,而且保證自己的所作所為是正確的。
多做之過:fall through作為switch的默認(rèn)行為是個失誤;相鄰的字符串自動合并成一個字符串;太多的缺省可見性,全局可見,一個大型函數(shù)一群“內(nèi)部”函數(shù)不得不在該函數(shù)的外部進行定義。沒有人會記得在它們之前加上static限定符,所以他們在缺省情況下是全局可見的。
誤做之過:
C語言中符號重載:static 在函數(shù)內(nèi)部,表示該變量的值在各個調(diào)用間一直保持延續(xù)性;在函數(shù)這一極,表示該函數(shù)只對文本文件可見。extern用于函數(shù)定義表示全局可見(屬于冗余),用于變量,表示它在其他地方定義。
運算符優(yōu)先級存在的問題:.優(yōu)先級高于*, p.f表示(p.f);函數(shù)()高于*;==和!=高于位運算符(val & mask != 0)表示val & (mask != 0);==和!=高于賦值符,c = getchar() != EOF表示c = (getchar() != EOF);算數(shù)運算符高于移位運算符 msb<<4 + lsb表示msb<<(4+lsb);逗號最低。
有些專家建議在C語言中記牢兩個優(yōu)先級就夠了:乘除先于加減,在涉及其他的操作符時一律加括號。
結(jié)合性,在幾個操作符具有相同優(yōu)先級時決定先執(zhí)行哪一個。
計算的次序之所以未定義,是想讓編譯器充分利用自身架構(gòu)的特點,或者充分利用存儲于寄存器的值。
如果對于堆棧的每次訪問之前都要檢查其大小和訪問權(quán)限,對于軟件來說代價太大了,根本不可行。
gets(char *s)
,不檢查緩沖區(qū)的空間,而fgets(char *s, int n, FILE *stream)
可以對讀入的字符數(shù)設(shè)置一個上限n。fgets對緩沖大小進行限制的方式,更為安全。
少錯之過,標(biāo)準(zhǔn)參數(shù)的處理以及把lint程序錯誤的從編譯器中分離出來。
Lint Early, Lint Often Lint is your software conscience. It tells you when you are doing bad things. Always use lint. Listen to your conscience.gcc as lint,使用-Wall:enable a bunch of warning。gcc --help=warning查詢。
linux上可以使用splint。
讓充滿Bug的代碼快速通過編譯實在是不劃算。----我習(xí)慣于寫過代碼后用眼睛看一遍,確認(rèn)無誤后再編譯調(diào)試,看來以后可以在中間加上一步用lint檢查。
大型緩沖區(qū)如果閑置不用是非常浪費空間的。
如果程序員可以在同一代碼塊中同時進行malloc和free操作,內(nèi)存管理是最輕松的。
深刻教訓(xùn):即使可以保證你的編程語言100%可靠,你仍然可能成為算法中災(zāi)難的犧牲品。----確實如此,學(xué)好算法。
第3章-- 分析C語言的聲明
聲明器(declarator), 就是標(biāo)識符以及與它組合與它組合在一起的任何指針,函數(shù)括號,數(shù)組下標(biāo)等。以下形式: 標(biāo)識符
或 標(biāo)識符[下標(biāo)]
或 標(biāo)識符(參數(shù))
或 (聲明器)
----注意括號不能亂加,就兩個地方可以加括號
聲明格式:類型說明符 聲明器[,聲明器];
類型說明符: int char void等
存儲類型: extern static register auto
類型限定符: const volatile
理解C語言聲明的優(yōu)先級規(guī)則
A 聲明從它的名字開始讀取,然后按照優(yōu)先級順序依次讀取。
B 優(yōu)先級從高到底依次是:
B.1 聲明中被括號括起來的那部分
B.2 后綴操作符:
括()表示一個函數(shù),
[]表示這是一個數(shù)組。
B.3 前綴操作符:
*表示指向...的指針
C 如果const和(或)volatile關(guān)鍵字與類型說明符(如int,long等)相鄰,它作用于類型說明符;其他情況下const和(或)volatile關(guān)鍵字作用于它左邊緊鄰的指針*號。
用優(yōu)先級規(guī)則分析C語言聲明:
char * const *(*next)();
char *(* c[10])(int **p);
如果需要頻繁地對整個數(shù)組進行賦值操作,可以通過把它放入struct中。
在調(diào)用函數(shù)中,參數(shù)傳遞時首先盡可能地存放到寄存器中(追求速度)。
union也可以把同一個數(shù)據(jù)解釋成兩種不同的東西,不用強制類型轉(zhuǎn)換。
typedef和宏文本替換之間存在一個關(guān)鍵性的區(qū)別:typedef看成是一種徹底的"封裝"類型——在它聲明后不能再往里面增加別的東西。首先,可以用其他類型說明符對宏類型名進行擴展,但對typedef所定義的類型名稱不能這樣做。typedef int banana; unsigned banana i; /*錯誤!非法 */;其次連續(xù)幾個變量聲明。
----由于typedef由編譯器解釋的,而宏是由預(yù)處理器解釋的
typedef void (*ptr_to_func)(int);
//這樣來定義函數(shù)指針的別名。
不要為了方便起見對結(jié)構(gòu)使用typedef,這樣做唯一的好處是能使你不必書寫struct關(guān)鍵字,但這個關(guān)鍵字可以向你提示一些信息。
應(yīng)該始終在struct的定義中使用結(jié)構(gòu)標(biāo)簽,即使它并非必須。這種做法可以使代碼更為清晰。結(jié)構(gòu)標(biāo)簽的名字可以取一個以"_tag"結(jié)尾的名字。
C語言中存在多種名字空間:
-
標(biāo)簽名(label name) -
標(biāo)簽(tag): 這個名字空間用于所有的結(jié)構(gòu)、枚舉和聯(lián)合 -
成員名:每個結(jié)構(gòu)或聯(lián)合都有自身的名字空間 -
其他
在同一個名字空間,任何名字必須具有唯一性。
----C中也有名字空間,沒注意啊。
第4章-- 令人震驚的事實:數(shù)組和指針并不相同
extern對象聲明告訴編譯器對象的類型和名字,對象的內(nèi)存分配則在別處進行。
X = Y;
在這個上下文環(huán)境里,符號X的含義是X所代表的地址。這被成為左值。
在這個上下文環(huán)境里,符號Y的含義是Y所代表的地址的內(nèi)容。這被稱為右值。
左值在編譯時可知,左值表示存儲結(jié)果的地方。
右值直到運行時才知。如無特別說明,Y的值是指右值。
數(shù)組名是個左值,但不是可修改的左值。
指針是間接尋址,數(shù)組名是直接尋址,這就是兩者在訪問數(shù)據(jù)時的區(qū)別。指針的值是運行時從內(nèi)存取得的,數(shù)名的值是編譯時已經(jīng)確定的。
專業(yè)的C程序員必須熟練的掌握malloc()函數(shù),并且學(xué)會用指針操縱匿名內(nèi)存。
第5章-- 對鏈接的思考
動態(tài)鏈接優(yōu)點:
-
1.可執(zhí)行文件的體積小,節(jié)省磁盤空間和虛擬內(nèi)存。 -
2.所有動態(tài)鏈接到某個特定函數(shù)庫的可執(zhí)行文件在運行時共享該函數(shù)庫在內(nèi)存中的一個單獨拷貝。
只使用動態(tài)鏈接。
gcc創(chuàng)建動態(tài)鏈接庫和使用
創(chuàng)建:gcc tomato.c -fPIC -shared -o libfruit.so
使用:gcc test.c -Wl,--rpath,. -L. -lfruit
這樣只要a.out和libfruit.so放在同一個目錄就可以了
與位置無關(guān)的代碼(position-independent code),對于共享庫顯得格外有用,因為每個使用共享庫的進程一般都會把它映射到不同的虛擬地址(盡管共享同一份物理拷貝),只要修改一下偏移量表就可以了。
grep很有用??!
始終將-l函數(shù)庫選項放在編譯命令行的最右邊。
警惕Interpositoning。缺省全局作用域。
準(zhǔn)則:不要讓程序中的任何符號成為全局的,除非有意把他們作為程序的接口之一。
ldd程序print shared library dependencies。
第6章-- 運動的詩章:運行時數(shù)據(jù)結(jié)構(gòu)
編程語言理論的經(jīng)典對立之一就是代碼和數(shù)據(jù)的區(qū)別。
代碼和數(shù)據(jù)的區(qū)別也可以是編譯時和運行時的分界線。編譯器的絕大部分工作都跟翻譯代碼有關(guān);必要的數(shù)據(jù)存儲管理的絕大部分都在運行時進行。
linux可執(zhí)行文件用文件第一個字節(jié)來標(biāo)注,7F開頭,緊跟后面的是"ELF",代表Executable and Linking Format.
可執(zhí)行文件由文本段、數(shù)據(jù)段和bss段組成,運行size a.out可查看各段大小。
bss段保存沒有值的變量,事實上只是,給出了運行時所需要的bss段大小。
運行時數(shù)據(jù)結(jié)構(gòu)有好幾種:堆棧,過程活動記錄,數(shù)據(jù),堆等。
堆棧有3個用處:
堆棧為函數(shù)內(nèi)部聲明的局部變量提供存儲空間。
進行函數(shù)調(diào)用時,堆棧存儲與此有關(guān)的一些維護信息。
堆棧也可以被看作暫時存儲區(qū)。比如計算表達(dá)式,存儲中間結(jié)果。
alloca()函數(shù)分配的內(nèi)存位于堆棧中,函數(shù)結(jié)束后自動銷毀。
發(fā)現(xiàn)數(shù)據(jù)段和文本段的位置,以及位于數(shù)據(jù)段中的堆,方法是聲明位于這些段的變量,并打印它們的地址。
過程活動記錄:局部變量,參數(shù),指向先前結(jié)構(gòu)的指針,返回地址。
Fedora上測了下,一個只有一個int參數(shù)的函數(shù)調(diào)用,要用32個字節(jié),參數(shù)4個,返回地址4,esp和ebp其他不知道。fame.h中是匯編,沒太看懂。
編譯器的設(shè)計者會盡可能地把過程活動記錄的內(nèi)容放到寄存器中,這樣可以提高速度。
static變量保存在數(shù)據(jù)段,而不是堆棧中。
auto關(guān)鍵字幾乎沒什么用處,因為它只能用于函數(shù)內(nèi)部,但是在函數(shù)內(nèi)部聲明的數(shù)據(jù)缺省就是這種分配。
setjmp和longjmp,在C++中變異為更普通的異常處理機制“catch”和“throw”。
對于如何在進程中支持不同的控制線程,只要簡單地為每個控制線程分配不同的堆棧即可。
有用的C語言工具:
indent 代碼縮進工具
默認(rèn)GNU風(fēng)格,使用-kr選項按K&R風(fēng)格。還有各種各樣選項,可以定制。
語法: indent [選項] [源文件列表]
indent [選項] [源文件] [-o 輸出文件]
ldd 用來查看程式運行所需的共享庫,常用來解決程式因缺少某個庫文件而不能運行的一些問題。
nm 打印目標(biāo)文件的符號表。
strace 工具trace system calls and signals
用法:strace [選項] command
gdb---哈哈,常用
time顯示程序所使用的實際時間和CPU時間
gprof列出程序的運行時分析圖。
標(biāo)準(zhǔn)的代碼優(yōu)化技巧包括:消除循環(huán),函數(shù)代碼就地擴展,公共子表達(dá)式消除,改進寄存器分配,省略運行時對數(shù)組邊界的檢查,循環(huán)不變量代碼移動,操作符長度削減(把指數(shù)操作轉(zhuǎn)變?yōu)槌朔ú僮?,把乘法操作轉(zhuǎn)變?yōu)橐莆徊僮骰蚣臃ú僮鳎┑取?/p>
第7章-- 對內(nèi)存的思考
內(nèi)存泄漏(leak)檢查工具:
mtrace
valgrind
malloc所分配的內(nèi)存通常會圓乘為下一個大于申請數(shù)的2的整數(shù)次方。
總線錯誤,幾乎都是由于未對齊的讀或?qū)懸鸬摹?---目前l(fā)inux好像不出現(xiàn)錯誤
段錯誤是由于MMU(內(nèi)存管理單元,負(fù)責(zé)支持虛擬內(nèi)存的硬件)的異常所致,而該異常通常是由于解除引用(查看指針?biāo)傅刂返膬?nèi)容)一個未初始化或非法值的指針引起的。
Keep it Simple, Stupid !
條件操作符簡潔,允許我們高高興興的在一行內(nèi)寫下代碼,而無需不必要的代碼膨脹。
最可能導(dǎo)致段錯誤的常見編程錯誤是:
-
壞指針的錯誤。free(p);后值空 p = NULL;
-
改寫錯誤。如數(shù)組越界。
-
指針釋放引起的錯誤。
第8章-- 為什么程序員無法分清萬圣節(jié)和圣誕節(jié)
很無厘頭的開始。
類型提升:在任何表達(dá)式中,并不局限于涉及操作符和混合類型的操作數(shù)的表達(dá)式。
char, 位段, enum, unsigned char, short, unsigned char -> int
float -> double
任何數(shù)組 -> 相應(yīng)類型的指針。----注意
函數(shù)的參數(shù)也是表達(dá)式,所以也會發(fā)生類型提升。不用函數(shù)原型,會先提升再自動剪裁。
如果使用了函數(shù)原型,缺省參數(shù)提升就不會發(fā)生,與實際類型相符合。----但數(shù)組到指針的提升仍會發(fā)生
不需要按回車鍵就能得到一個字符,單字符I/O----用于游戲編程,這個我就不看了
有限自動機(FSM)可以用作程序的控制結(jié)構(gòu)。它的基本思路是用一張表保存所有可能的狀態(tài),并列出進入每個狀態(tài)時可能執(zhí)行的所有動作,其中最后一個動作就是計算(通常在當(dāng)前狀態(tài)和下一次輸入字符的基礎(chǔ)上,另外再經(jīng)過一次表查詢)下一個應(yīng)該進入的狀態(tài)。你從一個“初始狀態(tài)”開始。在這一過程中,翻譯表可能告訴你進入了一個錯誤的狀態(tài),表示一個預(yù)期之外的或錯誤的輸入。你不停地在各種狀態(tài)間轉(zhuǎn)換,直到到達(dá)結(jié)束狀態(tài)。
在C語言中,有好幾種方法可以用來表達(dá)FSM,但他們絕大多數(shù)都是基于函數(shù)指針數(shù)組。一個函數(shù)指針數(shù)組可以像下面這樣聲明:
void (*state)MAX_STATES;
debugging hooks
調(diào)試器調(diào)試時可以調(diào)用函數(shù),比如gdb用call 函數(shù)名,對于復(fù)雜的數(shù)據(jù)結(jié)構(gòu)可以編寫一個函數(shù),用于遍歷數(shù)據(jù)結(jié)構(gòu)并打印出來。----時過境遷,現(xiàn)在強大的GUI調(diào)試器,這個已不怎么有用了。
可調(diào)式性編碼
可調(diào)式性編碼意味著把系統(tǒng)分成幾個部分,先讓程序總體結(jié)構(gòu)運行。只有基本的程序能夠運行之后你才能為那些復(fù)雜的細(xì)節(jié)完善、性能調(diào)優(yōu)和算法優(yōu)化進行編碼。
有時候,花點時間把編程問題分解成幾個部分往往是解決它的最快辦法。----確實得花時間,動腦筋來分解。
作者描寫其同事,寫散列表就是個例子啊。最初,使散列函數(shù)返回0,這樣所有元素都存儲于第0個位置后面的鏈表中。----這使得程序很容易調(diào)試
復(fù)雜類型轉(zhuǎn)換,先寫一個對象的聲明,然后刪去標(biāo)識符,最后放在左面,如int (*compar)(int *)。
不加類型說明符,聲明變量默認(rèn)是int;函數(shù)默認(rèn)返回值是int, 一般放在eax(第一個寄存器)中。int幾乎是C語言所有的默認(rèn)方式。應(yīng)該也是C最善于處理的數(shù)據(jù)類型。
qsort函數(shù)原型:void qsort(void *base, size_t count, size_t size, int (*compar)(const void* element1, const void *element2));
compar函數(shù)參數(shù)可以定義為(const void *)類型,這需要在compar函數(shù)內(nèi)部cast為所處理類型;也可以直接定義為所處理類型的指針,在調(diào)用qsort函數(shù)時需要將compar函數(shù)cast為(int (*)(const void *, constvoid *)
,一開始我以為這樣不正確(因為qsort函數(shù)內(nèi)部還是會調(diào)用compar的,這樣類型就不匹配了?。?,其實是正確的,因為這種類型檢查是編譯時做的(gcc 使用-c選項),鏈接時不做類型檢查,只要能找到那個函數(shù)名就行,運行時取參數(shù)更不管這些東西了,是用ebp+offset直接抓來的。
第9章-- 再論數(shù)組
數(shù)組的聲明就是數(shù)組,指針的聲明就是指針,兩者不能混淆。聲明與定義必須對應(yīng)。
對于編譯器而言,一個數(shù)組就是一個地址,一個指針就是一個地址的地址。----左值
什么時候數(shù)組和指針是相同的?
C語言標(biāo)準(zhǔn)對此作了如下說明:
-
規(guī)則1. 表達(dá)式中的數(shù)組名(與聲明不同)被編譯器當(dāng)作一個指向該數(shù)組第一個元素的指針。 -
規(guī)則2. 下標(biāo)(subscript)總是與指針的偏移(an offset from a pointer相同 -
規(guī)則3. 在函數(shù)參數(shù)的聲明中,數(shù)組名被編譯器當(dāng)作指向該數(shù)組的第一個元素的指針----這里數(shù)組是指一維數(shù)組
指針有類型限制,是因為編譯器需要知道對指針進行解除引用時應(yīng)該取幾個字節(jié),以及每個下標(biāo)的步長。
sizeof(數(shù)組名)結(jié)果是數(shù)組所占字節(jié)數(shù)(真正的數(shù)組,不是函數(shù)形參),由此可見是可以數(shù)組名包含了長度信息,并可以通過sizeof取得,所以C中檢查數(shù)組是否越界訪問是能夠做到的,但是很容易用指針避開,就像用指針可以修改const一樣。我覺得編譯器可以打開一個選項,是否檢查數(shù)組越界訪問。
把作為形參的數(shù)組和指針等同起來是出于效率原因的考慮。在C語言中,所有非數(shù)組形式數(shù)據(jù)實參均以傳值形式。如果要copy整個數(shù)組,無論在時間上還是內(nèi)存空間上的開銷都可能是非常大的。
int apricot[2][3][5]; // apricot 兩個[3][5]的數(shù)組,2*3個[5]的數(shù)組,2*3*5個int
int (*p)[3][5] = apricot; // 步長 3 * 5
int (*r)[5] = apricot[0]; // 步長 5
int *t = apricot[0][0]; // 步長 1
int u = apricot[0][0][0];
指向數(shù)組第一個元素的指針與數(shù)組名等同。
內(nèi)存中數(shù)組的布局
C語言中,最右邊的下標(biāo)最先變化,這個約定被稱為"行主序"。
只有字符串常量才可以初始化指針數(shù)組,因為可執(zhí)行文件中字符串常量是作為數(shù)據(jù)存儲。而161這樣的字面常量只出現(xiàn)在代碼中。
數(shù)組與指針可交換性的總結(jié):
-
用a[i]這樣的形式對數(shù)組進行訪問總是被編譯器”改寫“或解釋為像*(a+i)這樣的指針訪問。
-
指針始終就是指針。它絕不可以改寫成數(shù)組。只是可以使用下標(biāo)形式訪問指針。
-
在特定上下文中,也就是指針作為函數(shù)的參數(shù)(也就只有這種情況--注意),一個數(shù)組的聲明可以看作是一個指針。作為函數(shù)參數(shù)的數(shù)組始終會被編譯器修改成為指向數(shù)組中第一個元素的指針。
第10章-- 再論指針
數(shù)組和指針參數(shù)是如何被編譯器修改的?
“數(shù)組名被改寫成一個指針參數(shù)”規(guī)則并不是遞歸定義的。數(shù)組的數(shù)組會被改寫成“數(shù)組的指針”,而不是“指針的指針”。
數(shù)組的數(shù)組 char c[8][10]; char (*c)[10]; 數(shù)組的指針
指針數(shù)組 char *c[15]; char**c; 指針的指針
指針的指針 char **c; char **c; 不改變----指針與指針不用修改
數(shù)組的指針 char (*c)[64]; char (*c)[64]; 不改變----注意,指向一個長度為64的char數(shù)組的數(shù)組名的指針,訪問數(shù)組中元素這樣做:(*c)[0]。
int a[20];
int **p = &a; // 錯誤,指針的指針與數(shù)組的指針不兼容
int (*t)[20] = &a; // 正確,t為由20個int的數(shù)組的指針。
----此處括號是必須的,因為[]的優(yōu)先級比*高
Iliffe向量,創(chuàng)建一個一維數(shù)組,數(shù)組中的元素是指向其他東西的指針。
例如main(int argc, char *argv[])
,第二個參數(shù)會被改寫成char **。(注意,只有把二維數(shù)組改為一個指向向量的指針數(shù)組的前提下才可以這么做!)
在C語言中,傳遞多維數(shù)組必須提供除最左面一維以外的所有維的長度。
可以放棄多維數(shù)組的形式,提供自己的下標(biāo)方式,如char_array[row_size*i + j] = ...
模擬動態(tài)數(shù)組,當(dāng)表滿后,用realloc()對數(shù)組重新分配內(nèi)存,并確保realloc操作成功。
重分配操作很可能把原先的整個內(nèi)存塊移到一個不同的位置,這樣表格中元素的地址便不再有效。為了避免麻煩,應(yīng)該使用下標(biāo)而不是元素的地址。----這也是STL中引入迭代器的一個原因吧
“增加”和“刪除”操作都必須通過函數(shù)來進行,這樣才能維持表的完整性。
第11章-- 你懂得C,所以C++不在話下
類內(nèi)部定義的函數(shù)是inline函數(shù)
重載是編譯時解析的。
多態(tài)——運行時綁定。latebinding
new和delete操作符,用于取代malloc()和free()函數(shù),能夠自動完成sizeof的計算工作,并會自動調(diào)用合適的構(gòu)造函數(shù)和析構(gòu)函數(shù)。new能真正的創(chuàng)建一個對象,malloc()函數(shù)只是分配內(nèi)存。
C++的設(shè)計受限于嚴(yán)格的兼容性、內(nèi)部一致性和高效率。
復(fù)用是軟件科學(xué)的一個崇高而又朦朧的目標(biāo)。----很多時候不如另起爐灶從頭開始
管理和市場狀況是導(dǎo)致許多公司破產(chǎn)的原因,比單純的技術(shù)失敗更為常見。那些不時刻注意顧客需求的公司終究難以為繼,最能掌握這項藝術(shù)的公司往往能獲得成功。
附錄A-- 程序員工作面試的秘密
面試的關(guān)鍵在于正確理解問題!你需要仔細(xì)地聽,如果不理解問題或者覺得它的定義不清,可以要求一個更好的解釋。
提供一種尋找可靠答案的好方法。
鏈表環(huán)的檢測。
mango[i++] += y; // i++僅執(zhí)行一次
優(yōu)秀的程序員將會休息的更好,精力更加充沛,而蹩腳的程序員則很可能困得腦袋常常和桌子打架。
人類的最高目標(biāo)是奮斗、尋求、創(chuàng)造。
往期精彩
學(xué)習(xí)嵌入式可以帶娃,不信你們看
第10期 | ringbuff,通用FIFO環(huán)形緩沖區(qū)實現(xiàn)庫
代碼寫得很牛逼但UI界面卻搞得很丑?來,楊工帶你!
分享一個近期開源火爆全網(wǎng)的額溫槍方案(硬件+源碼)
火爆全網(wǎng)開源額溫槍同平臺之華大HC32L136 SDK開發(fā)入門
覺得本次分享的文章對您有幫助,隨手點[在看]
并轉(zhuǎn)發(fā)分享,也是對我的支持。
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!