C語(yǔ)言知識(shí)點(diǎn)保姆級(jí)總結(jié),這不得進(jìn)你的收藏夾吃灰?!
拖了很久的C語(yǔ)言所學(xué)知識(shí)的簡(jiǎn)單小結(jié),內(nèi)容有點(diǎn)多,第一次總結(jié)也可能有錯(cuò)誤或者不全面,歡迎隨時(shí)補(bǔ)充說明!
? 用不同數(shù)據(jù)類型所定義的變量所占空間大小不一樣,定義的變量不是保存于數(shù)據(jù)類型中,而是因?yàn)橹挥卸x了該數(shù)據(jù)類型的變量才能保存數(shù)據(jù)。
一、整型? 1、整型(int) 四字節(jié),默認(rèn)有符號(hào)(-231-231-1),無(wú)符號(hào)加unsigned(0-232-1)(十位數(shù));
? 2、短整型(short int) ,兩字節(jié)(-215-215-1)(五位數(shù));
? 3、長(zhǎng)整型(long int) ,四字節(jié)(同int,在目前的操作系統(tǒng)中幾乎沒有區(qū)別);
? 4、長(zhǎng)長(zhǎng)整型(long long int), 八字節(jié)(-263-263-1),無(wú)符號(hào)(0-264-1);
二、浮點(diǎn)型? 1、單精度浮點(diǎn)數(shù)(float),四字節(jié),保留小數(shù)點(diǎn)后6位
? 2、雙精度浮點(diǎn)數(shù)(double),八字節(jié),保留小數(shù)點(diǎn)后15位
int為一個(gè)32為的存儲(chǔ)單元,long long為64為的存儲(chǔ)單元
1 B/byte(字節(jié)) = 8 bit(比特)(位)
1 KB(千字節(jié)) = 1024 B/byte(字節(jié))
1 MB = 1024 KB
1 GB = 1024 MB
1TB =1024 GB
1 PB = 1024 TB
1 EB = 1024 PB
三、字符型? char,用于儲(chǔ)存字符,和int很像,可用ASCII碼來(lái)儲(chǔ)存字符,
eg:
char grade=’A’;
char grade=65;
' '單引號(hào)為字符,eg:char a='a';
? " "雙引號(hào)為字符串,eg:char* a=“asd”;編譯器會(huì)自動(dòng)給字符串結(jié)尾添加’\0‘來(lái)作為字符結(jié)束標(biāo)識(shí),strlen函數(shù)中不統(tǒng)計(jì)\0,但是\0在內(nèi)存中占據(jù)空間。
? 除此之外,還有轉(zhuǎn)義字符,通過反斜杠來(lái)完成相關(guān)操作,如果要特殊字符轉(zhuǎn)字面字符需要另外添加反斜杠,轉(zhuǎn)義字符在字符串中占空間,但是只計(jì)算一個(gè)長(zhǎng)度,\0不計(jì)長(zhǎng)度。
?
? 作用域(scope),程序設(shè)計(jì)概念,通常來(lái)說,一段程序代碼中所用到的名字并不總是有效/可用的,而限定這個(gè)名字的可用性的代碼范圍就是這個(gè)名字的作用域。
? 生命周期:變量的生命周期指的是變量的創(chuàng)建到變量的銷毀之間的一個(gè)時(shí)間段
#includeint global = 2019;//全局變量
int main()
{
int local = 2018;//局部變量
return 0;
}
分支及循環(huán)語(yǔ)句
一、分支語(yǔ)句? 1、if語(yǔ)句
? 語(yǔ)法結(jié)構(gòu):
if(表達(dá)式)
語(yǔ)句;
if(表達(dá)式){
語(yǔ)句列表1
}
else{
語(yǔ)句列表2;
}
//多分支
if(表達(dá)式1){
語(yǔ)句列表1;
}
else if(表達(dá)式2){
語(yǔ)句列表2;
}
else{
語(yǔ)句列表3;
}
? 表達(dá)式部分為真則執(zhí)行語(yǔ)句(0為假,非0為真),盡量在每個(gè)分支語(yǔ)句后都加{},否則只會(huì)執(zhí)行分支后第一條語(yǔ)句。
? else在沒有括號(hào)的情況下遵循就近原則所以在多重if語(yǔ)句嵌套使用情況下一定要加括號(hào)!
? 2、switch語(yǔ)句
? switch作為分支結(jié)構(gòu)常用于多分支的情況,可以簡(jiǎn)化多重if語(yǔ)句嵌套的情況。
? 語(yǔ)法結(jié)構(gòu)
switch(表達(dá)式A){
case 常量表達(dá)式1:
語(yǔ)句1;
break;
case 常量表達(dá)式2:
語(yǔ)句2;
break;
……
case 常量表達(dá)式n:
語(yǔ)句n;
break;
default:
語(yǔ)句n+1;
break;
}
? 其中
? 1、case后第一句不可定義變量,必須跟常量或者常量表達(dá)式,并且不可相同;
? 2、break在語(yǔ)句中可以起到劃分作用,不可省略,否則無(wú)法實(shí)現(xiàn)分支功能;
? 3、default語(yǔ)句不應(yīng)該省略,一般推薦位語(yǔ)句列表末尾;
? 4、switch語(yǔ)句結(jié)束條件:①遇到break;②執(zhí)行到語(yǔ)句列表末尾。
二、循環(huán)語(yǔ)句? 1、while語(yǔ)句
? 語(yǔ)法結(jié)構(gòu)
while(表達(dá)式){
循環(huán)語(yǔ)句;
}
? 注:在循環(huán)語(yǔ)句中break的作用是停止后期所有循環(huán),continue的作用是終止本次循環(huán),開始下一次循環(huán)的判斷。
? 2、for語(yǔ)句
for(表達(dá)式1;表達(dá)式2;表達(dá)式3){
循環(huán)語(yǔ)句;
}
? 表達(dá)式1為初始化部分,用于初始化循環(huán)變量,當(dāng)表達(dá)式1為空時(shí)直接進(jìn)入循環(huán);
? 表達(dá)式2 為條件判斷部分,用于判斷循環(huán)是否終止,當(dāng)表達(dá)式2為空時(shí)為死循環(huán);
? 表達(dá)式3為調(diào)整部分,用于循環(huán)條件的調(diào)整 。
? 注:建議使用“前閉后開”來(lái)限定區(qū)間范圍。
for(i=0; i<10; i++){
a[i]=i;
}
? 3、do while語(yǔ)句
do{
循環(huán)語(yǔ)句;
}while(表達(dá)式);
? 循環(huán)體至少執(zhí)行一次,while之后記得加分號(hào)。
? 二分查找函數(shù)循環(huán)實(shí)現(xiàn)范例:
int bin_search(int arr[], int left, int right, int key)
{
int mid = 0;
while(left<=right){
mid = (left+right)>>1;
if(arr[mid]>key)
{
right = mid-1;
}
else if(arr[mid]< key)
{
left = mid+1;
}
else
{
return mid;//找到了,返回下標(biāo)
}
}
return -1;//找不到
}
函數(shù)
一、庫(kù)函數(shù)? C語(yǔ)言基礎(chǔ)庫(kù)中的函數(shù),在添加頭文件后可直接調(diào)用。
二、自定義函數(shù) 1、函數(shù)組成? 由函數(shù)名、返回值類型、函數(shù)參數(shù)以及函數(shù)體組成。
? 實(shí)參:真實(shí)的傳入函數(shù)的變量,**在被調(diào)用時(shí)會(huì)發(fā)生臨時(shí)拷貝,并非把原來(lái)的變量直接放入函數(shù)中,**只是把實(shí)參的數(shù)據(jù)拷貝給形參。
? 形參:函數(shù)名括號(hào)后的變量,因?yàn)樾螀⒅挥性诒徽{(diào)用的時(shí)候才被實(shí)例化并分配空間(形參實(shí)例化),**在被調(diào)用過后即被銷毀,只在該函數(shù)中有效(局部變量),**所以叫形參。
? 函數(shù)聲明,要滿足先聲明后使用的原則,由返回值類型、函數(shù)名與函數(shù)參數(shù)組成(需要加分號(hào)), 當(dāng)我們用到很多函數(shù)聲明的時(shí)候,為了方便我們的調(diào)用,我們可以創(chuàng)建一個(gè)頭文件.h(比如test.h),將函數(shù)聲明放在頭文件當(dāng)中 ,在寫頭文件時(shí),要注意加上#pragma once 。
//函數(shù)定義
double Add(double x, double y){
return x+y;
}
//函數(shù)聲明
double Add(double x, double y);
2、函數(shù)調(diào)用? 分為傳值調(diào)用與傳址調(diào)用,其中傳址調(diào)用是把函數(shù)外部創(chuàng)建的內(nèi)存地址傳遞給函數(shù),可以真正與原值建立起聯(lián)系,直接操縱函數(shù)外部的變量。
? 函數(shù)也可以進(jìn)行嵌套調(diào)用以及鏈?zhǔn)皆L問。
? 嵌套調(diào)用樣例:
#includevoid new_line()
{
printf("hehe\n");
}
void three_line()
{
int i = 0;
for(i=0; i<3; i++)
{
new_line();
}
}
int main()
{
three_line();
return 0;
}
? 鏈?zhǔn)皆L問樣例:
#include#includeint main()
{
char arr[20] = "hello";
int ret = strlen(strcat(arr,"bit"));
printf("%d\n", ret);
return 0;
}
3、函數(shù)遞歸? 程序自身調(diào)用被稱為遞歸,把復(fù)雜問題層層轉(zhuǎn)化為與原問題類似的小問題,函數(shù)在調(diào)用自身的情況下存在不合法遞歸(即無(wú)限次的遞歸導(dǎo)致棧溢出)。
? 所以在使用遞歸的時(shí)候一定要有遞歸出口,否則會(huì)陷入死循環(huán)導(dǎo)致棧溢出!
? **注:**棧結(jié)構(gòu)為電腦存儲(chǔ)的一部分,從高地址處向下開辟存儲(chǔ)空間,與用于開辟動(dòng)態(tài)存儲(chǔ)空間的堆相向開辟(堆為從低地址出向上開辟存儲(chǔ)空間),而函數(shù)調(diào)用將會(huì)形成棧幀,函數(shù)返回后自動(dòng)釋放棧幀結(jié)構(gòu),在此過程中,該函數(shù)定義的所有局部變量都在該函數(shù)的棧幀內(nèi)進(jìn)行空間開辟。
樣例:求n的階乘
int factorial(int n)
{
if(n<= 1)
return 1;
else
return n* factorial(n-1);
}
? 遞歸與迭代
? 遞歸在使用過程中由于頻繁進(jìn)行函數(shù)調(diào)用,且每次調(diào)用都需要時(shí)間成本以及空間成本,所以遞歸程序簡(jiǎn)單,但是可能導(dǎo)致遞歸效率變低的問題,而迭代方案通過對(duì)變量值進(jìn)行替換所以不會(huì)造成棧溢出,解決了效率低下的問題。
? 樣例(求斐波那契數(shù)列第n個(gè)的值):
//遞歸實(shí)現(xiàn)
int fibrec(int n){
if(n<=2) retuen 1;
else return fibrec(n-1)+fibrec(n-2);
}
//迭代實(shí)現(xiàn)
int fibite(int n){
int fir=1,sec=1,thd=2;
if(n<=2) return 1;
else{
while(n>2){
fir=sec;
sec=thd;
thd=fir+sec;
n--;
}
return thd;
}
}
數(shù)組
一、一維數(shù)組的創(chuàng)建與初始化? 創(chuàng)建數(shù)組時(shí)數(shù)組空間為整體開辟整體釋放,在內(nèi)存中是連續(xù)存放,在定義時(shí)就已經(jīng)確定數(shù)組大小(下標(biāo)不可為0),且不可被整體賦值。在數(shù)組的創(chuàng)建過程中,如果進(jìn)行了初始化則可不指定數(shù)組的大小,多維數(shù)組按照一維數(shù)組進(jìn)行理解。
? 數(shù)組傳參發(fā)生降維,降維成指向其(數(shù)組)內(nèi)部元素類型的指針。
? 數(shù)組名一般情況下都指的是首元素的地址,但如果sizeof()單獨(dú)出現(xiàn)以及&后跟數(shù)組名時(shí)表示的是整個(gè)數(shù)組
int s[5];
//表示數(shù)組首元素地址
printf("%d\n", sizeof(s+1));//結(jié)果為4/8,指針的具體大小根據(jù)編譯器的不同大小不同
//表示整個(gè)數(shù)組
printf("%d\n", sizeof(s));//結(jié)果為20
二、數(shù)組傳參(函數(shù))? 由于在傳參過程中如果拷貝整個(gè)指針會(huì)導(dǎo)致效率大大降低甚至導(dǎo)致棧溢出,所以數(shù)組傳參要發(fā)降維問題,函數(shù)內(nèi)數(shù)組作為參數(shù)時(shí),實(shí)參為首元素地址,形參為指針。
? 在訪問結(jié)構(gòu)體成員時(shí)也同樣要發(fā)生類似的操作,用指向結(jié)構(gòu)體的指針來(lái)指代結(jié)構(gòu)體。
typedef struct node{
int a;
int b;
}point;
void pop(int* p){
}
int main(){
point a;
int* p=a;
pop(p);
return 0;
}
? 傳參樣例:
//用數(shù)組的形式傳遞參數(shù),不需要指定參數(shù)的大小,傳的只是數(shù)組首元素的地址。
void test(int arr[])
{}
//也可以傳入數(shù)組大小
void test(int arr[10])
{}
//數(shù)組降維,用指針進(jìn)行接收,傳的是數(shù)組首元素的地址
void test(int *arr)
{}
//二維數(shù)組傳參,第一個(gè)方括號(hào)可以空,但是第二個(gè)不可以空
void test(int arr[][5])
{}
void test(int arr[4][5])
{}
//傳過去的是二維數(shù)組的數(shù)組名,即數(shù)組首元素的地址,也就是第一行的地址,第一行也是個(gè)數(shù)組,用一個(gè)數(shù)組指針接收(比較少用)
void test(int (*arr)[5])
{}
三、字符數(shù)組char a[]={'a','x','d'};
//此處由于結(jié)尾沒有'\0',strlen的機(jī)制是遇到'\0'即停止,所以在結(jié)尾沒有'\0'時(shí)為隨機(jī)數(shù)
//strlen(a)為隨機(jī)數(shù)
//sizeof(a)為3
char a[]={'a','x','d','\0'};
//strlen(a)為3
//sizeof(a)為4
char* a="axd";//或char a[]="axd"
//直接通過""定義字符串時(shí),會(huì)自動(dòng)在結(jié)尾補(bǔ)'\0',不需要自行補(bǔ)充,但'\0'依舊會(huì)占據(jù)一個(gè)字節(jié)
//strlen(a)為3
//sizeof(a)為4
char c[5]={'a', 'b', '\0', 'c', '\0'};
printf("%s", c);//結(jié)果為ab,因?yàn)樽址Y(jié)束標(biāo)志位'\0'
操作符
一、運(yùn)算優(yōu)先級(jí)? 注:①++/–高于解引用;
? ②解引用高于±*/
? ③±*/高于位運(yùn)算;
? ④位運(yùn)算高于+=、-=、/=、*=;
%操作兩邊必須是整數(shù)。
二、二進(jìn)制中的操作符 1、位運(yùn)算基本介紹與運(yùn)算:&
? 同1則1,否則為0;
或運(yùn)算:|
? 同0為0,否則為1
非運(yùn)算:~
? 1取0 0 取1
異或運(yùn)算:^
? 兩者相等為0,不等為1
移位運(yùn)算操作符:<< 左移 ; >>右移
? ①**<<左移:**左邊拋棄末尾補(bǔ)0;負(fù)數(shù)對(duì)反碼的補(bǔ)碼進(jìn)行移位操作;相當(dāng)于乘2;
? ②**>>右移:有符號(hào)的補(bǔ)符號(hào)位**,無(wú)符號(hào)的補(bǔ)0;相當(dāng)于除以2。
2、反碼與補(bǔ)碼? **反碼:**正數(shù)的反碼為原碼本身,負(fù)數(shù)反碼符號(hào)位不變,剩余的數(shù)字位取反;
? **補(bǔ)碼:**正數(shù)的補(bǔ)碼為原碼本身,負(fù)數(shù)的補(bǔ)碼為反碼+1 。
三、隱式類型轉(zhuǎn)換? 隱式類型轉(zhuǎn)換的原因:參與計(jì)算的數(shù)據(jù)如果類型不同無(wú)法直接進(jìn)行計(jì)算。
? 整型提升:有符號(hào)的補(bǔ)符號(hào)位,無(wú)符號(hào)的補(bǔ)0(符號(hào)位為最外面的那位)
? 樣例:
? 例題,求循環(huán)次數(shù)
? 解答:
? unsigned char 8位數(shù)據(jù)位,范圍在0-255,所以-2(11111110)時(shí),變成254;同理-1(11111111)時(shí),變成255;最后減到0時(shí),不滿足循環(huán)條件,for停止。剛好173次。 (7 4 1 ==>共(7-1)/3+1=3次,1-3=-2,即254,繼續(xù)循環(huán))
254 251 … 5 2 ==>共(254-2)/3+1=85次(2-3=-1,即255,繼續(xù)循環(huán))
255 252 … 6 3 ==>共(255-5)/3+1=85次(3-3=0,退出循環(huán)) 所以總共173次
? 指針變量是個(gè)變量,指針本身是個(gè)地址,用于存放內(nèi)存單元的地址。
? 指針時(shí)用來(lái)存放地址的,指針類型的變量無(wú)論指向目標(biāo)是什么類型,指針本身在32位平臺(tái)所占大小都為4個(gè)字節(jié),在64位平臺(tái)是8個(gè)字節(jié) 。
#includeint main()
{
int a = 10;//在內(nèi)存中開辟一塊空間,左值為空間,右值為內(nèi)容
int *p = &a;//type* p
//這里我們對(duì)變量a,取出它的地址,可以使用&操作符。
//將a的地址存放在p變量中,p就是一個(gè)之指針變量。
return 0;
}
一、指針的解引用? 1、對(duì)指針的解引用只能看到sizeof(type)個(gè)字節(jié)的數(shù)據(jù);
? 2、按字節(jié)為單位,數(shù)據(jù)有高權(quán)值和低權(quán)值之分,地址有低地址和高地址之分;
? 3、數(shù)據(jù)低權(quán)值位在低地址處即為小端存儲(chǔ),反之則為大端存儲(chǔ)。
(“小小小”)
? 指向的位置是不可知的指針。
規(guī)避? 1、指針在定義時(shí)就進(jìn)行初始化;
? 2、避免指針越界(eg:注意循環(huán)時(shí)循環(huán)次數(shù)的限制);
? 3、指針使用完即進(jìn)行指針指向空間釋放;
? 4、避免返回局部變量的地址;
? 5、指針使用前檢查其有效性。
三、指針運(yùn)算? 1、指針±整數(shù),等價(jià)于±sizeof(type);
? 2、指針-指針,兩指針必須同一類型,一般用于數(shù)組與字符串求其兩地址間相隔的單元格數(shù),否則無(wú)效(指針+指針為非法操作);
? 3、指針的關(guān)系運(yùn)算。
? 4、指針和數(shù)組都可以用中括號(hào)或者解引用(二者互通)。
四、字符指針 1、字符指針在指針的類型中我們知道有一種指針類型為字符指針 char* ;
一般使用方法
int main()
{
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}
用char*指針指向字符串
int main()
{
const char* pstr = "hello bit.";
printf("%s\n", pstr);
return 0;
}
//上述代碼中把字符串hello bit.的首地址放入了指針中
需注意字符串可以以字符數(shù)組的形式給出,但是此時(shí)的字符數(shù)組附有存儲(chǔ)功能,而字符指針具有常量屬性,指向的是常量區(qū)的內(nèi)容,因此不可被修改,可以寫作:
const char* str="hello world";//從上圖表示不可被修改
? 也正因?yàn)檫@個(gè)原因 C/C++會(huì)把常量字符串存儲(chǔ)到單獨(dú)的一個(gè)內(nèi)存區(qū)域,當(dāng)幾個(gè)指針指向同一個(gè)字符串的時(shí)候,他們實(shí)際會(huì)指向同一塊內(nèi)存。但是用相同的常量字符串去初始化不同的數(shù)組的時(shí)候就會(huì)開辟出不同的內(nèi)存塊。
#includeint main()
{
char str1[] = "hello world.";
char str2[] = "hello world.";
const char *str3 = "hello world.";
const char *str4 = "hello world.";
if(str1 ==str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if(str3 ==str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
? 在此說一下const的一些知識(shí)點(diǎn):
? ① const修飾的變量不能被直接修改,但是可以通過指針在進(jìn)行類型強(qiáng)轉(zhuǎn)來(lái)修改(只是可以但是完全沒必要);
? ② const修飾指針,表示不可以通過指針來(lái)修改所指目標(biāo);
? ③ const能用則用,會(huì)很好的保護(hù)數(shù)據(jù),
? const的作用:
? ① 寫給編譯器看,提前發(fā)現(xiàn)可能錯(cuò)誤的修改;
? ② 寫給程序員看,提示該變量不建議修改。
const int* p=&a;
*p = 20; //錯(cuò)誤,*p所指的值不可以修改
p = &n;//正確,*p的指向可以修改
int* const q = &m;
*q = 20;//正確,此時(shí)const修飾的是q,此時(shí)q所指向的值可以進(jìn)行修改
q = &t;//錯(cuò)誤,由于const修飾的是q,此時(shí)的q的指向不可以進(jìn)行修改
const int a=10; //若const a=10,編譯器也會(huì)默認(rèn)為a是int類型的
int *P=(int*)&a; //注意需要強(qiáng)制&a前需要加int*類型強(qiáng)制類型轉(zhuǎn)換(&a的原本類型為const int*)
*P=12;
五、指針數(shù)組指針數(shù)組本質(zhì)上是數(shù)組,該類數(shù)組內(nèi)存放的的元素是指針。
int* arr1[10]; //整形指針的數(shù)組
char *arr2[4]; //一級(jí)字符指針的數(shù)組
char **arr3[5];//二級(jí)字符指針的數(shù)組
六、數(shù)組指針
1、數(shù)組指針定義指針數(shù)組本質(zhì)上是指針,該類指針指向的是一個(gè)數(shù)組。
example:
int (*p)[10];
//解釋:p先和*結(jié)合,說明p是一個(gè)指針變量,然后指著指向的是一個(gè)大小為10個(gè)整型的數(shù)組。所以p是一個(gè)
指針,指向一個(gè)數(shù)組,叫數(shù)組指針
2、數(shù)組指針&數(shù)組首先需要看的是數(shù)組名與&數(shù)組名(可以等價(jià)于數(shù)組指針)之間的關(guān)系
#includeint main()
{
int arr[10] = { 0 };
printf("arr = %p\n", arr);
printf("&arr= %p\n", &arr);
printf("arr+1 = %p\n", arr+1);
printf("&arr+1= %p\n", &arr+1);
return 0;
}
根據(jù)上面的代碼我們發(fā)現(xiàn),其實(shí)&arr和arr,雖然值是一樣的,但是意義應(yīng)該不一樣的。實(shí)際上: &arr 表示的是數(shù)組的地址,而不是數(shù)組首元素的地址。(細(xì)細(xì)體會(huì)一下)本例中 &arr 的類型是: int(*)[10] ,是一種數(shù)組指針類型數(shù)組的地址+1,跳過整個(gè)數(shù)組的大小,所以 &arr+1 相對(duì)于 &arr 的差值是40
七、數(shù)組傳參,指針傳參 1、一維數(shù)組傳參數(shù)組傳參會(huì)發(fā)生降維,最終傳入的是首元素的地址(指針),并利用此來(lái)訪問數(shù)組內(nèi)其他元素。
#includevoid test(int arr[])//ok
{}
void test(int arr[10])//ok
{}
void test(int *arr)//ok
{}
void test2(int *arr[20])//不ok
{}
void test2(int **arr)//不ok
{}
int main()
{
int arr[10] = {0};
int *arr2[20] = {0};
test(arr);
test2(arr2);
}
2、二維數(shù)組傳參二維數(shù)組傳參,函數(shù)形參的設(shè)計(jì)只能省略第一個(gè)[]的數(shù)字。
因?yàn)閷?duì)一個(gè)二維數(shù)組,可以不知道有多少行,但是必須知道一行多少元素。
void test(int arr[3][5])//ok
{}
void test(int arr[][])//不ok
{}
void test(int arr[][5])//ok
{}
void test(int *arr)//不ok
{}
void test(int (*arr)[5])//ok
{}
void test(int* arr[5])//不ok
{}
void test(int **arr)//ok
{}
int main()
{
int arr[3][5] = {0};
test(arr);
}
3、一級(jí)指針傳參需要傳入一個(gè)地址
#includevoid print(int *p, int size)
{
int i = 0;
for(i=0; i
4、二級(jí)指針傳參#includevoid test(int** ptr)
{
printf("num = %d\n", **ptr);
}
int main()
{
int n = 10;
int*p = &n;
int **pp = &p;
test(pp);
test(&p);
return 0;
}
八、函數(shù)指針1、函數(shù)指針定義
? 函數(shù)指針是指指向函數(shù)而非指向?qū)ο蟮闹羔槨O衿渌羔樢粯?,函?shù)指針也指向某個(gè)特定的類型(特定的函數(shù)類型)。函數(shù)類型由其返回類型以及形參表確定,而與函數(shù)名無(wú)關(guān) 。
? 代碼在電腦中同樣占據(jù)內(nèi)存空間,所以具有存儲(chǔ)地址,而代碼部分在電腦中也是不可被修改的類似字符串常量。
? 在函數(shù)中,函數(shù)名單獨(dú)時(shí)即為函數(shù)的地址(eg:main=&main),所以在用指針調(diào)用函數(shù)時(shí),可以直接用指針調(diào)用不需要加*
Type (*pFunc)(datatype args);
//pFunc為函數(shù)指針,Type為數(shù)據(jù)類型,參數(shù)(datatype args)可以有多個(gè),也可以沒有。
使用示例
bool max(int a, int b)
{
if (a>b)
{
return a;
}else{
return b;
}
}
void Test()
{
bool (*pFunc)(int, double);
pFunc = max;
cout<< max(5, 10)<< endl;
}
九、函數(shù)指針數(shù)組指針指向一個(gè)數(shù)組 ,數(shù)組的元素都是函數(shù)指針
使用方法: 把幾個(gè)相同類型的函數(shù)地址放到一個(gè)數(shù)組中,這個(gè)數(shù)組就是函數(shù)指針的數(shù)組。
十、回調(diào)函數(shù)解釋:調(diào)用庫(kù)中函數(shù),但是庫(kù)中函數(shù)需要編寫程序時(shí)編寫一個(gè)調(diào)用函數(shù),該庫(kù)中的函數(shù)為回調(diào)函數(shù)。也就是說一個(gè)通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù),當(dāng)這個(gè)指針被用來(lái)調(diào)用其所指向的函數(shù)時(shí),我們就說這是回調(diào)函數(shù)。
? 回調(diào)函數(shù)必須在中間函數(shù)以及回調(diào)函數(shù)同時(shí)具備時(shí)才可以實(shí)現(xiàn)。
作者:no.body
鏈接:https://www.zhihu.com/question/19801131/answer/27459821
來(lái)源:知乎
//大佬在這個(gè)帖子里對(duì)于概念解釋的很好,可以做參考!
回調(diào)函數(shù)就是回調(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時(shí)由另外的一方調(diào)用的,用于對(duì)該事件或條件進(jìn)行響應(yīng)。
結(jié)構(gòu)體 1、基本定義? **注:**①結(jié)構(gòu)體不可以自引用!但可以在結(jié)構(gòu)體內(nèi)定義該結(jié)構(gòu)體類型的指針!
? ②定義結(jié)構(gòu)體本質(zhì)是新增一種類型;
? ③結(jié)構(gòu)體傳參要傳結(jié)構(gòu)體地址(指針),以此提高效率。
struct node1{
int a;
int b;
};
typedef struct node2 {
int c;
int d;
}node2;//通過typedef為結(jié)構(gòu)體變量定義一個(gè)別名node2,在以后使用中可以使用別名以此提高編寫效率
int main(){
struct node1 s;//用結(jié)構(gòu)體定義變量
node2 q;//用別名定義變量
}
? **注:**結(jié)構(gòu)體不可以自引用!但可以在結(jié)構(gòu)體內(nèi)定義該結(jié)構(gòu)體類型的指針!
struct Node
{
int data;
struct Node next;
};//錯(cuò)誤
struct Node
{
int data;
struct Node* next;
};//正確
typedef struct Node
{
int data;
struct Node* next;
}Node;//正確
2、結(jié)構(gòu)體變量的定義和初始化struct Point1
{
int x;
int y;
}p1; //聲明類型的同時(shí)定義變量p1
struct Point p2; //定義結(jié)構(gòu)體變量p2
typedef struct Point2
{
int x;
int y;
}p;
p p1;
p p2;
在定義結(jié)構(gòu)體變量時(shí),可以在初始化的部分定義其內(nèi)容,也可以在之后定義。
typedef struct Point2
{
int x;
int y;
}p;
p p1;
p1.x=1;
p1.y=2;//可以直接用結(jié)構(gòu)體類型的變量進(jìn)行定義
typedef struct Point2
{
int x;
int y;
}p;
p* p2=(p*)malloc(sizeof(p));
p2->x=1;
p2->y=2;//定義一個(gè)指向結(jié)構(gòu)體的指針并為其分配空間即可進(jìn)行定義
3、結(jié)構(gòu)體的內(nèi)存對(duì)齊(結(jié)構(gòu)體的占用大小的計(jì)算)結(jié)構(gòu)體內(nèi)存空間占用的大小并不是單純的元素相加,而是通過浪費(fèi)一定量的空間來(lái)?yè)Q取目標(biāo)數(shù)據(jù)讀取速度的加快
計(jì)算方式:
① 第一個(gè)成員在與結(jié)構(gòu)體變量偏移量為0的地址處。
② 其他成員變量要對(duì)齊到某個(gè)數(shù)字(對(duì)齊數(shù))的整數(shù)倍的地址處。
? (起始偏移量要能整除該成員的對(duì)齊數(shù))
對(duì)齊數(shù) = 編譯器默認(rèn)的一個(gè)對(duì)齊數(shù) 與 該成員大小的較小值。? VS中默認(rèn)的值為8
③ 結(jié)構(gòu)體總大小為大對(duì)齊數(shù)(每個(gè)成員變量都有一個(gè)對(duì)齊數(shù))的整數(shù)倍。
④ 如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的大對(duì)齊數(shù)的整數(shù)倍處(即結(jié)構(gòu)體大?。Y(jié)構(gòu)體的整
體大小就是所有大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍。
樣例:
struct S1
{
char a;
int b;
char C;
};
printf("%d\n", sizeof(struct S1));
char 為1個(gè)字節(jié), int 為4個(gè)字節(jié);
char a 從0偏移開始,占用一個(gè)字節(jié);偏移量為1,接下來(lái)存放 int b,偏移量1不是對(duì)齊數(shù)4 的整數(shù)倍,所以向后繼續(xù)偏移一直到4,4是對(duì)齊數(shù)4的整數(shù)倍,所以將int b存放在偏移地址為4處,占用4個(gè)字節(jié);偏移量變?yōu)?,存放 char c ,占一個(gè)字節(jié),偏移量9不是大對(duì)齊數(shù)4的整數(shù)倍,所以向后繼續(xù)偏移直到偏移處為12的地方。
圖示如下:
自主設(shè)置默認(rèn)對(duì)齊數(shù)
#pragma pack(a)//通過該指令可設(shè)置默認(rèn)對(duì)齊數(shù)為a
位斷位段的聲明和結(jié)構(gòu)是類似的,有兩個(gè)不同:
1.位段的成員必須是 int、unsigned int 、signed int或者char(同屬于整型家族);
2.位段的成員名后邊有一個(gè)冒號(hào)和一個(gè)數(shù)字。
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
注: ① 位段的成員可以是 int unsigned int signed int 或者是 char (屬于整形家族)類型;
② 位段的空間上是按照需要以4個(gè)字節(jié)( int )或者1個(gè)字節(jié)( char )的方式來(lái)開辟的;
③ 位段涉及很多不確定因素,位段是不跨平臺(tái)的,注重可移植的程序應(yīng)該避免使用位段;
④位斷不需要考慮內(nèi)存對(duì)齊問題所以較為節(jié)省空間。
總而言之, 跟結(jié)構(gòu)相比,位段可以達(dá)到同樣的效果,但是可以很好的節(jié)省空間,但是有跨平臺(tái)的問題存在。
枚舉即一一列舉
enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun //最后一個(gè)不加逗號(hào)
};
enum Sex//性別
{
MALE,
FEMALE,
SECRET
};
與宏定義相比枚舉的優(yōu)點(diǎn):
① 增加代碼的可讀性和可維護(hù)性;
② 和#define定義的標(biāo)識(shí)符比較枚舉有類型檢查,更加嚴(yán)謹(jǐn);
③ 防止了命名污染(封裝);
④ 便于調(diào)試;
⑤ 使用方便,一次可以定義多個(gè)常量 。
聯(lián)合也是一種特殊的自定義類型
這種類型定義的變量也包含一系列的成員,特征是這些成員公用同一塊空間(所以聯(lián)合也叫共用體), 聯(lián)合的成員是共用同一塊內(nèi)存空間的,這樣一個(gè)聯(lián)合變量的大小,至少是大成員的大小(因?yàn)槁?lián)合至少得有能力保存大的那個(gè)成員)。
//聯(lián)合類型的聲明
union Un
{
char c;
int i;
};
//聯(lián)合變量的定義
union Un un;
**注:**聯(lián)合體需要考慮內(nèi)存對(duì)齊,要求為大內(nèi)存數(shù)的整數(shù)倍。
動(dòng)態(tài)內(nèi)存管理? 程序開始運(yùn)行后在堆上開辟大量空間(數(shù)組之類的空間開辟在棧上進(jìn)行),而在堆上開辟的空間使用完畢后需要在使用完成后由free函數(shù)進(jìn)行釋放,然后令指向該空間的指針指空,如果只申請(qǐng)不釋放會(huì)造成內(nèi)存泄漏問題。
動(dòng)態(tài)申請(qǐng)空間主要涉及三個(gè)函數(shù):malloc函數(shù),calloc函數(shù),relloc函數(shù)。
void* malloc (size_t size);
? 只申請(qǐng)空間,不對(duì)空間進(jìn)行初始化,傳入的參數(shù)size為要開辟的空間大小;
void* calloc (size_t num, size_t size);
? 申請(qǐng)空間,與malloc唯一的不同之處在于calloc會(huì)初始化為0,傳入的參數(shù)size為單個(gè)空間的大小,參數(shù)a為所需要的單個(gè)空間的數(shù)量;
void* realloc (void* ptr, size_t size);
將分配size個(gè)大小的空間,然后在調(diào)整原內(nèi)存空間大小的基礎(chǔ)上,將原來(lái)內(nèi)存中的數(shù)據(jù)移動(dòng)到新的空間,返回值為調(diào)整之后的內(nèi)存起始位置。
由于realloc可能會(huì)申請(qǐng)失敗返回NULL所以不建議直接用原指針接收返回地址,正確使用方法為:
int* ptr = (int*)malloc(100);
int* p = NULL;
p = realloc(ptr, 1000);
if (p = !NULL) {
ptr = p;
}
內(nèi)存釋放操作
int* p=(int*)malloc(100);
......
free(p);
p = NULL;
柔性數(shù)組
1、定義? 在結(jié)構(gòu)體內(nèi)大小為0(a[0])或空(a[])的數(shù)組(必須為結(jié)構(gòu)體內(nèi)最后一個(gè)元素且不能是唯一元素)
這樣可以在結(jié)構(gòu)體內(nèi)具有一個(gè)變長(zhǎng)數(shù)組包含柔性數(shù)組成員的結(jié)構(gòu)用malloc ()函數(shù)進(jìn)行內(nèi)存的動(dòng)態(tài)分配,并且分配
的內(nèi)存應(yīng)該大于結(jié)構(gòu)的大小,以適應(yīng)柔性數(shù)組的預(yù)期大小 ,sizeof 返回的這種結(jié)構(gòu)大小不包括柔性數(shù)組的內(nèi)存 。
2、使用方法typedef struct st_type
{
int i;
int a[0];//柔性數(shù)組成員
}type_a;
printf("%d\n", sizeof(type_a));//輸出的是4
//初始化
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
p->i = 100;
for(i=0; i<100; i++)
{
p->a[i] = i;
}
free(p);
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
新聞標(biāo)題:C語(yǔ)言知識(shí)點(diǎn)匯總-創(chuàng)新互聯(lián)
網(wǎng)頁(yè)鏈接:http://www.rwnh.cn/article36/csjppg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營(yíng)銷推廣、網(wǎng)站制作、動(dòng)態(tài)網(wǎng)站、網(wǎng)站排名、網(wǎng)站建設(shè)、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容