拖更了一周,今天終于有時間寫博客了。
大家好,我是十一,今天帶大家來學(xué)習(xí)C語言中的指針。
指針初階每日一圖:
指針理解的2個要點:
在學(xué)習(xí)指針之前我們需要先了解內(nèi)存:
內(nèi)存——電腦上的存儲設(shè)備。
程序運行的時候會加載到內(nèi)存中,也會使用內(nèi)存空間。
內(nèi)存是如何編號的?
對于32位的機器,假設(shè)有32根地址線,那么假設(shè)每根地址線在尋址的時候產(chǎn)生高電平(高電壓)和低電
平(低電壓)就是(1或者0)
這里一共可以產(chǎn)生2的32次方個地址。每個地址標(biāo)識1個字節(jié),那么一共就有2的32次方個字節(jié)。
也就是:4,294,967,296個字節(jié)——4,194,304KB——4,096MB——4GB的空間進(jìn)行編址。
同樣的方法,那64位機器,假設(shè)就有64根地址線。
在32位的機器上,地址是32個0或者1組成二進(jìn)制序列,那地址就得用4個字節(jié)的空間來存儲,所以一個指針變量的大小就應(yīng)該是4個字節(jié)。
如果在64位機器上,如果有64個地址線,那一個指針變量的大小是8個字節(jié),才能存放一個地址。
總結(jié):
我們都知道,變量有不同的類型,整形,浮點型等。那指針有沒有類型呢?
準(zhǔn)確的說:有的。
char* pc = NULL;
int* pi = NULL;
short* ps = NULL;
long* pl = NULL;
float* pf = NULL;
double* pd = NULL;
指針類型的作用:
2.1指針±整數(shù)指針類型其實是有意義的
指針類型決定了,指針進(jìn)行解引用操作的時候,一次性訪問幾個字節(jié)。(訪問權(quán)限的大?。?br />我們可以根據(jù)需要訪問的字節(jié)大小來選擇指針的類型。
如果我們對指針進(jìn)行±操作:
可以看到char*(字符) 指針+1跳過了1個字節(jié),int*(整形) 指針+1則跳過4個字節(jié)。
總結(jié):
野指針的概念: 野指針就是指針指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)
3.1野指針成因1. 指針未初始化
如下:
int main()
{int* p;
*p = 20;
return 0;
}
這里的局部變量指針(p)未初始化,默認(rèn)會為隨機值。
當(dāng)這個隨機值放到指針變量里,編譯器就會把這個隨機值當(dāng)成一個地址。
當(dāng)我們解引用找到這個空間,把20放進(jìn)去這個操作會非常的危險。
所以我們在使用指針的時候,指針必須有一個明確的指向
2. 指針訪問越界
如下:
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
int i = 0;
for (i = 0; i<= 10; i++)
{printf("%d ", *p);
p++;
}
return 0;
}
這樣的代碼就會出現(xiàn)指針的越界訪問。當(dāng)他第十次循環(huán)的時候這個指針就是一個野指針。
當(dāng)這個指針指向的空間不再合理的時候,這個指針其實就是有問題的。
運行效果:
3. 指針指向的空間釋放
如下:
int* test()
{int a = 10;
return &a;
}
int main()
{int* p = tese();
printf("%d\n", *p);
return 0;
}
我們看這個代碼,假設(shè)我們"a"的地址是:0X0012FF40,當(dāng)我們調(diào)用完test函數(shù)的時候,test函數(shù)返回了"a"的地址放到了"p"變量里,雖然"a"的地址放到了"p"變量里,但是test函數(shù)已經(jīng)調(diào)用完畢,"a"的空間就已經(jīng)被銷毀了,但是我們"p"變量里還存著"a"的地址,這時候這個指針就已經(jīng)是一個野指針了。
運行效果:
雖然我們這里打印出來的結(jié)果還是10,這只是僥幸,恰好這塊空間的數(shù)據(jù)沒有被修改,沒有被覆蓋掉,但是并不代表這句代碼就是對的。
我們稍微修改一下:
int* test()
{int a = 10;
return &a;
}
int main()
{int* p = test();
printf("十一\n");
printf("%d\n", *p);
return 0;
}
運行效果:
可以看到,這里打印出來的結(jié)果就不是10了。
#define N_VALUES 5
float values[N_VALUES];
float* vp;
//指針+-整數(shù);指針的關(guān)系運算
for (vp = &values[0]; vp< &values[N_VALUES];)
{*vp++ = 0;
}
我們來看這句代碼:*vp++ = 0;
注意:這里的vp++是后置++,所以是先使用在進(jìn)行++,那么這句代碼就可以理解為:
*vp = 0;
vp++;
先把數(shù)組的值改為0,vp在進(jìn)行++。
4.2指針-指針這個運算的運算條件是:兩個指針要指向同一塊空間。
我們來看這段代碼:
int main()
{int arr[10] = {0 };
printf("%d\n", &arr[9] - &arr[0]);
return 0;
}
運行效果:
這里為什么會得9呢?
其實指針-指針得到的是兩個指針之間的元素個數(shù),所以這里打印的結(jié)果就是:9
如果我們把兩個地址換一下:
int main()
{int arr[10] = {0 };
printf("%d\n", &arr[0] - &arr[9]);
return 0;
}
運行效果:
這里得到的結(jié)果就是-9。
注意:兩個指針的類型必須一致。
指針和數(shù)組是不同的對象,指針是一種變量,存放地址的,大小為4或8字節(jié)。
數(shù)組是一種相同類型元素的集合,是可以放多個元素的,大小是取決于元素個數(shù)和元素的類型的。
數(shù)組的數(shù)組名是數(shù)組首元素的地址,地址是可以放在指針變量中,可以通過指針訪問數(shù)組
比如:
int main()
{int arr[10] = {0 };
int* p = arr;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
//賦值
for (i = 0; i< sz; i++)
{*(p + i) = i + 1;
}
//打印
for (i = 0; i< sz; i++)
{printf("%d ", *(p+i));
}
return 0;
}
運行效果:
二級指針:
int main()
{int a = 10;
int* pa = &a;
int** ppa = &pa;//ppa就是一個二級指針變量
return 0;
}
我們對二級指針解引用2次就可以找到a變量。
int main()
{int a = 10;
int* pa = &a;
int** ppa = &pa;//ppa就是一個二級指針變量
printf("%d\n", **ppa);
**ppa = 20;
printf("%d\n", a);
return 0;
}
運行效果:
指針數(shù)組是指針還是數(shù)組?
答案:是數(shù)組。是存放指針的數(shù)組。
我們知道字符數(shù)組是存放字符的數(shù)組,整形數(shù)組是存放整形的數(shù)組。
那么指針數(shù)組是怎樣的?
其實指針數(shù)組就是存放指針的數(shù)組。
如下:
int main()
{int a = 10;
int b = 20;
int c = 30;
int d = 40;
int e = 50;
int* arr[5] = {&a,&b,&c,&d,&e };//指針數(shù)組
//打印數(shù)組
int i = 0;
for (i = 0; i< 5; i++)
{printf("%d ", *(arr[i]));
}
return 0;
}
運行效果:
//模擬一個3行4列的數(shù)組
int main()
{int a[] = {1,4,7,10 };
int b[] = {2,5,8,11 };
int c[] = {3,6,9,12 };
int* arr[3] = {a,b,c };//指針數(shù)組
int i = 0;
for (i = 0; i< 3; i++)//行
{int j = 0;
for (j = 0; j< 4; j++)//列
{ printf("%d ", arr[i][j]);
}
printf("\n");//打印完一行后換行
}
return 0;
}
運行效果:
以上就是本文的全部內(nèi)容了,希望大家看完能有所收獲。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧