我們都知道C語言關(guān)鍵字有auto、if、int等等…但是我們知道C語言一共有多少個(gè)關(guān)鍵字呢?
一般來說,共有32個(gè)關(guān)鍵字(C90或C89標(biāo)準(zhǔn));
但是后面C99又新增了5個(gè)關(guān)鍵字;但是目前主流的編譯器,對(duì)C99好多并不支持;
所以,我們默認(rèn)按照C90標(biāo)準(zhǔn),即C語言共有32個(gè)關(guān)鍵字;
關(guān)鍵字 | 說明 |
---|---|
auto | 聲明自動(dòng)變量 |
short | 聲明短整型變量或函數(shù) |
int | 聲明整形變量或函數(shù) |
long | 聲明長整型變量或函數(shù) |
float | 聲明單精度浮點(diǎn)數(shù)變量或函數(shù) |
double | 聲明雙精度浮點(diǎn)數(shù)或函數(shù) |
char | 聲明字符型變量或函數(shù) |
struct | 聲明結(jié)構(gòu)體變量或函數(shù) |
union | 聲明共用數(shù)據(jù)類型 |
enum | 聲明枚舉類型 |
typedef | 用以給數(shù)據(jù)類型取別名 |
const | 聲明只讀變量 |
unsigned | 聲明無符號(hào)變量或函數(shù) |
signed | 聲明有符號(hào)變量或函數(shù) |
extern | 聲明變量是在其他文件中聲明 |
register | 聲明寄存器變量 |
static | 聲明靜態(tài)變量 |
volatile | 說明變量在程序執(zhí)行中可被隱含的改變 |
void | 聲明函數(shù)無返回值或無參數(shù),聲明無類型指針 |
if | 條件語句 |
else | 條件語句與分支語句(與if合用) |
switch | 用于開關(guān)語句 |
case | 開關(guān)語句分支 |
for | 循環(huán)語句 |
do | 循環(huán)語句的循環(huán)體 |
while | 循環(huán)語句的循環(huán)條件 |
goto | 無條件跳轉(zhuǎn)語句 |
continue | 結(jié)束當(dāng)前一層循環(huán),開始下一輪循環(huán) |
break | 跳出當(dāng)前循環(huán) |
default | 開關(guān)語句中的“其他”分支 |
sizeof | 計(jì)算數(shù)據(jù)類型長度 |
return | 子程序返回語句循環(huán)條件(可帶參數(shù),也可不帶) |
//從vs中創(chuàng)建c語言項(xiàng)目
#include#include//此頭文件僅僅是為了停屏
int main()
{printf("hello world!\n");
system("pause");//pause停屏,我們可以看到終端
return 0;
}
在windows系統(tǒng)中,我們雙擊的本質(zhì)就是運(yùn)行程序,將程序添加到內(nèi)存當(dāng)中
任何程序在運(yùn)行之前都必須加載到內(nèi)存當(dāng)中
注意: 程序在沒有加載的時(shí)候,是放在硬盤當(dāng)中的;我們之所以加載到內(nèi)存當(dāng)中 -》快;
問題1:什么是變量?—在內(nèi)存中開辟特定大小的空間,用來保存數(shù)據(jù)
問題2:如何定義變量:類型 變量名 = 默認(rèn)值;例如:int a = 10; double d = 3.14; char c = 'a';
問題3:為什么要定義變量?—
計(jì)算機(jī)的誕生就是為了解決人類計(jì)算能力不足的問題;即計(jì)算機(jī)就是為了計(jì)算的。
而計(jì)算,就需要數(shù)據(jù);
我們計(jì)算數(shù)據(jù),并不是無時(shí)無刻都需要計(jì)算;例如:我們吃飯并不是所有飯菜都立刻吃掉的,我們需要碗和盤子,把飯菜放到里面,想吃的時(shí)候就吃;
那么,有人就會(huì)抬杠:為什么要盤子,不可以直接使用在鍋里吃嗎?可以,但是效率低
總之:我們定義變量是為了在我們想用的時(shí)候可以立即拿出,不用的時(shí)候就放在那就可以了;
總結(jié):變量的定義:開辟空間的,定義只能定義一次(你不可能和翠花表白很多次,別人會(huì)被你嚇跑的);變量的聲明是告之,可以聲明很多次;但是在聲明的時(shí)候,我們就不可以進(jìn)行賦值操作了(編譯器會(huì)有可能把這個(gè)過程看成是定義過程)
變量的作用域與生命周期#include#includeint g_x = 100;//全局變量
int main()
{int x = 10;
if (x)
{int y = 20;//局部變量
//y只能在代碼塊內(nèi)有效,而全局變量g_x在哪里都有效
printf("局部變量 y = %d, 全局變量 g_x = %d\n", y, g_x);
}
//printf("局部變量 y = %d\n", y);//錯(cuò)誤,局部變量只在本代碼塊內(nèi)有效
system("pause");
return 0;
}
在c語言中,auto的用法很少且比較雞肋,用處不大;但是在 C++ 中給auto賦予了很多的用處(配合STL);但是在C語言里面我們就暫且不說C++的知識(shí)了;
auto這個(gè)關(guān)鍵字一般是用來修飾局部變量的,默認(rèn)情況下都是auto修飾的(局部變量、自動(dòng)變量、臨時(shí)變量我們統(tǒng)稱為局部變量)
#include#includeint main()
{for (auto i = 1; i< 10; i++)
{printf("i = %d\n", i);
if (1)
{ auto j = 0;//局部變量,這一個(gè)代碼塊結(jié)束之后,j又被賦值成0
printf("before: j = %d\n", j);
j += 1;
printf("after: j = %d\n", j);//j是0/1循環(huán)的
}
}
system("pause");
return 0;
}
注意:這里面的auto都是可以省略的,在C語言中我們可以忽略這個(gè)關(guān)鍵字
最快的關(guān)鍵字 – register(寄存器變量)我們學(xué)習(xí)過計(jì)組的話,就會(huì)知道計(jì)算機(jī)的系統(tǒng)結(jié)構(gòu);其中,CPU主要負(fù)責(zé)計(jì)算相關(guān)的硬件單元,但是為了方便計(jì)算,(解決CPU與內(nèi)存之間速度差異的問題)一般第一步需要把數(shù)據(jù)從內(nèi)存中讀取到CPU中,也就是需要CPU具有一定的存儲(chǔ)能力;注意:CPU可能并不是需要計(jì)算當(dāng)前讀入到里面的數(shù)據(jù),只是為了提前存儲(chǔ)好,想用就可以用了,不然的話,速度太慢了;
我們來看一下CPU存儲(chǔ)金字塔:
距離CPU越近的存儲(chǔ)硬件,速度越快
- 局部的(全局變量會(huì)導(dǎo)致CPU寄存器被長時(shí)間占用)
- 不會(huì)被寫入的(寫入需要回內(nèi)存,后續(xù)還要讀取檢測的話,register就沒有意義了)
- 高頻率讀取的(提高效率)
- 寄存器數(shù)量有限,不可以大量使用register關(guān)鍵字
注意:除了以上的內(nèi)容,還有就是:register修飾的變量不可以取地址(地址是內(nèi)存相關(guān)的概念)
demo:
#include#includeint main()
{register int a = 10;
printf("&a = %p\n", &a);//報(bào)錯(cuò) -- C2103 寄存器變量上的“& ”
system("pause");
return 0;
}
最名不符實(shí)的關(guān)鍵字 – static在講這個(gè)關(guān)鍵字之間,我們之前應(yīng)該了解到,我們自己在寫C語言項(xiàng)目的時(shí)候,項(xiàng)目會(huì)非常大且復(fù)雜,我們一般都是會(huì)寫很多了源文件(.c文件)和一個(gè)頭文件(.h);我們把所有用到的函數(shù)、變量、頭文件、#define、struct、typedef等等都會(huì)放到 .h(頭文件) 文件中,這樣可以大大減少項(xiàng)目的維護(hù)成本;這里面又會(huì)牽扯到頭文件重復(fù)包含的問題,我們先給一個(gè)解決方案,后面還會(huì)細(xì)講
#pragma once
我們先提一下extern這個(gè)關(guān)鍵字,當(dāng)我們想跨源文件來使用某個(gè)變量或函數(shù)的時(shí)候,就必須使用到這個(gè)關(guān)鍵字例如:extern int g_val;
函數(shù)可以直接在頭文件聲明,不需要使用 extern,但是最好也帶上extern void show();
總結(jié):變量聲明必須帶上extern,函數(shù)聲明建議帶上extern(變量不可以跨文件訪問,而函數(shù)可以跨文件訪問)
static的作用
demo:
#include#includevoid fun1()
{int i = 0;
i++;
printf("no static: i = %d\n", i);//輸出10個(gè)1
}
void fun2()
{static i = 0;
i++;
printf("has static: i = %d\n", i);//輸出1-10;更改了i的生命周期
}
int main()
{for (int i = 0; i< 10; i++)
{//fun1();
fun2();
}
system("pause");
return 0;
}
總結(jié):static修飾局部變量,變量的生命周期會(huì)變成全局周期(作用域不變)
補(bǔ)充一下C語言尋址空間的知識(shí)
基本內(nèi)置數(shù)據(jù)類型 – char、short、int、long、float、double基本數(shù)據(jù)類型有以下幾種:
我們這里先講解基本的內(nèi)置類型:
這里,我們只需要搞懂一個(gè)問題:為什么語言要有好多種數(shù)據(jù)類型,直接將內(nèi)存整體使用不好嗎?
在任何時(shí)候,都不是只有我們當(dāng)前的程序在運(yùn)行,還有其他很多種程序在運(yùn)行,你把這塊內(nèi)存占用了,其他的程序并不知道你正在使用這塊內(nèi)存,他不知道是不是可以使用;還有,你把這塊內(nèi)存全用了,你的程序并不是無時(shí)無刻都在使用,當(dāng)不需要使用的時(shí)候,你就是在浪費(fèi)這塊內(nèi)存了;
做月餅的例子:月餅的外表有各種各樣的,我們只需要使用不同的模子就可以制造出各種各樣的月餅了;
所以,C語言中,為什么有那么多的類型,就是為了滿足不同的場景
比如:我們想計(jì)算我們的工資的時(shí)候,4個(gè)字節(jié)的int就足夠了,沒有必要開大
那么,我們這里就需要知道,這些類型到底在內(nèi)存中占用多少內(nèi)存大小呢?
注意:上面的單位都是字節(jié)
最冤枉的關(guān)鍵字 – sizeof我們?yōu)槭裁捶Qsizeof為最冤枉的關(guān)鍵字?就是因?yàn)槌D陝e人都把他誤認(rèn)為是函數(shù),這是錯(cuò)誤的,sizeof是C語言中的關(guān)鍵字
我們只需要記住sizeof是計(jì)算類型或變量在內(nèi)存中占多大空間的就可以了,上面我們已經(jīng)計(jì)算過了,至于sizeof與指針的內(nèi)容,我們會(huì)在后面指針的部分講到;
注意1:
int a = 10;
printf("%d\n", sizeof(a));//對(duì)
printf("%d\n", sizeof a);//對(duì)
printf("%d\n", sizeof(int));//對(duì)
printf("%d\n", sizeof int);//錯(cuò)誤
注意2:sizeof后面的括號(hào)里是不允許有其他操作的,就算寫也不起效果
int a = 10;
printf("%d\n", sizeof(a++));
printf("%d\n", a);//a還是10
signed、unsigned關(guān)鍵字(整形在內(nèi)存中的存儲(chǔ))浮點(diǎn)數(shù)(float、double)都是有符號(hào)的,浮點(diǎn)數(shù)沒有unsigned
我們需要先理解原碼、反碼、補(bǔ)碼的概念:
我們知道,一個(gè)變量的創(chuàng)建是現(xiàn)在內(nèi)存中開辟空間的,空間的大小是由類型決定的
那么,數(shù)據(jù)開辟好了空間,在內(nèi)存中到底是怎樣存儲(chǔ)的呢?
我們?cè)诙x類型的時(shí)候,默認(rèn)前面省略了 signed
我們現(xiàn)在來看個(gè)問題?unsigned int b = -10;
這個(gè)寫法是否正確呢?
答案?這樣寫是沒有問題的,是正確的的;整形在存儲(chǔ)的時(shí)候,是不關(guān)心內(nèi)容的
我們來看下面這個(gè)例子:
我們a雖然是有符號(hào)的整形,但是我們?nèi)〕鰜淼臅r(shí)候,按照有符號(hào)的整形打印他就是-10,而我們把它當(dāng)成無符號(hào)的整形取出來的時(shí)候,就是那個(gè)值了;同理b;所以我們發(fā)現(xiàn):我們定義變量,給他類型,只是給他開辟了特定的空間,到底存放什么內(nèi)容我們不用管,但是取出來的時(shí)候,我們就必須看他是什么類型,或者你按照什么類型給他取出來的
下面還有幾個(gè)小的知識(shí)點(diǎn),我們來看看吧~
到這里,我們已經(jīng)知道了我們的數(shù)據(jù)是存放到內(nèi)存里面,按照補(bǔ)碼形式進(jìn)行存儲(chǔ)的,那么我們來看一下到底是怎樣存的呢?
我們以int a = 10;
來看一下
我們發(fā)現(xiàn)在vs中,我們的變量最后在內(nèi)存中是這樣存儲(chǔ)的,我們來分析一下?
10的補(bǔ)碼是:0000 0000 0000 0000 0000 0000 0000 1010
在計(jì)算中存儲(chǔ)的是十六進(jìn)制:0x00 00 00 0A
為什么我們?cè)趦?nèi)存中看到的是反過來的呢?0x0a 00 00 00
這里我們需要了解大小端的概念:我們定義好變量后,會(huì)開辟一片空間,將變量的二進(jìn)制補(bǔ)碼寫入到內(nèi)存中,那么我們?nèi)绾螌戇M(jìn)去呢?是從前往后寫,還是從后往前寫呢?這里沒有特定的要求,不管我們?cè)趺捶?,只要使用同等的條件去取就可以了?由此,產(chǎn)生了兩種不同的廠商,分為大端和小端,目前比較流行的是小端。
對(duì)于大小端這件事,對(duì)于每個(gè)人是無法達(dá)到一致的,每個(gè)人都有每個(gè)人的看法,我們都沒有足夠的理由說服對(duì)方;
對(duì)于數(shù)據(jù)的存與取,我們除了要看上面我們學(xué)的看數(shù)據(jù)類型,這里還要加一個(gè)看是使用大端存儲(chǔ),還是小端存儲(chǔ)不管哪種存儲(chǔ)方式,我們只要使用同等條件去取,都可以!
我們?cè)趺磁袆e我們電腦使用大端還是小端呢?(2015年百度一道筆試題)
#include#includeint check_sys()
{int i = 1;
return (*(char*)&i);
}
int main()
{int ret = check_sys();
if (ret == 1) printf("小端\n");
else printf("大端\n");
system("pause");
return 0;
}
上面輸出的結(jié)果是小端;我們來解釋一下return (*(char*)&i);
這一段代碼:我們知道 i 放到內(nèi)存中的十六進(jìn)制數(shù)是:0x01 00 00 00;我們只需要看 i 的第一個(gè)字節(jié)內(nèi)容,如果是1就是小端,如果是0就是大端;那么我們?cè)趺床趴梢阅玫?i 的第一個(gè)字節(jié)呢?char* 的指針正好就是訪問一個(gè)字節(jié)的地址,我們完整的代碼就是:
int i = 1;
char* p = (char*)&i;
if(*p == 1) printf("小端\n");
else printf("大端\n");
為什么變量采用的都是補(bǔ)碼來進(jìn)行存儲(chǔ)?
整形取值范圍(很重要)
簡單為例,我們就以 signed char 為例,其它的和這類似!
那么為什么 1000 0000 就表示成-128呢?我們來看看char c = -128;
在內(nèi)存中表示多少
我們可以發(fā)現(xiàn)char類型是可以存放-128這個(gè)數(shù)據(jù)的,而128就不可以,這是為什么呢?
我們可以總結(jié)一下各種數(shù)據(jù)類型的取值范圍:
好了,到這里我們整形數(shù)據(jù)存儲(chǔ)的知識(shí)就學(xué)的就差不多了,我們來做幾個(gè)題目檢驗(yàn)一下成果吧!
例題一:
#include#includeint main()
{char a[1000];
for (int i = 0; i< 1000; i++) a[i] = -1 - i;
printf("%d\n", strlen(a));
system("pause");
return 0;
}
第一點(diǎn):我們首先要知道 strlen 這個(gè)庫函數(shù)是計(jì)算字符串長度的,遇到 ‘\0’ 截至,并且 ‘\0’ 不計(jì)算在長度內(nèi);'\0’對(duì)應(yīng)的ASCII碼值就是0。例如:char a[5] = {3, ‘h’, 5, 0, ‘e’};則 strlen(a)的答案就是3,只計(jì)算0前面的字符串長度,且0不包括在內(nèi)。
第二點(diǎn):我們需要知道當(dāng)變量取值范圍超過大值時(shí),之后的值該是多少?
因此,這道題的答案就是255!
例題二:
#include#includeint main()
{int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);
system("pause");
return 0;
}
例題三:
#include#includeint main()
{unsigned int i;
for (i = 9; i >= 0; i--) printf("%u\n", i);
system("pause");
return 0;
}
這個(gè)題我們要注意:i是個(gè)無符號(hào)整形變量,打印的時(shí)候,會(huì)依次打印9 、8、7、6、5…0,當(dāng)打印到0的時(shí)候,i 再減1,就相當(dāng)于 i + (-1);也就是:
這個(gè)數(shù)按照 unsigned int 來打印的話就是 2 ^ 32 - 1 那么大
其實(shí)變量的取值范圍就是按照之前我給大家畫的那個(gè)圓來記,以 signed char 來說:
當(dāng)變量取到頭的時(shí)候,會(huì)再循環(huán)一圈,以此類推…
還有我們?cè)诙xunsigned類型的時(shí)候,最后最好加個(gè) u,就像定義 float類型在后面加個(gè) f一樣,例如:unsigned int u = 10u;
還有一點(diǎn),大家在這里的時(shí)候,記得與整形提升不要搞混淆
c前面的 c + 1會(huì)把char類型的變量整形提升到 int 型,再進(jìn)行加法運(yùn)算
整形提升:在表達(dá)式計(jì)算時(shí),各種整形首先要提升為 int 類型;表達(dá)式的整形運(yùn)算要在CPU的相應(yīng)器件內(nèi)進(jìn)行,CPU運(yùn)算器的操作數(shù)的字節(jié)長度一般是 int 類型的字節(jié)長度
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧