知識分享:C語言語法總結(jié),初學(xué)者可收藏
C語言編程語法的快速學(xué)習(xí)(不針對考試)
1 .內(nèi)存,寄存器等存放的內(nèi)容斷電以后就會丟失,而且新的數(shù)據(jù)填入內(nèi)存后,舊的內(nèi)容就會被覆蓋。
2.電腦是以二進制存儲內(nèi)容的(客觀),存儲的東西是數(shù)據(jù)還是代碼是人為的,電腦本身并不知道某一段內(nèi)容是數(shù)據(jù)還是代碼。
3.存儲的數(shù)據(jù)超過設(shè)定的容量就會發(fā)生溢出,丟失一部分數(shù)據(jù)。
目前我們遵循的標準是c89/c99標準
在C語言中,單獨一個語句的結(jié)束標志是西文的分號;不管你的語句是放在了一行還是單獨另起一行,但是,如果是花括號構(gòu)成的復(fù)合語句(準確來說整體的語句結(jié)束時的末尾為右花括號}),一般情況下分號可以省略
eg: int a;
{int a=3;
if(a==3) a=4;
else a=5;
}
數(shù)據(jù)類型
最開始我們會學(xué)到一些C語言自己擁有的數(shù)據(jù)類型,也就是基本類型,先介紹整數(shù)類型(有符號的是以補碼的形式存儲)
char類型是character的縮寫,意思是字符類型。它是用來表示一個字符的編碼。在被進行數(shù)學(xué)運算或者位運算的時候會被視為普通的整數(shù)類型,而在其他的情況則會與其他的整數(shù)類型區(qū)別對待,比如在輸出成文字的時候系統(tǒng)會按照文字的某一種編碼(ASCII碼,GB2312,utf-8,big5碼等)根據(jù)char類型的值尋找對應(yīng)的文字,然后按照這個文字的顯示方式(字體)和各種參數(shù)來顯示或者輸出。通常在編譯器的設(shè)定里為1B
int類型(integer)為常用的整數(shù)類型,能夠表示比較大的整數(shù),參與數(shù)學(xué)運算或者位運算。有正負之分。short類型,long類型和int類型的區(qū)別是存儲的數(shù)值范圍是long>=int>=short>=char
unsigned是一個修飾符,用來表示后面的整數(shù)沒有負數(shù),不用考慮數(shù)學(xué)的符號,在表示unsigned int時候,int可以省略。
注意:C語言沒有專門表示邏輯的類型和常量,用整數(shù)表示邏輯真假時,0表示假,非零的數(shù)表示真。邏輯轉(zhuǎn)換為整數(shù)時,真為1,假為0。在c99里,引入了一個新的數(shù)據(jù)類型_Bool型專門表示邏輯類型,不過實際上它也是屬于整數(shù)類型,只不過它只能為0或1,true或者false
接下來是浮點數(shù)類型,它們能表示一定范圍的小數(shù)。表示范圍的大小long double>=double>=float,它們的存儲方式請自行搜索。
viod類型是特殊的類型,它表示什么類型都不是。一般用在函數(shù)的聲明和定義表示不返回數(shù)據(jù)。
定義變量的格式是
數(shù)據(jù)類型 自定義 變量名;
c語言規(guī)定,自定義變量名字不能與c語言自己已經(jīng)定好的名稱重名(如果重名在有些情況下c語言無法判斷這個名字是變量名還是預(yù)約好的名稱),自定義變量名的開頭只能是字母和下劃線,后面可以使用字母,下劃線和數(shù)字。
一般也可以在定義的時候賦予初值其形式是
數(shù)據(jù)類型 自定義變量名=值;
如果不賦值的話,初值是個隨機數(shù)
實質(zhì)是向系統(tǒng)申請一塊內(nèi)存區(qū)域,系統(tǒng)找到一塊合適的地方再進行簡單的標記(比如登記給定的類型,放入指定的值)。(就像是自己提出要租什么類型的房子,房東找到合適的房子給你,然后身份證進行簡單的登記,房子里至于是什么樣房東不管,這也解釋了為什么初始化一個變量以后里面的內(nèi)容是隨機的。 嚴格來說,里面的內(nèi)容不能算是隨機,因為可以跟蹤上一次程序使用這一塊內(nèi)存的操作來推出內(nèi)容是什么,不過誰有這閑工夫干這沒意義的事?)
一般情況下,如果程序發(fā)現(xiàn)變量被賦予的值和它自身的值不相同,會先進行隱式轉(zhuǎn)換(一般是占用空間小的類型向占用空間大的類型轉(zhuǎn)換),就是能簡單的去去小數(shù),把存儲的位數(shù)進行調(diào)整,如果自己沒辦法進行調(diào)整,此時需要強制進行類型轉(zhuǎn)換,格式為(數(shù)據(jù)類型) 最小單位的表達式
變量的修飾關(guān)鍵詞
const關(guān)鍵詞是用來聲明變量所在的內(nèi)存區(qū)域是只讀的,也就是說可以使用其里面的值,但是不能修改,常常用于當(dāng)做常量,或者寫函數(shù)時將不需要修改值的變量設(shè)置成const防止意外修改。
aoto關(guān)鍵詞是默認的關(guān)鍵詞,用來聲明局部變量,生命周期一般是在變量所在的范圍最小的花括號內(nèi)(可以把整個源代碼文件的范圍當(dāng)做一個很大的無名花括號,定義在程序里的變量一般初值全為二進制的0),在生命周期外變量會被銷毀,由于局部變量實在太常用,auto寫的又不是很多,所以在c11標準中auto變成了根據(jù)給定的初值自動設(shè)置變量的類型的關(guān)鍵詞。
register關(guān)鍵字是聲明變量是在寄存器中存儲,寄存器是一個高速小容量靠近CPU的儲存單元,并且寄存器的數(shù)量有限,有些的還有特殊的用途,所以register只是一個建議,而且由于寄存器是一種單獨離散的特殊單元,不能用&取地址(寄存器沒有地址)
static關(guān)鍵字是程序運行時聲明變量的所在的內(nèi)存一直會被保存,直到程序退出內(nèi)存才會釋放這個空間。被其修飾的變量所在的內(nèi)存區(qū)域一般全是二進制的0
extern表示這個全局變量是從別的文件定義的。
常量
常量顧名思義就是不變的量,數(shù)學(xué)里的π永遠等于3.1415926535...,e等于
2.718281828459...,f(x)=x2+2x+1中的數(shù)2,1。類似的,代碼里直接出現(xiàn)的數(shù),和符號代替的數(shù)就是常量。在c語言中基本類型的數(shù)值都有表示方法
在整型常量中,有二進制,十進制,八進制和十六進制表示方法,十進制就跟正常生活數(shù)的表示方法一樣。八進制要在八進制表示的數(shù)前面加一個0,十六進制要在前面加0x或者0X,二進制要在數(shù)的前面加0b,默認情況下,十進制表示的數(shù)都會被認為是int類型,如果想表示無符號類型就要在數(shù)的后面加一個u,長整型要在數(shù)的后面加l,長無符號整型在數(shù)的后面加lu,長長整型要加ll。浮點數(shù)一般是我們生活常用的表達。默認是double類型,要是表示float類型,需要在數(shù)的后面加一個f。
字符型常量是用一對單引號包含一個字符 eg 'c' '1'
字符串(字符數(shù)組常量)是用一對雙引號包含字符串。是特殊的字符數(shù)組常量的表示方法。eg“c++”
基本運算符號
賦值符號=是運算級別倒數(shù)第二的運算符號 它是將右邊的值賦值給左邊,不難理解,賦值符號左邊只能是像可以寫入的變量這樣的存儲單元,所以這樣的存儲單元又叫左值(lvalue),賦值表達式返回的值是等號右邊得到的值。eg a=1;這個返回的值是1
逗號,是運算級別最低的符號,它主要是從最左邊以逗號為分界點,逐一執(zhí)行里面的操作得到數(shù)值,整個返回值的最后結(jié)果是最右邊得到的值。
加號+ 減號- 乘號* 除號/和數(shù)學(xué)意義上的運算是一樣的,他們相對的運算順序也和數(shù)學(xué)的四則運算是一樣的。
求余符號%是計算整數(shù)之間整除以后的余數(shù)。
位左移<<是把一個數(shù)當(dāng)做二進制進行左移,左邊移出的二進制位舍棄,右邊移進來的二進制位用0填充。eg:6<<2表示將6這個int類型左移兩位,得到24.
位右移>>是把一個數(shù)當(dāng)做二進制進行右移,右邊移出的二進制位舍棄,左邊移進來的二進制位用0填充。eg:6>>2表示將6這個int類型右移兩位,得到1.
位與&是把兩個數(shù)的二進制逐個進行與運算。
位或|是把兩個數(shù)的二進制逐個進行或運算。
位取反~是把一個數(shù)的二進制進行取反運算
異或^是把2個數(shù)的二進制進行異或運算
取地址符號&是得到一個變量在內(nèi)存中的地址。(這里的地址是個相對概念,因為在系統(tǒng)里給程序的內(nèi)存地址是個相對地址)
*尋址符號是根據(jù)內(nèi)存地址來指向一個內(nèi)存空間,eg *p=2;將2賦給p里的內(nèi)存地址指向的內(nèi)存單位。
成員運算符.是引出整體里的成員,比如k.name就是調(diào)出k里的小成員name
->指向成員運算符,就是通過其將內(nèi)存地址直接指向成員而不是整體,eg p->name就是p這個指針通過此運算符直接指向那個內(nèi)存單位的成員name
自增++是指存儲單位的值加一個單位的數(shù)值,而自減--是指存儲單位的值減一個單位的數(shù)值。他們在前面表示先進行運算在取值,在后面表示先取值在進行運算(有自增自減運算是因為匯編有專門的指令inc,dec)
符合賦值符號是先計算等號右邊的值,在把左邊的值和右邊計算的結(jié)果進行運算賦值給左值。(有復(fù)合復(fù)制符號是因為匯編里像add eax,ebp都是把左邊的值和右邊的值進行運算并把結(jié)果存入左邊的存儲單元)eg a += 2就是a和2相加,在把結(jié)果給a。
括號()是將括號里的表達式強制提到最高運算的優(yōu)先級,相對于數(shù)學(xué)運算里括號的作用。
邏輯運算
大于>,小于<,不大于<=,不小于>=,不等于!=,等于==表示的意義和數(shù)學(xué)一樣,只不過它返回的是邏輯上的真或者假
邏輯與&&,邏輯或||,邏輯非!和數(shù)學(xué)里的用法是一樣的,不過要注意的是,當(dāng)一個運算只計算了左邊得到的邏輯結(jié)果就能判定整個邏輯運算的結(jié)果時,它會跳過右邊的邏輯運算。
條件運算符?:是計算問號左邊的邏輯真假,如果為真結(jié)果就是冒號左邊的結(jié)果,為假是冒號右邊的結(jié)果。
流程控制語句
如果語句,格式:
if(返回整數(shù)的表達式)
語句1
[else 語句2]
此語句先計算返回整數(shù)的表達式,如果是邏輯上的真,就執(zhí)行語句1,如果是假就執(zhí)行語句2,如果沒有邏輯為假的操作,方括號里的語句可以不寫。
先判斷當(dāng)循環(huán)語句格式:
while(返回整數(shù)的表達式)
語句
此語句先判斷返回整數(shù)的表達式,為真就執(zhí)行循環(huán)語句,在進入下一次循環(huán)判斷,為假就結(jié)束循環(huán)不執(zhí)行語句
后判斷循環(huán)語句格式:
do 循環(huán)語句 while(返回整數(shù)的表達式)
這個先執(zhí)行循環(huán)語句,然后在判斷返回整數(shù)的表達式,為真就繼續(xù)進行循環(huán),為假就結(jié)束循環(huán)。
記次循環(huán)語句格式:
for(語句a;返回整數(shù)的表達式b;語句c) 循環(huán)語句d
首先執(zhí)行語句a,然后計算返回整數(shù)的表達式b,如果為邏輯上的真就執(zhí)行循環(huán)語句d,最后在執(zhí)行語句c進入下一個循環(huán)判斷;如果為假就結(jié)束循環(huán)
注意:循環(huán)語句里可以使用break來跳出循環(huán)體,也可以使用continue來直接進入下一次的循環(huán)。
選擇語句格式
switch(返回整數(shù)的表達式){
case 整數(shù)常量a:語句a1;
語句a2;
。。
語句an;
case 整數(shù)常量b:語句b1;
語句b2;
。。。
語句bn;
...
case 整數(shù)常量n:語句n1;
。。。。
語句nn;
default:語句1;
語句2;
。。。
語句n;
}
此語句是先計算返回整數(shù)的表達式,然后進入花括號與case后的整數(shù)常量進行判斷,遇到相等的整數(shù)常量就在此開始執(zhí)行后面的語句一直執(zhí)行到底,當(dāng)然,也可以中間使用break語句跳出這個花括號的復(fù)合語句。
函數(shù)(構(gòu)成c語言程序最小的單元)
編程的函數(shù)和數(shù)學(xué)里的函數(shù)類似,只不過數(shù)學(xué)里的函數(shù)僅僅只是輸入數(shù)(可以是一個數(shù)或者幾個數(shù))通過一定的方法得到另一個數(shù)。而編程里的函數(shù)不止可以做數(shù)學(xué)計算,還可以干其他的事,而且輸入可以沒有,也可以有好幾個(就行你給一個人發(fā)出命令,可以讓他去寫一篇文章,可以規(guī)定一些要求,也可以什么也不要求,然后返回的東西就是寫好的文章)
函數(shù)的聲明:
數(shù)據(jù)類型 函數(shù)名([數(shù)據(jù)類型 參數(shù)名1,數(shù)據(jù)類型 參數(shù)名2。。。,數(shù)據(jù)類型 參數(shù)名n]);
函數(shù)的定義:
數(shù)據(jù)類型 函數(shù)名([數(shù)據(jù)類型 參數(shù)名1,數(shù)據(jù)類型 參數(shù)名2。。。,數(shù)據(jù)類型 參數(shù)名n]){
語句1。。。
語句n
}
其中函數(shù)不能嵌套定義,也就是說不能在一個函數(shù)的語句里不能在定義一個函數(shù)。
實際上,那些參數(shù)也是函數(shù)里的局部變量,只是擺在了括號里等待數(shù)據(jù)的傳入。而且在c語言里,在調(diào)用函數(shù)時,傳入?yún)?shù)的個數(shù)和類型都要正確。
往深處看,函數(shù)的聲明有些類似于變量的聲明,其實,函數(shù)的聲明這一塊是向系統(tǒng)申請一塊內(nèi)存,然后往這一塊內(nèi)存填充代碼。函數(shù)名是函數(shù)的入口地址,本質(zhì)就是指針。
函數(shù)的調(diào)用形式
存在的函數(shù)名(傳入的參數(shù)1,。。。。,傳入的參數(shù)n)
但調(diào)用的前提是前面必須有函數(shù)的定義或者聲明,否則會出現(xiàn)錯誤
以上的一些規(guī)定其實可以和數(shù)學(xué)的函數(shù)類比,數(shù)學(xué)的函數(shù)哪里學(xué)過嵌套定義另外的函數(shù),但是我們可以在前面設(shè)一個函數(shù),然后在另外一個函數(shù)調(diào)用前面設(shè)好的函數(shù),而且數(shù)學(xué)里前面沒有設(shè)好的函數(shù),后面的函數(shù)不能無中生有調(diào)用前面沒有的函數(shù)(就像你之前如果不知道寫文章是什么意思,老板命令你寫文章,你不知道怎么回事。)
在c語言中,整個程序的入口函數(shù)名為main,定義入口函數(shù)的格式為:
int main(){}和int main(int argc,char**argv){}
其他的類型
數(shù)組類型是為了方便解決一些問題,在內(nèi)存的排列是連續(xù)的。表示方法如下:
數(shù)據(jù)類型 []
數(shù)組變量初始化一般有如下幾個方法
int a[3]={1,2,3}
int a[]={1,2,3,6,7}
int a[10]={1,2,3}
但是數(shù)組在定義后不能直接整體賦值,也就是說,像a={3,4,5,6,7}的賦值將會導(dǎo)致錯誤,這是因為數(shù)組名表示的是指針常量,而不是變量,只能間接通過內(nèi)存復(fù)制來間接賦值。
數(shù)組變量引用的下標一定是有符號的整數(shù)類型(無符號的將會導(dǎo)致程序崩潰)
指針是存儲內(nèi)存地址的存儲單元,它的作用是方便對某一塊內(nèi)存進行操作(比如對另一塊傳入的變量進行操作,對申請到的無名內(nèi)存進行操作等)其基本形式是 數(shù)據(jù)類型 *,而在利用指針的時候,指針的使用方法是 *變量名,整體就變成了指向目標類型的變量了
結(jié)構(gòu)體是指為了方便管理數(shù)據(jù)專門自己設(shè)置的數(shù)據(jù)類型,不管有名還是無名它都會開辟內(nèi)存空間,一般定義方式為
struct 自定義結(jié)構(gòu)體名 {
數(shù)據(jù)類型1 成員名稱1
。。。
數(shù)據(jù)類型n 成員名稱n
};
這里自定義結(jié)構(gòu)體名可以省略,但是這里的分號不可以省略,因為定義的整體就是一個數(shù)據(jù)類型
eg struct student {
unsigned number;
unsigned age;
unsigned score;
} function(){}
這里的函數(shù)的返回類型為結(jié)構(gòu)體student
使用定義的結(jié)構(gòu)體類型的方法是struct 已定義的結(jié)構(gòu)體名
枚舉類型enum在c語言是一種構(gòu)造類型,用于聲明一組命名的常數(shù)。其基本定義格式是 enum 枚舉類型名字 {成員名1[=整數(shù)值],。。。。,成員名n[=整數(shù)]}
如果成員1沒有給出整數(shù),默認為0,之后的元素以1遞增,成員名不能重名。
使用定義的枚舉類型為 enum 定義的枚舉類型名字
共同體(聯(lián)合,union)是一種構(gòu)造類型,幾個成員共用一個內(nèi)存空間,最后的大小取決于占用內(nèi)存最大的成員,其基本形式是
union 共同體名稱{
數(shù)據(jù)類型 成員名1
數(shù)據(jù)類型 成員名2
。。。。
數(shù)據(jù)類型 成員名n
};
使用已定義的共同體類型為 union 已定義的名字
預(yù)處理指令
所有的預(yù)處理指令都是在程序編譯以前就執(zhí)行的指令,且前面都是#開頭。
#include指令是包含指令,在編譯以前將給定的文件包含進去,有兩種形式#include <文件名>和#include "文件名",其中前一個是讓預(yù)處理程序到預(yù)定義的缺省路徑下尋找文件,后一種是讓其先在源代碼文件的當(dāng)前目錄下尋找文件,然后在默認路徑下找。
#define 目標1 結(jié)果1,是講非雙引號之外的內(nèi)容進行簡單的文本替換(結(jié)果1可以有多個空格),常見的形式為
#define pi 3.1415926
#define text “Hello world”
如果定義了函數(shù)的替換,函數(shù)的參數(shù)會在代碼里簡單的替換成目標指令
目標中的 #表示將參數(shù)變成字符串,##是連接兩個字符串的
#define M(x,y) (x)*(y)
M(3+5,2+7)相對于(3+5)*(2+7)
#define paster( n ) printf( "token " #n" = %d ", token##n )
paster(9);相對于printf("token 9 = %d ",token9);
當(dāng)然,如果替換的內(nèi)容很長,又不想寫在一行上,就可以在一行的末尾用結(jié)尾,然后另起一行繼續(xù)寫
#define menutext "1.scanf()
2.printf()
3.exit "
#if預(yù)處理是一個和類似于if語句的預(yù)處理指令,如果為真就執(zhí)行#if和#else或者#elif之間的語句,否則就會執(zhí)行后面的#else或者進行#elif的判斷(else if的省略)
#ifdef和#ifndef比較特殊,它是判斷前面有沒有#define定義的標識符 執(zhí)行方式類似于#if
#endif是結(jié)束前面預(yù)處理指令的判斷
其他
typedef關(guān)鍵詞是為一個數(shù)據(jù)類型其另外一個名字,并不是生成了一個新的類型,形式是typedef 數(shù)據(jù)類型 別名比如
typedef struct {int a;int b; int c;} ok;
typedef unsigned long DWORD;
個人吸收他人的一點見解
其實數(shù)組的定義應(yīng)該是類似于java標準的定義int [2] a={2,3};(實際這樣寫C語言會報錯)而且嚴格意義上來說,a指向的類型是int [2]類型,&a[0]指向的類型是int類型,除非是作為sizeof或者單目&操作符的操作數(shù),C語言都將數(shù)組名弱化為基本的類型只是方便我們的處理。
希望對你有幫助!
————————
另外,對于準備學(xué)習(xí)C/C++編程的小伙伴,如果你想更好的提升你的編程核心能力(內(nèi)功)不妨從現(xiàn)在開始!
微信公眾號:C語言編程學(xué)習(xí)基地
整理分享(多年學(xué)習(xí)的源碼、項目實戰(zhàn)視頻、項目筆記,基礎(chǔ)入門教程)
歡迎轉(zhuǎn)行和學(xué)習(xí)編程的伙伴,利用更多的資料學(xué)習(xí)成長比自己琢磨更快哦!
編程學(xué)習(xí)書籍分享:

粉絲編程交流:
