悟道系列之——C語言
這是我的第一篇博文。對我來說CSDN并不陌生,但一直以來我都是一個默默的潛水者,可是今天我要冒泡了。特意選了十月一日來重新注冊賬號,我想賦予這個日子以新的意義。在進入正題之前,我想有必要簡單的向大家介紹一下自己。
本人80后后,剛畢業于一所普通師范類學校的化學專業。本人形象猥瑣,身無長物,自覺難以為祖國的教育事業服務,遂混跡于程序猿們的隊伍之中。
本科四年,前半段渾渾噩噩,后半段幡然悔悟。而正式決定踏入編程,則已是2011年的愚人節了。(我有意選擇這個日子作為紀念)屈指算來今天竟剛滿一年半,這真是一個讓人驚喜的巧合。
寫了這么多廢話,無非是想讓大家明白:這不是一個大牛的博客。如果您想從中尋找一些金玉良言,那么讓您失望了。這里只是一個技術菜鳥對他一路以來在編程中思考和領悟的記錄,分享給那些在學習中有些困惑的初學者。
從C講起吧,以前學習時做了很多筆記,現在把它們篩選整理成電子版的形式分享出來,也方便自己以后查閱。
本系列文章中的讀者應該是 C語言語法的入門者。
因為本文不是零基礎掃盲貼。要熟悉C的語法 隨便一本教材反復研讀實踐即可。
此文大多是個人的讀書筆記、編程感悟及曾經遇到的問題,至于一些技巧和代碼風格網上資源不在少數,故本文很少提及。
提綱:
**壹**:變量的作用域及存儲方式
[**貳**:幾個關鍵字、幾個運算符、隱式轉換/溢出、表達式求值的順序、左值和右值](http://blog.csdn.net/yang_yulei/article/details/8068210)
[**叁**:數組與指針(一)](http://blog.csdn.net/yang_yulei/article/details/8071047)
[**肆**:數組與指針(二)](http://blog.csdn.net/yang_yulei/article/details/8071068)
[**伍**:字符串、函數、動態內存分配](http://blog.csdn.net/yang_yulei/article/details/8072552)
[**陸**:結構、聯合、位段、位級操作](http://blog.csdn.net/yang_yulei/article/details/8072567)
[**柒**:文件、輸入輸出函數](http://blog.csdn.net/yang_yulei/article/details/8087957)
[**捌**:預處理、程序調試、編程風格](http://blog.csdn.net/yang_yulei/article/details/8098329)
[**玖**:常用庫函數](http://blog.csdn.net/yang_yulei/article/details/8098357)
開場白:
**【C語言結合了匯編語言的所有威力和匯編語言的所有易用性】**
壹
**變量的作用域:**
1,?局部變量
局部變量是在函數內定義的變量,其作用域僅限于函數內,在函數內才引用,即可以對它賦值或取值。在作用域外,使用它們是非法的。
2,?全局變量
全局變量是定義在函數之外的變量,它的作用域是從定義處開始,到所在文件的結束。即從定義之處起,它可以在文本的所有函數中使用。
【全局變量的命名最好取有特殊含義的標識符(例如在變量名前加q_)。防止不經意間改變了它的值。***全局變量違反了最低特權原則,而且是糟糕的軟件工程方法***】
3,?外部變量
全局變量的作用域是在所在文件的整個文件,而一個文件中的全局變量的作用域還可以擴展到其它文件。某個文件中引用另一個文件中的全局變量,只要用extern聲明,說明這個變量是在其它文件中已經定義過的外部變量。那么,該文件中不會為外部變量分配內存。
幾點說明:
(1)關于外部變量聲明的定義和引用
C所存在的一個眾所周知的缺陷是很難區分外部變量聲明的定義和引用。(來源于《C語言參考手冊》)
標準C:在頂層聲明中,如果出現了初始化值,它就被認為是個定義性聲明。其它的聲明則是引用性聲明。在C程序的所有文件中,同一個變量的定義性聲明只能出現一次。
~~~
int x ; //引用 (C++認為其是定義)
int x=0; //定義
extern int x ; //引用
extern int x =0 ; //定義 (C++認為非法)
~~~
建議:
A,每個外部變量具有一個單獨的定義點(在源文件中)。**在定義性聲明中,省略extern類別,并提供一個顯式的初始化值:? int? errcnt = 0 ;**
【所以說,全局變量就是外部變量】
B,在其它引用外部變量的每個源文件或頭文件中,**在引用性聲明中,使用存儲類別extern,并且不要包含初始化值:? extern? int?errcnt? ;**
**【注意:】**
**外部變量的引用類型必須和其定義類型一致!**(分別編譯的時候編譯器無法檢查兩者類型是否一致,但是若不一致運行時會出錯)
~~~
//file1.c------
intarr[80];
//file2.c--------
externint *arr;
intmain()
{
arr[1]= 100;
printf("%d\n",arr[1]);
return0;
}
~~~
該程序可以編譯通過,但運行時會出錯。原因是,在另一個文件中用 extern int *arr來外部聲明一個數組并不能得到實際的期望值,因為他們的類型并不匹配。導致指針實際并沒有指向那個數組。修改:extern int arr[]。
數組是數組指針是指針。雖然在函數間傳遞時數組名會退化為常量指針。在定義的時候它們是不同的,編譯器給它們分配不同的空間。在外部聲明引用時,編譯器見到int*arr只會認為其是指針,由于其是全局變量,故給其初始化為0,而編譯器見到extern int arr[]會知道arr為外部定義的數組。
(2)同一源文件中,允許全局變量和局部變量同名,但在局部變量的作用域內,全局變量不起作用。【**即當全局變量與局部變量相遇,局部變量屏蔽全局變量**】
~~~
#include <stdio.h>
int a=1 , b=2, c=3 ;
int main(void)
{
{
int a=20, b=30 ;
c=(a-=10)+b++ ;
printf("%d,%d,%d\n",a,b,c) ; //輸出10,31,40
}
printf("%d,%d,%d",a,b,c) ; //輸出 1,2,40
return0 ;
}
//位于一個花括號之間的所有語句成為一個代碼塊,在代碼塊開始位置聲明的變量的作用域只在此代碼塊中
//花括號的作用就是打包,使之成為一個整體,并與外界絕緣。
~~~
**變量的存儲方式**
1,?動態存儲:在程序的執行過程中,使用它時才分配存儲單元,使用完畢立即釋放。
(其存儲空間在棧上)
自動變量的類型說明符為:auto自動變量是動態存儲方式,凡未加存儲類型說明的變量均視為自動變量。自動變量的作用域和生存期都局限于定義它的個體內。
2,?靜態變量:在變量定義時就分定存儲單元并一直保持不變,直至程序結束。
(其存儲空間在堆上)
【**靜態變量的初值是在編譯時賦予的,不是在程序執行期間賦予的**】
(1)??????靜態局部變量
在局部變量的說明前加上static 就構成靜態局部變量。
A,靜態局部變量在函數內定義,但**它的生存期為整個程序**。
**B,**其生存期雖為整個程序,但其作用域與自動變量相同,**只能在定義的函數內使用。退出函數后,盡管該變量還在,但已不能再使用。**
C,允許對靜態局部變量賦初值。若未賦初值,則由系統自動賦0值
D,只在第一次調用函數時給靜態變量賦初值,再次調用定義它的函數時,其保存了前一次被調用后留下的值。
【因此,當多次調用一個函數且要求在調用之后保留某些變量的值時,可采用靜態局部變量】
(2)??????靜態全局變量
在全局變量前加static,就構成了靜態的全局變量。它們都是靜態存儲方式。但兩者的區別在于:作用域的擴展上。
全局變量的作用域可以擴展到整個源程序。靜態全局變量的作用域局限于一個源文件內。
【因此,全局變量加上static限制,是為了避免在其它源文件中被引用,防止出錯】
C語言中static的作用:
1、?修飾變量。
靜態全局變量,作用域僅限于變量被定義的文件中。
靜態局部變量,在函數體中定義的,就只能在這個函數里用了。
2、?修飾函數。
指函數的作用域僅局限于本文件(內部函數),使用內部函數的好處是防止與其他文件中的函數命名沖突。