- 相關(guān)推薦
c語(yǔ)言讀書(shū)筆記
C語(yǔ)言是一門(mén)通用計(jì)算機(jī)編程語(yǔ)言,應(yīng)用廣泛。C語(yǔ)言的設(shè)計(jì)目標(biāo)是提供一種能以簡(jiǎn)易的方式編譯、處理低級(jí)存儲(chǔ)器、產(chǎn)生少量的機(jī)器碼以及不需要任何運(yùn)行環(huán)境支持便能運(yùn)行的編程語(yǔ)言。大學(xué)網(wǎng)整理了C語(yǔ)言的讀書(shū)筆記,歡迎大家閱讀。
c語(yǔ)言讀書(shū)筆記
《C 語(yǔ)言深度解剖》這本書(shū)是一本“解開(kāi)程序員面試筆試的秘密”的好書(shū)。作者陳正沖老師提出“以含金量勇敢挑戰(zhàn)國(guó)內(nèi)外同類(lèi)書(shū)籍”,確實(shí),這本書(shū)中的知識(shí)點(diǎn)都是一些在面試中常見(jiàn)的考點(diǎn),并且很多都是我們平常不注意的點(diǎn),對(duì)于我們深入理解C語(yǔ)言確實(shí)很有幫助。
第1章關(guān)鍵字
1.register
雖然寄存器的速度非?,但是使用register修飾符也有些限制的:register變量必須是能被CPU寄存器所接受的類(lèi)型。
意味著register變量必須是一個(gè)單個(gè)的值,并且其長(zhǎng)度應(yīng)小于或等于整型的長(zhǎng)度。而且register變量可能不存放在內(nèi)存中,
所以不能用取址運(yùn)算符“&”來(lái)獲取register變量的地址。
2.static修飾符
(1)修飾變量
靜態(tài)局部變量,在函數(shù)體里面定義的,就只能在這個(gè)函數(shù)里用了,同一個(gè)文檔中的其他函數(shù)也用不了。由于被static修飾的變量總是存在內(nèi)存的靜態(tài)區(qū),所以即使這個(gè)函數(shù)運(yùn)行結(jié)束,這個(gè)靜態(tài)變量的值還是不會(huì)被銷(xiāo)毀,函數(shù)下次使用時(shí)仍然能用到這個(gè)值。
(2)修飾函數(shù)
第二個(gè)作用:修飾函數(shù)。函數(shù)前加static使得函數(shù)成為靜態(tài)函數(shù)。但此處“static”的含義不是指存儲(chǔ)方式,而是指對(duì)函數(shù)的作用域僅局限于本文件(所以又稱(chēng)內(nèi)部函數(shù))。使用內(nèi)部函數(shù)的好處是:不同的人編寫(xiě)不同的函數(shù)時(shí),不用擔(dān)心自己定義的函數(shù),是否會(huì)與其它文件中的函數(shù)同名。
關(guān)鍵字static有著不尋常的歷史。起初,在C中引入關(guān)鍵字static是為了表示退出一個(gè)塊后仍然存在的局部變量。隨后,static在C中有了第二種含義:用來(lái)表示不能被其它文件訪(fǎng)問(wèn)的全局變量和函數(shù)。為了避免引入新的關(guān)鍵字,所以仍使用static關(guān)鍵字來(lái)表示這第二種含義。
3.if語(yǔ)句使用注意
先處理正常情況,再處理異常情況。
在編寫(xiě)代碼是,要使得正常情況的執(zhí)行代碼清晰,確認(rèn)那些不常發(fā)生的異常情況處理代碼不會(huì)遮掩正常的執(zhí)行路徑。這樣對(duì)于代碼的可讀性和性能都很重要。因?yàn)?if
語(yǔ)句總是需要做判斷,而正常情況一般比異常情況發(fā)生的概率更大(否則就應(yīng)該把異常正常調(diào)過(guò)來(lái)了),如果把執(zhí)行概率更大的代碼放到后面,也就意味著if語(yǔ)句將進(jìn)行多次無(wú)謂的比較。
另外,非常重要的一點(diǎn)是,把正常情況的處理放在if后面,而不要放在else后面。當(dāng)然這也符合把正常情況的處理放在前面的要求。
4.千萬(wàn)小心又小心使用void指針類(lèi)型。
按照ANSI(AmericanNationalStandardsInstitute)標(biāo)準(zhǔn),不能對(duì)void指針進(jìn)行算法操作,即下列操作都是不合法的:
void*pvoid;
pvoid++;//ANSI:錯(cuò)誤
pvoid+=1;//ANSI:錯(cuò)誤
ANSI標(biāo)準(zhǔn)之所以這樣認(rèn)定,是因?yàn)樗鼒?jiān)持:進(jìn)行算法操作的指針必須是確定知道其指向數(shù)據(jù)類(lèi)型大小的。也就是說(shuō)必須知道內(nèi)存目的地址的確切值。
例如:
int*pint;
pint++;//ANSI:正確
但是大名鼎鼎的GNU(GNU'sNotUnix的遞歸縮寫(xiě))則不這么認(rèn)定,它指定void*的算法操作與char*一致。因此下列語(yǔ)句在GNU編譯器中皆正確:
pvoid++;//GNU:正確
pvoid+=1;//GNU:正確
在實(shí)際的程序設(shè)計(jì)中,為符合ANSI標(biāo)準(zhǔn),并提高程序的可移植性,我們可以這樣編寫(xiě)實(shí)現(xiàn)同樣功能的代碼:
void*pvoid;
(char*)pvoid++;//ANSI:正確;GNU:正確
(char*)pvoid+=1;//ANSI:錯(cuò)誤;GNU:正確
GNU和ANSI還有一些區(qū)別,總體而言,GNU較ANSI更“開(kāi)放”,提供了對(duì)更多語(yǔ)法的支持。但是我們?cè)谡鎸?shí)設(shè)計(jì)時(shí),還是應(yīng)該盡可能地符合ANSI標(biāo)準(zhǔn)。
5.const與宏
節(jié)省空間,避免不必要的內(nèi)存分配,同時(shí)提高效率
編譯器通常不為普通const只讀變量分配存儲(chǔ)空間,而是將它們保存在符號(hào)表中,這使得它成為一個(gè)編譯期間的值,沒(méi)有了存儲(chǔ)與讀內(nèi)存的操作,使得它的效率也很高。
例如:
#define M 3//宏常量
const int N=5;//此時(shí)并未將N放入內(nèi)存中
......
inti=N;//此時(shí)為N分配內(nèi)存,以后不再分配!
intI=M;//預(yù)編譯期間進(jìn)行宏替換,分配內(nèi)存
intj=N;//沒(méi)有內(nèi)存分配
intJ=M;//再進(jìn)行宏替換,又一次分配內(nèi)存!
const定義的只讀變量從匯編的角度來(lái)看,只是給出了對(duì)應(yīng)的內(nèi)存地址,而不是象#define一樣給出的是立即數(shù),所以,const定義的只讀變量在程序運(yùn)行過(guò)程中只有一份拷貝(因?yàn)樗侨值闹蛔x變量,存放在靜態(tài)區(qū)),而#define定義的宏常量在內(nèi)存中有若干個(gè)拷貝。#define宏是在預(yù)編譯階段進(jìn)行替換,而const修飾的只讀變量是在編譯的時(shí)候確定其值。
#define宏沒(méi)有類(lèi)型,而const修飾的只讀變量具有特定的`類(lèi)型。
6.最易變的關(guān)鍵字----volatile
volatile是易變的、不穩(wěn)定的意思。很多人根本就沒(méi)見(jiàn)過(guò)這個(gè)關(guān)鍵字,不知道它的存在。也有很多程序員知道它的存在,但從來(lái)沒(méi)用過(guò)它。我對(duì)它有種“楊家有女初長(zhǎng)成,養(yǎng)在深閨人未識(shí)”的感覺(jué)。volatile關(guān)鍵字和const一樣是一種類(lèi)型修飾符,用它修飾的變量表示可以被某些編譯器未知的因素更改,比如操作系統(tǒng)、硬件或者其它線(xiàn)程等。遇到這個(gè)關(guān)鍵字聲明的變量,編譯器對(duì)訪(fǎng)問(wèn)該變量的代碼就不再進(jìn)行優(yōu)化,從而可以提供對(duì)特殊地址的穩(wěn)定訪(fǎng)問(wèn)。
先看看下面的例子:
int i=10;
int j=i;//(1)語(yǔ)句
int k=i;//(2)語(yǔ)句
這時(shí)候編譯器對(duì)代碼進(jìn)行優(yōu)化,因?yàn)樵?1)(2)兩條語(yǔ)句中,i沒(méi)有被用作左值。這時(shí)候編譯器認(rèn)為i的值沒(méi)有發(fā)生改變,所以在(1)語(yǔ)句時(shí)從內(nèi)存中取出i的值賦給j
之后,這個(gè)值并沒(méi)有被丟掉,而是在(2)語(yǔ)句時(shí)繼續(xù)用這個(gè)值給k賦值。編譯器不會(huì)生成出匯編代碼重新從內(nèi)存里取i的值,這樣提高了效率。但要注意:(1)(2)語(yǔ)句之間i沒(méi)有被用作左值才行。
再看另一個(gè)例子:
volatile int i=10;
int j=i;//(3)語(yǔ)句
int k=i;//(4)語(yǔ)句
volatile關(guān)鍵字告訴編譯器i是隨時(shí)可能發(fā)生變化的,每次使用它的時(shí)候必須從內(nèi)存中取出i的值,因而編譯器生成的匯編代碼會(huì)重新從i的地址處讀取數(shù)據(jù)放在k中。
這樣看來(lái),如果i是一個(gè)寄存器變量或者表示一個(gè)端口數(shù)據(jù)或者是多個(gè)線(xiàn)程的共享數(shù)據(jù),就容易出錯(cuò),所以說(shuō)volatile可以保證對(duì)特殊地址的穩(wěn)定訪(fǎng)問(wèn)。
但是注意:在VC++6.0中,一般Debug模式?jīng)]有進(jìn)行代碼優(yōu)化,所以這個(gè)關(guān)鍵字的作用有可能看不出來(lái)。你可以同時(shí)生成Debug版和Release版的程序做個(gè)測(cè)試。
留一個(gè)問(wèn)題:const volatile int i=10;這行代碼有沒(méi)有問(wèn)題?如果沒(méi)有,那i到底是什么屬性?
這個(gè)可以同時(shí)使用。
7.空結(jié)構(gòu)體是有大小的
structstudent
{
}stu;
sizeof(stu)的值是多少呢?在VisualC++6.0上測(cè)試一下。
很遺憾,不是0,而是1。為什么呢?你想想,如果我們把structstudent看成一個(gè)模子的話(huà),你能造出一個(gè)沒(méi)有任何容積的模子嗎?顯然不行。編譯器也是如此認(rèn)為。編譯器認(rèn)為任何一種數(shù)據(jù)類(lèi)型都有其大小,用它來(lái)定義一個(gè)變量能夠分配確定大小的空間。既然如此,編譯器就理所當(dāng)然的認(rèn)為任何一個(gè)結(jié)構(gòu)體都是有大小的,哪怕這個(gè)結(jié)構(gòu)體為空。那萬(wàn)一結(jié)構(gòu)體真的為空,它的大小為什么值比較合適呢?假設(shè)結(jié)構(gòu)體內(nèi)只有一個(gè)char型的數(shù)據(jù)成員,那其大小為1byte(這里先不考慮內(nèi)存對(duì)齊的情況).也就是說(shuō)非空結(jié)構(gòu)體類(lèi)型數(shù)據(jù)最少需要占一個(gè)字節(jié)的空間,而空結(jié)構(gòu)體類(lèi)型數(shù)據(jù)總不能比最小的非空結(jié)構(gòu)體類(lèi)型數(shù)據(jù)所占的空間大吧。這就麻煩了,空結(jié)構(gòu)體的大小既不能為0,也不能大于1,怎么辦?定義為0.5個(gè)byte?但是內(nèi)存地址的最小單位是1個(gè)byte,0.5個(gè)byte怎么處理?解決這個(gè)問(wèn)題的最好辦法就是折中,編譯器理所當(dāng)然的認(rèn)為你構(gòu)造一個(gè)結(jié)構(gòu)體數(shù)據(jù)類(lèi)型是用來(lái)打包一些數(shù)據(jù)成員的,而最小的數(shù)據(jù)成員需要1個(gè)byte,編譯器為每個(gè)結(jié)構(gòu)體類(lèi)型數(shù)據(jù)至少預(yù)留1個(gè)byte的空間。所以,空結(jié)構(gòu)體的大小就定位1個(gè)byte。
8. 大端與小端
在x86 系統(tǒng)下,輸出的值為多少?
#include
int main()
{
int a[5]={1,2,3,4,5};
int *ptr1=(int *)(&a+1);
int *ptr2=(int *)((int)a+1);
printf("%x,%x",ptr1[-1],*ptr2);
return 0;
}
5和0x02000000
由于x86是小端方式,所以低位內(nèi)容存放到了低位地址。圖中每一種顏色代筆一個(gè)int型的內(nèi)存分布。&a可以獲得數(shù)組a的地址,也就是這兒的0xbfd46624, 所以&a+1的結(jié)果應(yīng)該是0xbfd46638(即圖中最下面紅色部分)。對(duì)于代碼中的ptr1由于其為int型指針,所以ptr[-1]的意思應(yīng)該是取0xbfd46638地址之前的一個(gè)整型,即為a數(shù)組中的最后一個(gè)值5。而在計(jì)算ptr2的時(shí)候,(int)a是將整型地址a轉(zhuǎn)換成了一個(gè)整型數(shù),這樣(int)a+1的結(jié)果就是0xbfd46625,然后再將其轉(zhuǎn)化為int型指針,這樣利用ptr2獲得的數(shù)值就是從0xbfd46625開(kāi)始的一個(gè)整型,即為0x02000000
10. 花括號(hào)
花括號(hào)每個(gè)人都見(jiàn)過(guò),很簡(jiǎn)單吧。但曾經(jīng)有一個(gè)學(xué)生問(wèn)過(guò)我如下問(wèn)題:
char a[10] = {“abcde”};
他不理解為什么這個(gè)表達(dá)式正確。我讓他繼續(xù)改一下這個(gè)例子:
char a[10] { = “abcde”};
問(wèn)他這樣行不行。那讀者以為呢?為什么?
花括號(hào)的作用是什么呢?我們平時(shí)寫(xiě)函數(shù),if、while、for、switch 語(yǔ)句等都用到了它,但有時(shí)又省略掉了它。簡(jiǎn)單來(lái)說(shuō)花括號(hào)的作用就是打包。你想想以前用花括號(hào)是不是為了把一些語(yǔ)句或代碼打個(gè)包包起來(lái),使之形成一個(gè)整體,并與外界絕緣。這樣理解的話(huà),上面的問(wèn)題就不是問(wèn)題了。
11.再論 a 和&a 之間的區(qū)別
int main()
{
char a[5]={'A','B','C','D'};
char (*p3)[5] = &a;
char (*p4)[5] = a;
return 0;
}
int main()
{
char a[5]={'A','B','C','D'};
char (*p3)[3] = &a;
char (*p4)[3] = a;
return 0;
}
int main()
{
char a[5]={'A','B','C','D'};
char (*p3)[10] = &a;
char (*p4)[10] = a;
return 0;
}
int a[5][5];
int (*p)[4];
p = a;
問(wèn)&p[4][2] - &a[4][2]的值為多少?
12. 用 malloc 函數(shù)申請(qǐng) 0 字節(jié)內(nèi)存
另外還有一個(gè)問(wèn)題:用 malloc 函數(shù)申請(qǐng) 0 字節(jié)內(nèi)存會(huì)返回 NULL 指針嗎?
可以測(cè)試一下,也可以去查找關(guān)于 malloc 函數(shù)的說(shuō)明文檔。申請(qǐng) 0 字節(jié)內(nèi)存,函數(shù)并不返回 NULL,而是返回一個(gè)正常的內(nèi)存地址。但是你卻無(wú)法使用這塊大小為 0
的內(nèi)存。這好尺子上的某個(gè)刻度,刻度本身并沒(méi)有長(zhǎng)度,只有某兩個(gè)刻度一起才能量出長(zhǎng)度。對(duì)于這一點(diǎn)一定要小心,因?yàn)檫@時(shí)候 if(NULL != p)語(yǔ)句校驗(yàn)將不起作用。
13. 不使用任何變量編寫(xiě) strlen 函數(shù)
看到這里,也許有人會(huì)說(shuō),strlen 函數(shù)這么簡(jiǎn)單,有什么好討論的。是的,我相信你能 熟練應(yīng)用這個(gè)函數(shù),也相信你能輕易的寫(xiě)出這個(gè)函數(shù)。但是如果我把要求提高一些呢:
不允許調(diào)用庫(kù)函數(shù),也不允許使用任何全局或局部變量編寫(xiě) int my_strlen (char *strDest); 似乎問(wèn)題就沒(méi)有那么簡(jiǎn)單了吧?這個(gè)問(wèn)題曾經(jīng)在網(wǎng)絡(luò)上討論的比較熱烈,我?guī)缀跏侨獭坝^戰(zhàn)” ,差點(diǎn)也忍不住手癢了。不過(guò)因?yàn)槲业慕鉀Q辦法在我看到帖子時(shí)已經(jīng)有人提出了, 所以作罷。
解決這個(gè)問(wèn)題的辦法由好幾種,比如嵌套有編語(yǔ)言。因?yàn)榍短讌R編一般只在嵌入式底 層開(kāi)發(fā)中用到,所以本書(shū)就不打算討論 C 語(yǔ)言嵌套匯編的知識(shí)了。 有興趣的讀者,可以查找相關(guān)資料。 也許有的讀者想到了用遞歸函數(shù)來(lái)解決這個(gè)問(wèn)題。是的,你應(yīng)該想得到,因?yàn)槲野堰@ 個(gè)問(wèn)題放在講解函數(shù)遞歸的時(shí)候討論。
既然已經(jīng)有了思路, 這個(gè)問(wèn)題就很簡(jiǎn)單了。
代碼如下:
int my_strlen( const char* strDest )
{
assert(NULL != strDest);
if ('' == *strDest)
{
return 0;
}
else
{
return (1 + my_strlen(++strDest));
}
}
第一步:用 assert 宏做入口校驗(yàn)。
第二步:確定參數(shù)傳遞過(guò)來(lái)的地址上的內(nèi)存存儲(chǔ)的是否為''。如果是,表明這是一個(gè) 空字符串,或者是字符串的結(jié)束標(biāo)志。
第三步:如果參數(shù)傳遞過(guò)來(lái)的地址上的內(nèi)存不為'',則說(shuō)明這個(gè)地址上的內(nèi)存上存儲(chǔ) 的是一個(gè)字符。既然這個(gè)地址上存儲(chǔ)了一個(gè)字符,那就計(jì)數(shù)為 1,然后將地址加 1 個(gè) char類(lèi)型元素的大小,然后再調(diào)用函數(shù)本身。如此循環(huán),當(dāng)?shù)刂芳拥阶址慕Y(jié)束標(biāo)志符''時(shí), 遞歸停止。
當(dāng)然,同樣是利用遞歸,還有人寫(xiě)出了更加簡(jiǎn)潔的代碼:
int my_strlen( const char* strDest )
{
return *strDest?1+strlen(strDest+1):0;
}
這里很巧妙的利用了問(wèn)號(hào)表達(dá)式, 但是沒(méi)有做參數(shù)入口校驗(yàn), 同時(shí)用*strDest 來(lái)代替('' == *strDest)也不是很好。所以,這種寫(xiě)法雖然很簡(jiǎn)潔,但不符合我們前面所講的編碼規(guī)范。
可以改寫(xiě)一下:
int my_strlen( const char* strDest )
{
assert(NULL != strDest);
return ('' != *strDest)?(1+my_strlen(strDest+1)):0;
}
上面的問(wèn)題利用函數(shù)遞歸的特性就輕易的搞定了, 也就是說(shuō)每調(diào)用一遍 my_strlen 函數(shù), 其實(shí)只判斷了一個(gè)字節(jié)上的內(nèi)容。但是,如果傳入的字符串很長(zhǎng)的話(huà),就需要連續(xù)多次函數(shù)調(diào)用,而函數(shù)調(diào)用的開(kāi)銷(xiāo)比循環(huán)來(lái)說(shuō)要大得多,所以,遞歸的效率很低,遞歸的深度太大甚 至可能出現(xiàn)錯(cuò)誤(比如棧溢出) 。所以,平時(shí)寫(xiě)代碼,不到萬(wàn)不得已,盡量不要用遞歸。即便是要用遞歸,也要注意遞歸的層次不要太深,防止出現(xiàn)棧溢出的錯(cuò)誤;同時(shí)遞歸的停止條 件一定要正確,否則,遞歸可能沒(méi)完沒(méi)了。
c語(yǔ)言讀書(shū)筆記
我有一本c語(yǔ)言程序設(shè)計(jì)書(shū),已經(jīng)靜靜的躺著好長(zhǎng)時(shí)間了,前幾天朋友說(shuō),你這本書(shū)有些發(fā)黃了,看來(lái)是好長(zhǎng)時(shí)間沒(méi)有翻過(guò)了。
其實(shí)這本書(shū)是我初學(xué)電腦時(shí)朋友給的,但只看了幾頁(yè)就放在那兒了,那時(shí)沒(méi)有自己的電腦,看起來(lái)很吃力。在朋友的提醒下,現(xiàn)在可以找一點(diǎn)時(shí)間去翻一翻,雖然沒(méi)有什么價(jià)值,但學(xué)習(xí)也是一種樂(lè)趣......
記錄第二天:
昨天詳細(xì)讀了一下第一章,感覺(jué)寫(xiě)的很詳細(xì),但我不知道書(shū)上的知識(shí)點(diǎn)是否全正確。
一、數(shù)據(jù)類(lèi)型的基本概念
(1)數(shù)據(jù)類(lèi)型規(guī)定了一個(gè)以值為其元素的集合。
(2)數(shù)據(jù)類(lèi)型定義了一個(gè)運(yùn)算集
(3)數(shù)據(jù)類(lèi)型定義了數(shù)據(jù)在計(jì)算機(jī)內(nèi)的存儲(chǔ)及書(shū)寫(xiě)中的表示方式。
二、c語(yǔ)言的數(shù)據(jù)類(lèi)型
數(shù)據(jù)包含常量和變量,他們都屬于某個(gè)數(shù)據(jù)類(lèi)型。
三、常量
常量是程序中其值不發(fā)生變化的量,常量有數(shù)、字符和字符串。在c中常量不需要類(lèi)型說(shuō)明就可以直接使用,除此之后c中還有一種表示常量的形式,稱(chēng)為符號(hào)常量。
(一)數(shù)
1、c中數(shù)有整數(shù)和小數(shù)
(1)整數(shù)
整數(shù)有十進(jìn)制,八進(jìn)制,十六進(jìn)制,八進(jìn)制以數(shù)字0開(kāi)頭,十六進(jìn)制以0x開(kāi)頭,十進(jìn)制以1-9中的一個(gè)開(kāi)頭。
整數(shù)有正負(fù)之分,分別在前面加上+,-符號(hào),正數(shù)的符號(hào)+可以省略。
整數(shù)有短整數(shù),整數(shù),長(zhǎng)整數(shù)之分,一般短整數(shù)16位,在我的機(jī)器上是short(16),int(32),long(32),對(duì)于整數(shù)的取值范圍有符號(hào)的(-2的n位次方至2的n位次方減1),無(wú)符號(hào)的0到2的n位次方-1
長(zhǎng)型數(shù)的書(shū)寫(xiě)方法:在數(shù)后面加一個(gè)L,如:0xffL
(2)實(shí)數(shù)
又叫浮點(diǎn)數(shù),只有十進(jìn)制的,實(shí)數(shù)有單精度和雙精度之分,實(shí)數(shù)有兩種表示形式,一種是小數(shù),一種是指數(shù)。
小數(shù):由整數(shù)部分,小數(shù)點(diǎn),小數(shù)部分。
指數(shù):由尾數(shù)(必須有),e/E,指數(shù)(必須是整數(shù))
(二)字符常量
字符常量是用一對(duì)''括起來(lái)的單一字符,一個(gè)字符常量在計(jì)算機(jī)中占一個(gè)字節(jié)(8位),字符常量的值就是這個(gè)字符在所屬字符集中的編碼(如:ASCII碼)。
字符常量中的單引號(hào)用作定界符,所以對(duì)于單引號(hào)的表示方法就得用另外一種方法表示:''' 用一個(gè)斜杠加一個(gè)'來(lái)轉(zhuǎn)義一個(gè)單引號(hào),對(duì)于斜框用來(lái)轉(zhuǎn)義。
字符常量在計(jì)算機(jī)中是以編碼的方式存放,所以說(shuō)他實(shí)際是一個(gè)字節(jié)的整數(shù),可以參與各種運(yùn)算,如+,-,*,/,比較等。
(三)字符串常量
字符串常量是用雙引號(hào)護(hù)起來(lái)的一串字符,字符的個(gè)數(shù)稱(chēng)其長(zhǎng)度,字符串常量簡(jiǎn)稱(chēng)為字符串。
長(zhǎng)度為n的字符串在計(jì)算機(jī)的存儲(chǔ)中占用n+1個(gè)字節(jié),最后多出來(lái)的那個(gè)存放一個(gè)NULL字符,ASCII編碼是0,我們可以用''來(lái)表示這個(gè)字符。
任何一個(gè)字符串在機(jī)器內(nèi)都是以結(jié)尾。如:abc,其實(shí)是'a','b','c',''的存儲(chǔ)格式。
對(duì)于"這個(gè)雙引號(hào),由于用作定界符了,所以只能轉(zhuǎn)義表示:"。
注意: 'A' , "A"這是兩個(gè)不同的存儲(chǔ)方式,一個(gè)是65,一個(gè)是65,0
(四)
一般的字符可以直接寫(xiě)出,但對(duì)于NULL,回車(chē),新行,退格等字符如何書(shū)寫(xiě)?
對(duì)于這些字符我們可以用其它的方式表示出來(lái),常用的有:
新行
回車(chē)
水平制表
v 垂直制表
退格
f 換頁(yè)
a 響鈴
" 雙引號(hào)
' 單引號(hào)
NULL
ddd 1到3位八進(jìn)制數(shù)表示一個(gè)字符
xdd 1到2位十六進(jìn)制數(shù)表示一個(gè)字符
其實(shí)ddd,xdd就是字符的編碼。
(五)符號(hào)常量
在c語(yǔ)言中可以對(duì)常量進(jìn)行命名,即用符號(hào)代替常數(shù)值,該符號(hào)叫符號(hào)常量,符號(hào)常量一般用大寫(xiě)字母表示。
定義格式:
#define 符號(hào)常量名 常量
如:
#define NULL 0
#define EOF -1
#define PI 3.1415926
這里#define是預(yù)編譯命令,每一個(gè)#define只能定義一個(gè)符號(hào)常量,且用一行書(shū)寫(xiě),不用分號(hào)結(jié)尾。
例:
#include
#define PI 3.1415926
int main(void)
{
float area,r;
printf("請(qǐng)輸入圓的半徑:");
scanf("%f",&r);
area = PI*r*r;
printf("這個(gè)圓的面積是:%f ", area);
return 0;
}
使用符號(hào)常量的好處:
(1)增強(qiáng)程序的可讀性。
如用PI,代表數(shù)學(xué)中的PI,用EOF代表文件尾,很直觀。
(2)增強(qiáng)程序的可維護(hù)性
如果多處用到同一個(gè)常量,可以定義符號(hào)常量,維護(hù)時(shí)只修改一處即可。對(duì)于擴(kuò)充和可移植一個(gè)程序時(shí)大有好處。
四、變量
變量是他的值可以發(fā)生變化的一種量,每一個(gè)變量都對(duì)應(yīng)計(jì)算機(jī)中相應(yīng)長(zhǎng)度的存儲(chǔ)單元,以存放變量所取的值。
如:
#include
int main(void)
{
int x = 0; //x的初值為0
x = 5; //x的值發(fā)生了變化
x = 7*5;
x = x+1;
printf("%d ",x);
return 0;
}
每一個(gè)變量都用一個(gè)名字(叫變量名)來(lái)表示,變量的名字實(shí)際上是內(nèi)存單元的命名,變量的地址就是該內(nèi)存單元的開(kāi)始地址。變量的命名規(guī)則同用戶(hù)自定義標(biāo)識(shí)符。
任何一個(gè)變量都屬于某一數(shù)據(jù)類(lèi)型,如果他是整型量,則只能取整數(shù)值。
(一)基本數(shù)據(jù)類(lèi)型
(1)、從長(zhǎng)度上分有8位、16位、32位和64們珠。
(2)、從數(shù)據(jù)的符號(hào)來(lái)分,有無(wú)符號(hào)的,和有符號(hào)的。
(3)、按照數(shù)學(xué)性質(zhì)來(lái)分,分為整型和實(shí)型。
c語(yǔ)言的基本數(shù)據(jù)類(lèi)型表:
對(duì)于數(shù)的值域范圍的算法:
有符號(hào):[-2(位長(zhǎng)度-1)次方到 2(位長(zhǎng)度-1)次方-1]
無(wú)符號(hào):[0到 2位長(zhǎng)度次方]
-----------------------------------------------------------------
類(lèi)型標(biāo)識(shí)符 名字 長(zhǎng)度 范圍
char 字符型 8 ASCII字符代碼
unsigned char 無(wú)符號(hào)字符型 8 0-255
signed char 有符號(hào)字符型 8 -127:127
int 整型 16(和環(huán)境有關(guān)) 范圍算法
unsigned int 無(wú)符號(hào)整型 同上 同上
signed int 有符號(hào)整數(shù) 同上 同上
short int 短整型 16(和環(huán)境有關(guān)) 同上
unsigned short int 無(wú)符號(hào)短整型 同上 同上
signed short int 有符號(hào)短整型 同上 同上
long int 長(zhǎng)整型 32位(和環(huán)境有關(guān)) 同上
unsigned long int 無(wú)符號(hào)長(zhǎng)整型 同上 同上
signed long int 有符號(hào)長(zhǎng)整型 同上 同上
float 單精度浮點(diǎn)型 32
double 雙精度浮點(diǎn)型 64
void 空類(lèi)型
-------------------------------------------------------------------
注:
(1)void類(lèi)型有兩種用法,一是指定函數(shù)的'返回值的類(lèi)型,一是用來(lái)設(shè)置類(lèi)屬指針。
(2)對(duì)于不同的環(huán)境,數(shù)據(jù)表示的范圍不同,可以用sizeof(類(lèi)型)來(lái)測(cè)試。
(二)變量的定義
變量的定義就是按照特定的方式為其指定標(biāo)識(shí),類(lèi)型和長(zhǎng)度等。程序中所用的每一個(gè)變量都必須先定義后引用,沒(méi)有定義的變量是不能引用的。定義的目的是為編譯程序提供所需的信息,以保證完成以下工作。
1、在編譯時(shí)根據(jù)類(lèi)型信息來(lái)檢查程序中有無(wú)非法的數(shù)據(jù)結(jié)構(gòu)。
2、根據(jù)類(lèi)型信息來(lái)檢查對(duì)變量施加的運(yùn)算是否合理。如對(duì)兩個(gè)浮點(diǎn)數(shù)不可以進(jìn)行%運(yùn)算。
3、編譯時(shí)根據(jù)類(lèi)型和長(zhǎng)度信息對(duì)變量分配內(nèi)存,確定數(shù)據(jù)在內(nèi)存中的表示方式。
定義:
數(shù)據(jù)類(lèi)型 變量或變量表;
如:
int year,date;
int x;
(三)變量的初始化
int x; 對(duì)于這樣的變量只是指定了名字和數(shù)據(jù)類(lèi)型,并沒(méi)有給他初始值,但這并不表示變量沒(méi)有值,他的值是當(dāng)前內(nèi)存單元中的數(shù)據(jù),這個(gè)數(shù)據(jù)是沒(méi)有意義的,引用時(shí)會(huì)產(chǎn)生莫名其妙的結(jié)果。
初始化:在定義時(shí)直接賦值,則稱(chēng)為初始化。
int x = 5;
double y = 3.4;
變量的初始化并不都是在編譯階段完成的,只有靜態(tài)變量和外部變量是在編譯階段完成,而局部變量是在運(yùn)行時(shí)初始化的。局部變量的初始化就是一個(gè)賦值語(yǔ)句。
int abc()
{
int a =3;
int b =4; //這是在運(yùn)行時(shí)才初始化,而非編譯時(shí)。
}
//補(bǔ)充
數(shù)據(jù)類(lèi)型的轉(zhuǎn)換
在c語(yǔ)言的表達(dá)式中,準(zhǔn)許對(duì)不同類(lèi)型的數(shù)值型數(shù)據(jù)進(jìn)行某一操作,當(dāng)不同類(lèi)型的數(shù)據(jù)進(jìn)行操作時(shí),先將其轉(zhuǎn)換成相同的數(shù)據(jù)類(lèi)型,然后再進(jìn)行操作。
有兩種轉(zhuǎn)換方式:隱式轉(zhuǎn)換,顯示轉(zhuǎn)換。
一、隱式類(lèi)型轉(zhuǎn)換
隱式轉(zhuǎn)換就是在編譯時(shí)由編譯程序按照一定規(guī)則自動(dòng)完成。c語(yǔ)言規(guī)定的轉(zhuǎn)換規(guī)則是由低級(jí)向高級(jí)轉(zhuǎn)換,如果一個(gè)操作符帶有兩個(gè)不同類(lèi)型的操作數(shù),那么在操作之前先將較低的類(lèi)型向高級(jí)轉(zhuǎn)換,再進(jìn)行運(yùn)算。
注意:
1、所有的float類(lèi)型都轉(zhuǎn)換成double類(lèi)型,提高運(yùn)算精度。
2、在賦值語(yǔ)句中,如果=號(hào)左右兩邊的數(shù)據(jù)類(lèi)型不同,則將賦值號(hào)右邊的值轉(zhuǎn)換為賦值號(hào)左邊的數(shù)據(jù)類(lèi)型。
3、在函數(shù)參數(shù)傳遞時(shí),也發(fā)生數(shù)據(jù)類(lèi)型轉(zhuǎn)換。
4、char short自動(dòng)轉(zhuǎn)換成int再參與運(yùn)算。
規(guī)則:
1、char short自動(dòng)轉(zhuǎn)換成int
2、float轉(zhuǎn)換成double
3、低級(jí)到高級(jí)-> char short ->int ->unsigned-> long ->(float ->double)double
二、顯式轉(zhuǎn)換
顯式轉(zhuǎn)換又叫強(qiáng)制型轉(zhuǎn)換,他不換默認(rèn)規(guī)則,由程序員指定。
如:
int i;
i = i+3.124; //默認(rèn)是i轉(zhuǎn)成double,再運(yùn)算,之后double轉(zhuǎn)成int賦給i
顯示轉(zhuǎn)換: i = i+(int)3.124 //先把3.124轉(zhuǎn)成int,再參與運(yùn)算。
顯示類(lèi)型轉(zhuǎn)換方法:(數(shù)據(jù)類(lèi)型)表達(dá)式
如:(int) 3.14159; //把double -> int
[c語(yǔ)言讀書(shū)筆記]
【c語(yǔ)言讀書(shū)筆記】相關(guān)文章:
c++課程設(shè)計(jì)實(shí)踐報(bào)告08-10
讀書(shū)筆記摘抄03-23
《初雪 》讀書(shū)筆記08-16
草葉集讀書(shū)筆記06-18
愛(ài)心與教育讀書(shū)筆記06-18
讀書(shū)筆記的寫(xiě)法指點(diǎn)04-14
護(hù)理札記的讀書(shū)筆記06-19