if( i == 0); if(i == 1) // 1 if( i == TURE); if( i == FALSE); //2 if(i); if(!i); //3
注意:大家知道if語句是靠其後面括號裡表達式的值來進行分支跳轉。表達式為真,則執行if語句後面緊跟的代碼;否則不執行。那顯然,第三組寫法很好。不會引起誤會,也不會因為TRUE,FALSE的不同定義值而出錯。 當然,還有float變量和“零值”比較。指針變量與“零值”比較。大家可以自己研究。我在這裡就不再講述了。 2.while循環使用 1).講述一個例子來剖析一下吧
#include int main() { int a = 1; int b = 2; int c = 2; int t; while (a < b < c) { t = a; a = b; b = t; c--; } printf("%d %d", a, c); system("pause"); return 0; }
分析一下結果會是什麼?a的值為1,c的值為0;while循環也關注的是括號裡面的值是否為真,那麼a 3.for循環的使用 同樣用一個例子來分析一下
#include int main() { int i = 0; int arr[10] = {0}; for (i = 0; i < 10; i++) { arr[i] = i; } for (i = 0; i < 10; i++) { printf("%d\n", arr[i]); } system("pause"); return 0; }
當然這個程序是非常簡單,但足以說明問題。當i = 10的時候會跳出循環。那麼就很簡單明了了。當然for循環也可以用while循環改寫。 二.數組 數組是儲存同一數據類型的一組有序的數據的集合。 數組中需要注意的點: 1.數組用循環語句賦值。同樣是上面的for循環,可以自己試試將條件 i<10改為 i<11試試。程序會無條件的奔潰。因為你操作越界了,訪問了不屬於你自己的內存。 2.數組下標的操作。記住一點的就是,數組的下標是從0開始,並不是1!!! 3.數組和逗號表達式一起迷惑你。
#include int main() { int a[3][2] = { (0, 1), (2, 3), (4, 5) }; int *p = a[0]; printf("%d", p[0]); system("pause"); return 0; }
這個時候的p[0]等於1;為什麼,不是應該是0?這就考到了逗號表達式,逗號表達式最後一個值才是整個表達式的值,那麼上面的代碼就變成了 int a[3][2] = {1,3,5};如果這樣說,你是不是就會做對呢? 4.二維數組在內存中的存儲 假如二維數組
int arr[3][3] = {0};
二維數組在內存中存儲是線性的。我們可以用一維數組的方式來理解二維數組,上述代碼代表的二維數組有三個元素,arr[0],arr[1],arr[2],同時每一個元素分別有三個元素,arr[0][0],arr[0][1],arr[0][2]...,那麼可以這樣理解arr[0],arr[1],arr[2],就是一維數組的數組名,只不過這三個一維數組是有聯系的並且在內存中是連續開辟的。 同理我們可以推到三維數組直到n維數組。只要你有時間並且有毅力和決心(意義不大)。哈哈!! 5.字符數組 字符數組的賦值方式,為什麼要提字符數組的賦值方式,本人認為這和字符串的操作息息相關,看看兩種不同的賦值方式。 1).
char arr[]={'i',' ','a','m',' ','h','a','c','k','e','r'};
可以預見的是,沒有‘\0’;那麼這個字符數組所儲存的字符串是不會使用一系列的字符串操作函數。如果對常見的字符串操作函數不太了解,那麼訪問下面的鏈接,http://10799170.blog.51cto.com/10789170/1715083 幫助你了解常見的字符串操作函數的實現與注意的事項。言歸正傳,第二種賦值方式。 2). char arr[] = "i am hacker"; 這種賦值方式,是最常見也是經的起考驗,建議大家就這樣使用字符數組的賦值。這種賦值方式不會丟掉“\0”。那麼,問題來了,可不可以這樣賦值?
char arr[] = {"i am hacker"}; char arr[] { = "i am hacker"};
答案是肯定的,有興趣的讀者可以在《c語言深度剖析》第二章第6小節看到。 6.總結一下: 1).自己給數組在內存中賦值的時候,千萬注意內存越界的問題。 2).數組的下標操作。 3).字符數組的“\0”。 4).二維數組的賦值方式,理解方式以及使用方式。 三.指針 指針是地址。我在初學指針的時候,總是分不清楚,指針和指針變量和它指向的地址中的內容的區別,所幸,我在鑽研了一下午理解了指針這個東西。得益於一本叫做《c和指針》的書,裡面講述的清楚易懂。 1.一級指針 定義一個一級指針 1 int *p = NULL; 首先要說的是,指針就是地址,指針變量就是用來保存指針指向的那塊空間的地址,“*”就是打開這塊內存的鑰匙。其次,指針的定義和賦值是兩碼事,不可以混為一談。最後我也曾經寫過自己對指針,數組指針的理解。讀者有興趣可以打開下面的鏈接 1).指針的笑話(在vc6.0中實現)
int *p = (int *)ox12ff7c; //這個地址必須是內存開始給變量分配地址的第一個,要不是 //不會有作用! *p = NULL; p = NULL;
讀者可以自己試試結果是什麼。 2).談談指針的安全 指針是可以指向內存中的任何地址的,但是在一個程序中,總是只有自己的棧幀,或者儲存在靜態去和堆上的內存。如果一不小心訪問到不屬於自己的內存,並改掉其中的值。對於一個大型程序來說,調試都是一個非常龐大的工作。所以,在使用指針的時候千萬要小心。杜絕野指針!! 3).const和assert修飾指針 不需要修改指針指向的值,請必須加上const修飾
const int *p; int const *p; int * const p; const int * const p;
讀者可以嘗試著分析上面的語句代表著什麼。 assert只在debug版本生效,在release版本沒有意義。在debug版本可以幫助我們檢驗指針的有效性。大公司面試的時候很注重這一定。 自己在學習的時候看的書是《c語言深度剖析》和《c和指針》。讀者可以自己進一步了解。 四.內存操作 說到內存操作,不得不提到棧幀。讀者可以參考我原來寫過的一片博文 附上url http://10799170.blog.51cto.com/10789170/1715186 那麼我們在這裡就主要討論討論malloc開辟內存時應該注意的問題。 1).動態開辟內存後,需要判斷內存是否開辟成功。 如果內存沒有開辟成功,我們直接使用會造成訪問越界; 2).在使用完成後必須使用free函數釋放掉內存,其原理是將指針與內存切斷聯系。 會造成內存洩漏。很危險! 3).使用完成後指針應賦為NULL;杜絕野指針。 沒有及時將指針賦值為NULL,指針會指向“垃圾”內存! 五.函數 函數這一部分,本來是不願意拿出來說的,畢竟每一個學習c語言的人,幾乎都在寫函數。那麼我們就總結一下函數的好處吧。 1).降低復雜性 2).避免重復代碼 3).限制改動帶來的影響。 4).隱含順序 5).改進性能 6).進行集中控制 讀者需要了解請參照《c語言深度剖析》。 六.結構體 說說我對結構體的感悟吧,不再談語法。 1.結構體是一個自定義的類型,可以用這個類型定義結構體變量。 2.結構體不同於數組,它可以將集中不同的數據類型集中在一起。 3.是實現鏈表的結點。 4.本人用結構體實現過一個簡易的電話本,附上url