1. 程序運(yùn)行模式
當(dāng)我們將一個(gè)程序交給CPU去執(zhí)行的時(shí)候,CPU只會(huì)執(zhí)行main函數(shù)中的代碼睬棚,別的地方的代碼是不會(huì)執(zhí)行的,因此如果想要在CPU中執(zhí)行程序就必須要在main函數(shù)中從上到下一句一句執(zhí)行代碼完慧,并且只有在上一句執(zhí)行完畢之后才會(huì)執(zhí)行下一句黎泣。
mian是程序的入口,當(dāng)mian函數(shù)中的代碼執(zhí)行完畢之后就會(huì)自動(dòng)結(jié)束必尼,所以也是出口蒋搜。
2. 計(jì)算機(jī)三大件
CPU : 中央處理器,處理數(shù)據(jù)的判莉,負(fù)責(zé)計(jì)算豆挽,協(xié)調(diào)其他硬件相互和諧的工作。
內(nèi)存 :存儲(chǔ)數(shù)據(jù) 券盅,臨時(shí)帮哈,效率高,通過電路存儲(chǔ)锰镀,電子式娘侍。
硬盤 :存儲(chǔ)數(shù)據(jù) 咖刃,永久存儲(chǔ),效率低憾筏,效率和轉(zhuǎn)速有關(guān)嚎杨,機(jī)械式。
3. 程序是如何運(yùn)行的
程序本質(zhì)就是一對(duì)指令氧腰,程序存儲(chǔ)在硬盤之中枫浙,當(dāng)雙擊點(diǎn)開之后,CPU會(huì)先將程序復(fù)制到內(nèi)存之中容贝,然后CPU再去讀取內(nèi)存中程序的指令自脯。這是因?yàn)樵趦?nèi)存中CPU的讀取效率更高。
例如:播放器播放電影斤富,播放時(shí)是運(yùn)行在內(nèi)存中的膏潮,但是電影文件確實(shí)保存在硬盤中的,當(dāng)雙擊電影打開播放器满力,播放器運(yùn)行在內(nèi)存中焕参,然后播放器在去分段的讀取電影文件。
或者英雄聯(lián)盟這樣的大型游戲也不是將整個(gè)游戲拷貝到內(nèi)存中油额,而是只將exe文件拷貝到CPU中叠纷,然后需要什么文件就加載哪些文件,不用的就會(huì)釋放掉潦嘶。
4. 程序處理數(shù)據(jù)
- 要不要存涩嚣?
程序自己是否要把這些數(shù)據(jù)存儲(chǔ)起來,對(duì)于用戶操作產(chǎn)生的數(shù)據(jù)掂僵,或者一會(huì)兒要用的數(shù)據(jù)可以存儲(chǔ)起來航厚,以便以后顯示方便快捷。 - 存到哪锰蓬?
存儲(chǔ)到內(nèi)存中幔睬,因?yàn)槌绦蜃约壕驮趦?nèi)存當(dāng)中 - 如何將數(shù)據(jù)存儲(chǔ)在內(nèi)存之中?
先在內(nèi)存中找一個(gè)位置芹扭,將數(shù)據(jù)放到這個(gè)位置中麻顶,當(dāng)想要使用數(shù)據(jù)的時(shí)候,只要找到這個(gè)位置就可以了舱卡。
而每一個(gè)位置在內(nèi)存中都有一個(gè)獨(dú)一無二地址辅肾,16進(jìn)制表示,0x開頭轮锥。通過這個(gè)地址找到這個(gè)位置宛瞄,然而地址非常難記,所以給位置起個(gè)別名,通過別名找到位置份汗。
因此在開辟空間的同時(shí),需要指定空間的別名和類型蝴簇,而變量就是內(nèi)存中用來存儲(chǔ)數(shù)據(jù)的空間杯活,那么變量名就是變量所代表的那塊空間的別名。所以熬词,變量的本質(zhì)就是內(nèi)存中存儲(chǔ)數(shù)據(jù)的那塊兒空間旁钧。
聲明一個(gè)變量,實(shí)際上就是在內(nèi)存中開辟一塊指定類型和別名的空間
5. 內(nèi)存中的五大區(qū)域
內(nèi)存當(dāng)中分為五大區(qū)域
為什么要分區(qū)個(gè)區(qū)域互拾?雖然每一個(gè)區(qū)域都是用來存儲(chǔ)數(shù)據(jù)的歪今,但是不同的數(shù)據(jù)存儲(chǔ)在不同的區(qū)域,這樣不僅方便系統(tǒng)的管理颜矿,也可以使系統(tǒng)更快寄猩,更明確的找到要找的地址。
- 棧 - 專門用來存儲(chǔ)局部變量骑疆,所有的局部變量都是聲明在棧區(qū)域當(dāng)中田篇。
- 堆 - 允許程序員手動(dòng)的從堆申請(qǐng)空間來使用。程序員可以自己申請(qǐng)指定字節(jié)數(shù)的空間箍铭。
- BSS段 - 用來存儲(chǔ)未初始化的全局變量和靜態(tài)變量泊柬,聲明一個(gè)全局變量,如果我們沒有初始化诈火,在程序運(yùn)行最開始的時(shí)候兽赁,這個(gè)變量沒有初始化時(shí)是存儲(chǔ)在BSS段,初始化之后冷守,全局變量和靜態(tài)變量就會(huì)被放到常量區(qū)刀崖。
- 數(shù)據(jù)段/常量區(qū) - 用來存儲(chǔ)已經(jīng)初始化的全局變量、靜態(tài)變量教沾,還有常量數(shù)據(jù)
- 代碼段 - 用來存儲(chǔ)程序的代碼/指令蒲跨。
注意:我們堆中申請(qǐng)的字節(jié)空間,如果我們不主動(dòng)釋放授翻,那么系統(tǒng)是不會(huì)釋放的或悲,除非程序結(jié)束
在堆中申請(qǐng)字節(jié)空間的步驟 a. 申請(qǐng) -> b. 使用 -> c. 釋放
如何在堆區(qū)申請(qǐng)指定字節(jié)數(shù)的字節(jié)空間呢?C語言提供了三個(gè)函數(shù)用來申請(qǐng)空間堪唐。這三個(gè)函數(shù)聲明在<stdlib.h>
的系統(tǒng)頭文件中巡语。
malloc()函數(shù)
malloc()
參數(shù)只有一個(gè):size_t
類型的,也就是unsigned long
淮菠。
表示在堆內(nèi)存中申請(qǐng)參數(shù)個(gè)連續(xù)的字節(jié)空間男公,返回值是void *
表示沒有類型的指針。并且返回的是創(chuàng)建的空間中的第一個(gè)字節(jié)的地址合陵。
那么我們應(yīng)該使用什么類型的指針變量來保存malloc()返回的地址枢赔?
用什么類型去接受澄阳,那要看你想要如何去操作申請(qǐng)的這些字節(jié)空間。如果你想要4個(gè)字節(jié)4個(gè)字節(jié)去操作那么就要用int *
類型去接收,如果想8個(gè)字節(jié)8個(gè)字節(jié)的去錯(cuò)做那么就用double *
類型去接收踏拜。
所以: int *p = malloc(24); 就相當(dāng)于在堆內(nèi)存中創(chuàng)建了一個(gè)長(zhǎng)度為6的整型數(shù)組
注意:
1.在堆區(qū)申請(qǐng)的字節(jié)空間是從低地址向高地址申請(qǐng)碎赢,每次申請(qǐng)的字節(jié)地址都是從0開始的,并且每次申請(qǐng)的空間不一定是連續(xù)的速梗。但是每一次申請(qǐng)的指定個(gè)字節(jié)肮塞,這些字節(jié)一定是連續(xù)的。
2.在堆區(qū)申請(qǐng)的字節(jié)里面也是有值的姻锁,值是垃圾值枕赵,并且值不會(huì)自動(dòng)清零。
3.在向堆區(qū)申請(qǐng)字節(jié)空間的時(shí)候位隶,有可能會(huì)申請(qǐng)失敗拷窜,如果申請(qǐng)失敗,返回的指針就是NULL值钓试,所以我們?cè)谏暾?qǐng)空間之后装黑,最好進(jìn)行判斷 if(p1) 看是否申請(qǐng)成功。
4.申請(qǐng)的空間使用完畢之后弓熏,一定要進(jìn)行釋放 free(p1); 如果沒有free()恋谭,那么需要等程序結(jié)束之后這些空間才會(huì)被釋放。
calloc()
calloc() 作用:向堆區(qū)申請(qǐng)指定字節(jié)數(shù)的空間挽鞠。
參數(shù)1.多少個(gè)單位
參數(shù)2.每一個(gè)單位的字節(jié)數(shù)
例:callco(3,sizeof(int)); // 表示申請(qǐng)3個(gè)4字節(jié)數(shù)的空間疚颊。
同樣有可能申請(qǐng)失敗。與malloc()的優(yōu)勢(shì)信认,calloc()申請(qǐng)的字節(jié)材义,申請(qǐng)完之后,系統(tǒng)會(huì)將申請(qǐng)到的空間自動(dòng)清零
realloc()
realloc()作用:擴(kuò)容嫁赏。
當(dāng)我們申請(qǐng)的字節(jié)空間不夠用的時(shí)候其掂,我們可以使用realloc() 擴(kuò)容。
例:realloc(p1,4); 表示在p1后面申請(qǐng)4個(gè)字節(jié)空間潦蝇。
一般會(huì)在我們申請(qǐng)的空間后面擴(kuò)容款熬,但是如果我們申請(qǐng)的空間后面被占用了,或者不夠我們擴(kuò)容的空間攘乒,就會(huì)重新去尋找一塊新足夠的空間申請(qǐng)贤牛,并將原來的數(shù)據(jù)拷貝過來,原來的空間將被釋放则酝。
注意:我們只能操作我們申請(qǐng)到的字節(jié)空間殉簸,如果貿(mào)然操作其他字節(jié)空間,很有可能修改掉系統(tǒng)的數(shù)據(jù),造成嚴(yán)重問題般卑。
6. fputs()函數(shù)
作用: 將字符串?dāng)?shù)據(jù)輸出到指定的流中武鲁。
流: 標(biāo)準(zhǔn)輸出流->控制臺(tái)。文件流 --> 磁盤上的文件椭微。
使用格式: fputs(要輸出的字符串,指定的流);
1). 使用fputs函數(shù)將字符串?dāng)?shù)據(jù)輸出到標(biāo)準(zhǔn)輸出流洞坑,也就是控制臺(tái)
標(biāo)準(zhǔn)輸出流: 控制臺(tái). stdout
2). 將字符串存儲(chǔ)到文件中.
a. 要先聲明1個(gè)文件指針,指向磁盤上的文件蝇率。使用fopen函數(shù)可以創(chuàng)建1個(gè)指向文件的指針。
fopen函數(shù)的兩個(gè)參數(shù):
第1個(gè)參數(shù): 文件的路徑刽沾,代表創(chuàng)建的指針就指向這個(gè)文件本慕。
第2個(gè)參數(shù): 操作文件的模式,你要對(duì)這個(gè)文件做什么操作侧漓,必須要告訴他锅尘。
"w" --> write 代表要向這個(gè)文件寫入內(nèi)容。
"r" --> read 代表從這個(gè)文件中讀取數(shù)據(jù)布蔗。
"a" --> apped 追加代表向這個(gè)文件中追加數(shù)據(jù)藤违。
當(dāng)操作模式是"w"的時(shí)候,如果文件不存在纵揍, 就會(huì)創(chuàng)建這個(gè)文件顿乒,如果文件存在,就會(huì)將原來的文件替換掉泽谨。
當(dāng)操作模式是"a"的時(shí)候璧榄,如果文件存在則追加。如果不存在就創(chuàng)建這個(gè)文件吧雹。
b. 使用fputs函數(shù)將字符串寫入到指定的文件流中骨杂。
fputs(字符串,文件指針);
c. 寫完之后,一定要記得使用fclose()
函數(shù)將這個(gè)文件關(guān)閉雄卷。
7. fget()函數(shù)
作用: 從指定的流中讀取字符串搓蚪。
這個(gè)流可以是標(biāo)準(zhǔn)輸入流-->控制臺(tái),也可以是文件流丁鹉。
1). 使用fgets函數(shù)從標(biāo)準(zhǔn)輸入流中讀取數(shù)據(jù)妒潭。
使用fgets函數(shù)從控制臺(tái)接收用戶輸入字符串,scanf函數(shù)gets函數(shù)也可以實(shí)現(xiàn)這個(gè)功能鳄炉。
scanf的缺點(diǎn)
a. 不安全.
b. 輸入的空格會(huì)被認(rèn)為結(jié)束.
gets函數(shù)的缺點(diǎn).
a. 不安全.
fgets函數(shù)的優(yōu)點(diǎn)
a. 安全.
b. 空格也會(huì)一并接收.
語法:
fgets(要將字符串存儲(chǔ)到哪1個(gè)數(shù)組中,最多接收多少個(gè)長(zhǎng)度的字符串,指定流);
第2個(gè)參數(shù): 如果參數(shù)為n 那么函數(shù)最多就接收n-1個(gè)長(zhǎng)度的字符串杜耙,這個(gè)參數(shù)一般情況下和第1個(gè)參數(shù)數(shù)組的長(zhǎng)度一致。
第3個(gè)參數(shù):流拂盯,stdin: 代表標(biāo)準(zhǔn)輸入流佑女,也就是鍵盤流從控制臺(tái)輸入。
為什么fgets函數(shù)是安全的?
1. 如果輸入的字符串的長(zhǎng)度大于等于了第2個(gè)參數(shù)n,只會(huì)接收前面的n-1個(gè)团驱,然后最后1個(gè)自動(dòng)是'\0'摸吠。這樣,就不會(huì)崩潰。
2. 如果輸入的字符串的長(zhǎng)度剛好等于n-1那就是剛好的嚎花。
3. 如果輸入的字符串的長(zhǎng)度小于了n-1寸痢,那么就會(huì)將我們最后輸入的換行字符'\n'一并的接收。然后后面才是'\0'結(jié)束符紊选。
2). 使用fgets函數(shù)從文件流中讀取數(shù)據(jù):
就是讀取磁盤上文件的內(nèi)容.
// 1. 創(chuàng)建1個(gè)讀取文件的文件流.
FILE* pFile = fopen("/Users/Itcast/Desktop/abc.txt", "r");
// 2. 準(zhǔn)備1個(gè)字符數(shù)組.準(zhǔn)備存儲(chǔ)讀取到的字符串?dāng)?shù)據(jù).
char content[50];
// 3. 使用fgets函數(shù)從指定的文件流中讀取.
fgets(content, 50, pFile);
// 4. 讀取成功:
printf("讀取的內(nèi)容是: %s\n",content);
// 5. 關(guān)閉文件流
fclose(pFile);
8. const修飾基本數(shù)據(jù)類型的變量
const是1個(gè)關(guān)鍵字啼止,是來修飾變量的,也就是說在聲明變量的同時(shí)兵罢,可以使用const關(guān)鍵字來修飾献烦。
例: const int num = 10;
一般情況下來說,被const修飾的變量具備一定程度上的不可變性卖词,被const修飾的變量我們叫做只讀變量巩那。
const修飾基本數(shù)據(jù)類型的變量 int、double此蜈、float即横、char。
1. const int num = 10;
這個(gè)時(shí)候.num變量的值只能去取值,而不能去修改.
2. int const num = 10;
效果同上.
const修飾數(shù)組.
1. const int arr[4] = {10,20,30,40};
數(shù)組的元素的值不能修改.
2. int const arr[4] = {10,20,30,40};
效果同上.
const修飾指針;
1. const int* p1 = #
無法通過p1指針去修改指針指向的變量的值裆赵,但是如果直接操作變量這是可以的东囚,并且指針變量的值可以改,可以把另外1個(gè)變量的地址賦值給這個(gè)指針顾瞪。
2. int const * p1 = #
效果同上
3. int * const p1 = #
p1的值不能修改舔庶,但是可以通過p1去修改p1指向的變量的值。
4. int const * const p1 = #
既不能修改p1的值陈醒,也不能通過p1去修改p1指向的變量的值惕橙。
const的使用場(chǎng)景.
1. const的特點(diǎn):
被const修飾的變量,是只讀變量钉跷,只能取值而不能改值弥鹦。所以,const變量的值爷辙,至始至終都不會(huì)發(fā)生變化彬坏。因此當(dāng)某些數(shù)據(jù)是固定的,在整個(gè)程序運(yùn)行期間都不會(huì)發(fā)生變化膝晾,并且你也不允許別人去修改時(shí)栓始,可以使用const來修飾這個(gè)變量。
3. 當(dāng)函數(shù)的參數(shù)是1個(gè)指針的時(shí)候血当,函數(shù)的內(nèi)部是有可能會(huì)修改實(shí)參變量的值的幻赚,那么這個(gè)時(shí)候禀忆,可以使用const修飾指針參數(shù),這樣函數(shù)內(nèi)部只會(huì)使用我們的值 絕對(duì)改不了參數(shù)的值落恼。
9. 結(jié)構(gòu)體
不同的數(shù)據(jù)類型的變量是用來保存不同類型的數(shù)據(jù)的箩退。而結(jié)構(gòu)體是我們自己定義的數(shù)據(jù)類型。并指定這個(gè)數(shù)據(jù)類型的變量由哪些小的變量和成的佳谦。
語法格式:
例:
struct Student
{
char * name;
int age;
float height;
};
這代表我們新創(chuàng)建了一個(gè)數(shù)據(jù)類型戴涝,這個(gè)數(shù)據(jù)類型的名稱叫做 struct Student
這個(gè)新類型是由1個(gè)char * 類型,一個(gè)int 類型钻蔑,一個(gè)float類型的
小的標(biāo)量聯(lián)合而成的啥刻。然而只有類型是不夠的,還需要根據(jù)類型聲明變量咪笑。
聲明結(jié)構(gòu)體類型的變量:
struct Student Tom;
** 結(jié)構(gòu)體變量的初始化**
意義:為結(jié)構(gòu)體變量中的小變量賦值郑什。嚴(yán)格意義上是將地址賦值給小變量。結(jié)構(gòu)體變量中的小變量就叫做結(jié)構(gòu)體的成員蒲肋。
初始化語法 使用點(diǎn)語法。
結(jié)構(gòu)體變量名稱.成員 = 數(shù)據(jù);
Tom.name = @"Tom";
什么時(shí)候使用結(jié)構(gòu)體
當(dāng)要保存一個(gè)數(shù)據(jù)钝满,但是發(fā)現(xiàn)這個(gè)數(shù)據(jù)需要由其他小變量組成的兜粘,這個(gè)時(shí)候先使用結(jié)構(gòu)體類自定義這個(gè)數(shù)據(jù)類型由哪些小變量合成的,然后在根據(jù)這個(gè)結(jié)構(gòu)體類型聲明變量弯蚜,來保存數(shù)據(jù)孔轴。
結(jié)構(gòu)體注意點(diǎn)
一定要先聲明結(jié)構(gòu)體類型,然后在聲明結(jié)構(gòu)體變量碎捺。
-
結(jié)構(gòu)體變量也是變量所以可以批量聲明路鹰。
struct Car{} BMWCar,BCCar,KDLKCar;
定義結(jié)構(gòu)體名稱要求每一個(gè)單詞的首字母大寫。
可以在聲明結(jié)構(gòu)體類型的時(shí)候聲明結(jié)構(gòu)體變量收厨。
-
匿名結(jié)構(gòu)體
struct{ // 匿名結(jié)構(gòu)體只能在聲明結(jié)構(gòu)體的同時(shí)創(chuàng)建變量晋柱,并且不能單獨(dú)的聲明變量 }car1;
結(jié)構(gòu)體變量的初始化
- 先聲明變量,在使用點(diǎn)語法一個(gè)一個(gè)賦值诵叁。
- 在聲明結(jié)構(gòu)體變量的同時(shí)雁竞,就為結(jié)構(gòu)體變量的成員初始化。(最常用)
- 只初始化部分成員拧额,按順序碑诉。
- 也可以指定成員初始化。
struct Student jim = {.name = "jim",.age = 18};
結(jié)構(gòu)體變量成員的默認(rèn)值
聲明一個(gè)結(jié)構(gòu)體變量侥锦,如果沒有給結(jié)構(gòu)體變量成員賦值进栽,那么成員是有值的,是垃圾值恭垦。只要在聲明結(jié)構(gòu)體變量的同時(shí)快毛,為一個(gè)成員變量初始化格嗅,整個(gè)結(jié)構(gòu)體就會(huì)自動(dòng)初始化為0,就不在是垃圾值了祸泪。
結(jié)構(gòu)體類型的作用域
一般情況下結(jié)構(gòu)體類型都是定義在函數(shù)外面吗浩,已讓所有函數(shù)都可以使用。
結(jié)構(gòu)體變量之間的相互賦值
相同結(jié)構(gòu)體類型的結(jié)構(gòu)體變量是可以賦值的没隘。
結(jié)構(gòu)體變量之間賦值的原理:
將結(jié)構(gòu)體變量中的每一個(gè)成員的值懂扼,拷貝過來復(fù)制一份,然后重新賦值給目標(biāo)結(jié)構(gòu)體變量中對(duì)應(yīng)的成員右蒲。結(jié)構(gòu)體變量之間的賦值是值傳遞阀湿。
結(jié)構(gòu)體數(shù)組
struct 結(jié)構(gòu)體類型名稱 數(shù)組名[數(shù)組長(zhǎng)度];
可以存儲(chǔ)5個(gè)strut 結(jié)構(gòu)體類型名稱 的結(jié)構(gòu)體
struct Student students[5];
數(shù)組的類型是struct Student,可以存儲(chǔ)5個(gè)struct Student類型的變量瑰妄。
結(jié)構(gòu)體數(shù)組的初始化
students[0] = (struct Student) {"name",16}; // 需要轉(zhuǎn)化為結(jié)構(gòu)體類型陷嘴。
或者直接在聲明結(jié)構(gòu)體數(shù)組的時(shí)候,為結(jié)構(gòu)體賦值间坐。
結(jié)構(gòu)體數(shù)組長(zhǎng)度的計(jì)算
使用sizeof計(jì)算出數(shù)組占用的總字節(jié)數(shù)/ 每一個(gè)元素占用的字節(jié)數(shù)
sizeof(students)/ sizeof(struct Student)
結(jié)構(gòu)體指針
struct 結(jié)構(gòu)體類型名稱* 指針名;
struct Student* pStu;
聲明了一個(gè)pStu指針變量灾挨,這個(gè)指針變量的類型是struct Student *。
這個(gè)指針就只能指向 struct Student
pStu = &stu1;
使用竹宋±统危可以使用指針間接的訪問結(jié)構(gòu)體變量。
(*pStu).name;
(*結(jié)構(gòu)體指針名).成員
pStu -> name;
結(jié)構(gòu)體指針名->成員
結(jié)構(gòu)體嵌套
結(jié)構(gòu)體是可以嵌套的蜈七,在一個(gè)結(jié)構(gòu)體內(nèi)部聲明另外一個(gè)結(jié)構(gòu)體即可秒拔。
結(jié)構(gòu)體與函數(shù)
作為參數(shù)
結(jié)構(gòu)體是自定義的數(shù)據(jù)類型,當(dāng)然可以作為參數(shù)飒硅,結(jié)構(gòu)體作為參數(shù)傳值是值傳遞砂缩,如果想要在函數(shù)中修改結(jié)構(gòu)體變量的值,可以使用結(jié)構(gòu)體指針三娩。
作為返回值
結(jié)構(gòu)題類型完全可以作為函數(shù)的返回值庵芭,在返回的時(shí)候直接將結(jié)構(gòu)體變量返回即可。如果返回結(jié)構(gòu)體變量的地址尽棕,需要將結(jié)構(gòu)體創(chuàng)建在堆區(qū)喳挑。
10. 枚舉
變量的取值只能是指定的幾個(gè)值當(dāng)中的任意一個(gè),除此之外其他不行滔悉,需要自己定義具備限定取值的類型伊诵。
作用:支持先創(chuàng)建一種數(shù)據(jù)類型,這個(gè)數(shù)據(jù)類型的變量的取值被限定回官。
語法結(jié)構(gòu):
enum Type
{
Type1,
Type2,
Type3,
};
這個(gè)數(shù)據(jù)類型的名稱叫做 **enum Type **曹宴。可以聲明這個(gè)類型的變量歉提,這個(gè)變量中就只能存儲(chǔ)這其中指定的任意一個(gè)笛坦。
聲明枚舉類型的變量区转。
enum 枚舉類型名稱 變量名 = 枚舉類型限定的取值之一。
枚舉作用域
一般定義在函數(shù)外版扩,每一個(gè)枚舉值都對(duì)應(yīng)一個(gè)整形數(shù)废离,默認(rèn)為0,依次遞增礁芦。枚舉類型的變量蜻韭,無論什么類型 都占據(jù)4個(gè)字節(jié)。而枚舉變量中真正存儲(chǔ)的是柿扣,枚舉值對(duì)應(yīng)的整形的數(shù)肖方。所以使用%d輸出枚舉的值。
所以也可以直接為枚舉變量賦值整形變量未状。但是一般不建議這么做 俯画,可讀性降低。命名規(guī)范 首字母大寫司草,每一個(gè)單詞的首字母大寫
枚舉值名稱以枚舉類型名開頭
11.type define 類型定義
作用: 為一個(gè)已經(jīng)存在的數(shù)據(jù)類型取別名艰垂。
例:typedef int clint;
為int數(shù)據(jù)類型去了一個(gè)別名,叫做clint埋虹。這個(gè)時(shí)候clint 完全等價(jià)于int 材泄。
因此當(dāng)數(shù)據(jù)類型很長(zhǎng)的時(shí)候既可以為這個(gè)數(shù)據(jù)類型取一個(gè)短一點(diǎn)的別名。
typedefine 數(shù)據(jù)類型 數(shù)據(jù)類型別名;
typedefine 給結(jié)構(gòu)體和枚舉取別名
1.聲明結(jié)構(gòu)體類型的同時(shí)給結(jié)構(gòu)體區(qū)別名
typedefine struct Student
{
} Student;
2.最常用是為聲明匿名結(jié)構(gòu)體的同時(shí) 取一個(gè)短別名吨岭。
typedefine struct
{
} Student;
3.枚舉同理
typedefine enum
{
} Dreiction;
12. 預(yù)處理指令
C語言從編寫到編譯、鏈接峦树、執(zhí)行的流程
編譯做的事情
- 先執(zhí)行原文件中的預(yù)處理指令辣辫,如果有文件包含指令,就將文件的內(nèi)容拷貝到寫指令的地方魁巩。
- 檢查語法是否符合規(guī)范急灭,符合就生成.o目標(biāo)文件,就是.c 對(duì)應(yīng)的二進(jìn)制指令谷遂。如果不符合語法規(guī)范葬馋,就報(bào)錯(cuò)不生成.o目標(biāo)文件。
- 鏈接
為.o的目標(biāo)文件添加啟動(dòng)代碼
告訴編譯器要調(diào)用的函數(shù)在什么地方
調(diào)用的時(shí)候去正確的地方找實(shí)現(xiàn) - 鏈接成功以后.out文件運(yùn)行即可肾扰。
預(yù)處理指令
預(yù)處理指令以#開頭畴嘶,并且都是在編譯之前執(zhí)行。
預(yù)處理指令類型
- 文件包含指令 #include集晚。
- 宏定義:可以將一段代碼定義為一個(gè)標(biāo)識(shí)窗悯,使用這個(gè)標(biāo)識(shí)就代表這段代碼。
- 條件編譯指令:只編譯指定的C代碼為二進(jìn)制指令偷拔。
宏定義
#define 宏名 宏值
#define N 10
會(huì)將C代碼中使用宏名的地方替換成宏值 過程叫做宏替換
宏值可以是任意語句蒋院,定義宏的時(shí)候亏钩,并不會(huì)去檢查與法,只有當(dāng)完成了宏替換的時(shí)候欺旧,才會(huì)去檢查替換以后的代碼是否符合語法規(guī)范姑丑。
如果宏值是一個(gè)表達(dá)式,那么宏值并不是表達(dá)式的值辞友,而是表達(dá)式本身栅哀。
如果宏值當(dāng)中包括一個(gè)變量名,那么在使用這個(gè)宏之前必須保證這個(gè)變量已經(jīng)存在踏枣。
無法通過賦值符號(hào)位宏賦值昌屉。因?yàn)楹旮揪筒皇亲兞俊?/p>
宏作用域
從定義宏的地方開始,后面的所有地方都可以使用這個(gè)宏茵瀑。就算這個(gè)宏定義在這個(gè)大括弧里面间驮,在這個(gè)后面,哪怕是大括弧的后面都可以使用马昨。
默認(rèn)情況下竞帽,宏從定義的地方一直到文件結(jié)束都可以使用,#undef
可以讓宏提前失效
#undef N
解除宏定義鸿捧,之后宏就不可以使用了 體現(xiàn)實(shí)效
字符串優(yōu)先屹篓,也就是字符串中不會(huì)識(shí)別宏。系統(tǒng)不會(huì)認(rèn)為是一個(gè)宏匙奴,而認(rèn)為是字符串的一部分堆巧。
宏的層層替換。一個(gè)宏值中可以使用另外一個(gè)宏名泼菌。
#define 和typedef的區(qū)別
#define
預(yù)處理指令 在預(yù)編譯的時(shí)候會(huì)把宏明替換成宏值谍肤,typedef
運(yùn)行的時(shí)候才會(huì)執(zhí)行。
#define
可以將任意的C代碼取一個(gè)表示名哗伯, typedef
只能為數(shù)據(jù)類型取名字。
帶參數(shù)的宏
在定義宏的時(shí)候焊刹,宏名是可以帶參數(shù)的。在這個(gè)宏值當(dāng)中虐块,可以直接使用這個(gè)參數(shù)。
#define N(a)
// 如果使用的宏有參數(shù)贺奠,就必須在使用的時(shí)候?yàn)楹陚髦怠?N(10);
宏帶參數(shù)替換的原理
先將參數(shù)賦值,然后在將宏值里面用到參數(shù)的地方替換為值颁糟,最后宏替換航背,將值替換為宏名玖媚。
使用帶參數(shù)的宏注意點(diǎn)
- 宏不是函數(shù),所以宏的參數(shù)不需要添加類型說明今魔。
- 我們?cè)诙x宏的時(shí)候,編譯器是如何區(qū)分宏名和宏值的障贸。
#define 宏名 宏值
宏名中不可以有空格错森,與參數(shù)之間也不可以有空格。 - 為帶參數(shù)的宏傳值的時(shí)候篮洁,是本色傳遞涩维,如果傳遞一個(gè)變量,并不是傳遞這個(gè)變量的值袁波,而是直接傳遞的就是這個(gè)變量的串瓦阐。
- 宏值一旦換行就認(rèn)為宏定義結(jié)束了,需要使用 \ 來拼接宏
- 宏只適合于少量的代碼篷牌。
條件編譯指令
- 預(yù)處理指令睡蟋, 在預(yù)編譯階段執(zhí)行。
- 作用:默認(rèn)情況下,我們所有的C代碼都會(huì)被編譯為二進(jìn)制代碼,條件編譯指令的作用疚漆,可以讓編譯器只編譯部分的代碼。
-
#if #elif #endif
必須要有#endif
#if
和if
語句的區(qū)別
- 條件編譯指令是一個(gè)預(yù)處理指令豺瘤,在預(yù)處理階段執(zhí)行,而
if
語句是C代碼听诸,在程序運(yùn)行的時(shí)候執(zhí)行。 - if語句無論如何全都要被編譯為二進(jìn)制指令蚕泽,條件編譯指令:只會(huì)將符合條件的C代碼編譯為二進(jìn)制指令晌梨。
- 條件編譯指令參數(shù)必須為宏。
#ifdef 宏名
如果定義了宏名的宏 就編譯其中的代碼
#ifndef 宏名
如果沒有定義宏名就來到這里须妻。
#endif
13. static 和 extern
C語言當(dāng)中的兩個(gè)關(guān)鍵字仔蝌,是用來修飾變量和函數(shù)的。
如果都沒有修飾 默認(rèn)是 extern 荒吏。
static和extern修飾局部變量
static修飾局部變量敛惊,那么這個(gè)變量就叫做靜態(tài)變量,靜態(tài)變量不在存儲(chǔ)在棧區(qū)绰更,而是存儲(chǔ)在常量區(qū)中瞧挤,當(dāng)函數(shù)執(zhí)行完畢之后锡宋,這個(gè)靜態(tài)變量不會(huì)被回收。
當(dāng)?shù)谝淮螆?zhí)行這個(gè)函數(shù)的時(shí)候特恬,就會(huì)將這個(gè)靜態(tài)變量聲明在常量區(qū)执俩,第二次去執(zhí)行這個(gè)函數(shù)的時(shí)候役首,聲明靜態(tài)變量的這句話就不會(huì)在執(zhí)行了衡奥,而是直接略過远荠,直接使用靜態(tài)變量的值矮台。
所以static修飾的靜態(tài)變量瘦赫,函數(shù)結(jié)束不會(huì)被回收确虱,仍然存在窘问,函數(shù)無論執(zhí)行多少次宜咒,這個(gè)靜態(tài)變量只有一份故黑。
extern不能修飾局部變量场晶。static和extern修飾全局變量的效果
一個(gè)全局變量诗轻,最完整的步驟也應(yīng)該分為兩步,1.先寫全局變量的聲明搔体,只定義而不賦值侦高。2.在寫全局變量的定義奉呛,定義全局變量并初始化瞧壮。
全局變量可以只有聲明咆槽,如果這樣的話秦忿,那么這個(gè)全局變量的值背會(huì)編譯器自動(dòng)的去實(shí)現(xiàn)灯谣,會(huì)將這個(gè)全局變量自動(dòng)初始化為0。
全局變量也可以只有定義而沒有聲明峻呛,但是這個(gè)時(shí)候钩述,這個(gè)全局變量的定義必須要在使用全局變量的函數(shù)的前面。
全局變量的聲明要寫在.h文件中所禀,全局變量的實(shí)現(xiàn)要寫在.c文件中北秽。
如果將全局變量定義在模塊之中贺氓,這個(gè)全局變量就必須要使用static或者extern來修飾
static修飾全局變量辙培,這個(gè)全局變量只能在當(dāng)前 模塊訪問搀别。
extern修飾全局變量歇父,這個(gè)全局變量就可以跨模塊訪問再愈。static和extern修飾函數(shù)的效果
static修飾函數(shù) 函數(shù)只可以在當(dāng)前模塊訪問
extern修飾函數(shù) 那么函數(shù)可以跨模塊調(diào)用
文中如果有不對(duì)的地方歡迎指出垂睬。我是xx_cc驹饺,一只長(zhǎng)大很久但還沒有二夠的家伙赏壹。
本文已在版權(quán)印備案疟暖,如需轉(zhuǎn)載請(qǐng)?jiān)L問版權(quán)印俐巴。92899035