一下分為幾個部分分別加以說明。
一、關鍵字
1.什麼是定義?什麼是宣告?兩者有何區別?
答:定義是建立乙個物件,並未該物件分配一塊記憶體和取乙個名字,這個名字就是變數名或者物件名;宣告是告訴編譯器這個變數或者物件的記憶體已經存在,這裡只是引用。兩者最重要的區別在於,定義建立了物件並為物件分配了記憶體,而宣告沒有分配記憶體。
2.static關鍵字的作用
答:static既可以修飾變數,也可以修飾函式,但兩者的作用不一樣,下面分別加以說明:
(1)static修飾變數
變數又分為全域性變數和區域性變數,被static修飾後的變數的內存在靜態儲存區,準確的說應該是 .data 段(《程式設計師自我修養》上有詳細介紹)
a)靜態全域性變數
對於一般的全域性變數,其生存週期和程式一樣,作用域為整個檔案,而且如果其他檔案想引用該全域性變數的話,可以使用extern關鍵字宣告即可。但是當全域性變數被static修飾以後,在原來基礎上唯一改變的是,其他檔案無法再通過extern進行引用。所以一般程式設計時都會加上static,這樣就不用擔心自己的變數和其他人定義的變數在命名上發生衝突了。
b)靜態區域性變數
靜態區域性變數的作用域和區域性變數一樣,只侷限於某個函式內,其他函式無法引用。但也有其特殊的地方,一般的區域性變數在函式呼叫完成以後會被系統自動釋放,但是對於靜態區域性變數其生存週期和全域性變數的週期一樣;靜態區域性變數只初始化一次,下次呼叫時保持上一次的值而不會重複初始化。
(2)static修飾函式
static修飾函式時,函式的作用域僅侷限於本檔案(所以又稱為內部函式)。使用內部函式的好處是不用擔心自己寫的函式和其他檔案的函式重名。
3.變數命名規則
從我寫程式開始,需要定義變數時一直都是看哪個字母閒著就用哪個,常用的有i,j,k......等。程式**比較少時這樣寫也沒什麼能看懂,但是一旦程式**很多時,再這樣給變數命名就會帶來很多不必要的麻煩。大家可能和我剛開始一樣覺得這是乙個很小的問題,但是我發現,養成乙個很好的命名習慣不是一下子就能做到的,需要自己在平時養成這樣的習慣,下面簡單說一下命名規則:
(1)命名時要保證最短的變數名,但要包含最大的資訊量;
(2)駝峰式命名,當識別符號由多個詞組成時,每個詞的第乙個字母大寫,其餘全部小寫;
(3)識別符號分為兩部分:字首_含義。下面列出常用的字首縮寫:
bool--bchar--cint--i short--s long--l unsigned--u double--u
pointer--p enum/struct/union--st function_pointer--fp array--*_a typedef enum/struct/union-- *_st
(4)所用的巨集定義、列舉常量和const修飾的常量全部大寫
4.關鍵字sizeof
首先要說明的一點是sizeof不是函式,而是乙個關鍵字,是乙個運算子。
sizeof計算變數所佔空間大小時,括號可以省略;但是就算某種資料型別的記憶體大小時不能省略。舉例如下:
int i= 0;
sizeof(int) sizeof(i) sizeof i //均正確
sizeof int //錯誤
5.if的條件表示式怎麼寫
if語句在程式中使用的很是頻繁,但大家一般都不會去思考怎麼寫乙個比較合理或者規範的條件表示式,這裡說一種常用的規範:
(1)bool變數和零值比較
if(btestflag) 或 if(!btestflag)
(2)float/double變數和零值比較
float ftestval = 0.0;
const double epsinon = 0.000001;
if(ftestval >= -epsinon && ftestval <= epsinon)
(3)z指標變數和零值比較
if(null == p) 或者if(null != p)
6.空語句的寫法
對於寫空語句,如果直接寫乙個「;」使**不易閱讀。建議寫成 null; 這種形式。
7.關鍵字const
(1)const修飾變數
const修飾變數時,變數變為唯讀變數。但竟然是變數,那就不能作為定義陣列時的大小出現,因為陣列的大小必須在編譯時確定,必須為乙個常量。
(2)const修飾指標
const int *p;
int const *p;
int *const p;
const int *const p;
這裡提供一種簡單的方法來判斷const到底修飾的是p還是*p,總結起來就是一句話「忽略型別,淨水樓台先得月」。我們判斷const的修飾物件時可以忽略型別名,如上面的我們可以忽略int,則變成:
const *p;
const *p;
const p;
const *const p;
8.關鍵字 volatile
遇到這個關鍵字宣告的變數,編譯器對該變數訪問時不再進行優化,從而可以提供對特殊位址的穩定訪問。
先看看下面的例子:
int i=10;
int j = i;//(1)語句
int k = i;//(2)語句
這時候編譯器對**進行優化,因為在(1)、(2)兩條語句中,i 沒有被用作左值。這時候編譯器認為i 的值沒有發生改變,所以在(1)語句時從記憶體中取出i 的值賦給j 之後,這個值並沒有被丟掉,而是在(2)語句時繼續用這個值給k 賦值。編譯器不會生成出彙編**重新從記憶體裡取i 的值,這樣提高了效率。但要注意:(1)、(2)語句之間i 沒有被用作左值才行。
再看另乙個例子:
volatile int i=10;
int j = i;//(3)語句
int k = i;//(4)語句
volatile關鍵字告訴編譯器i是隨時可能發生變化的,每次使用它的時候必須從記憶體中取出i的值,因而編譯器生成的彙編**會重新從i 的位址處讀取資料放在k 中。
二、符號
1.注釋符號
(1)編譯器剔除注釋時不是簡單的去掉,而是用空格來替換
(2)/* */不能巢狀
2.++/--運算子
++/--在遇到逗號、分號時認為本計算單元已經結束,會進行自加或自減。
三、預處理
1.預處理有三種--檔案包含、巨集定義和條件編譯,這是三種預處理指令,不是c語言的一部分。
2.#運算子
宣告乙個符號為巨集引數,如下:
#define sqr(x) printf("the square of "#x" is %d.\n",((x)*(x))); //被#修飾後,這裡的x成為了巨集引數
再使用:
sqr(8);
則輸出的是:
the square of 8 is 64.
四、指標和陣列
1.null不要寫成null或者null,影響**的移植性。
2.如何將陣列寫入指定位址。
如往記憶體0x12ff7c位址存入乙個整數0x100:
int *p = (int*)0x12ff7c;
*p = 10;
或者:*(int*)0x12ff7c = 0x100;
3.當一維陣列作為函式引數的時候,編譯器總是把它解析成乙個指向其首元素位址的指標。
4.函式指標、函式指標陣列和指向函式指標陣列的指標
函式指標:char* (*pfunc)(char *p);
函式指標陣列:char* (*pfunc[3])(char *p);
指向函式指標陣列的指標:char* (*(*pfunc[3])(char *p);
五、記憶體管理
1.堆、棧和靜態區
靜態區:儲存自動管全域性變數和static變數。靜態區的內容在整個程式的宣告週期內都存在,由編譯器在編譯的時候分配。
棧:儲存區域性變數。棧上的內容只在函式的範圍內存在,當函式執行結束,這些內容也會自動銷毀。其特點是效率高,但空間大小有限。
堆:由malloc系列函式或new操作符分配的記憶體。其生命週期由free或delete決定。在沒有釋放之前一直存在,知道程式結束。其特點是使用靈活,空間比較大,但容易出錯。
2. 使用malloc分配記憶體時,如果分配失敗則返回null。所以在每次使用malloc函式以後都要使用if(null != p)來判斷一下是否分配成功。
3. 使用free釋放記憶體後要將指標變數的值置為null。
C語言程式設計易錯點總結
二 變數類 三 陣列類 四 指標類 五 預處理類 六 輸入輸出類 高亮 c語言是一門面向過程的 抽象化的通用程式語言,廣泛應用於底層開發。它是目前最著名,最流行的語言,效率高 功能強 用法靈活。在學習程式語言的過程中,最怕最難的就是找bug,而找bug又是必不可少的能力,甚至可能是程式設計中必經的乙...
C 易錯點總結
1.下面這段 考察變數的作用域問題。cpp view plain copy include using namespace std void other intmain 答案如下 main 0 10 0 other 4 0 15 main 0 10 8 other 6 4 15 考察點 區域性作用域...
C語言易錯點
c語言易錯點 1.每個c語言程式中main函式是有且只有乙個的。2.演算法可以沒有輸入,但必須要有輸出。3.在函式中不可以再定義函式。4.break可用於迴圈結構和switch語句。5.break和continue的區別在於前者是跳出迴圈,後者是結束本次迴圈。6.逗號的運算子的級別最低。7.c語言對...