C語(yǔ)言中的指針 初階
1.指針是什么
初學(xué)者都有一個(gè)疑問(wèn),那就是指針是什么?簡(jiǎn)單的說(shuō),就是通過(guò)它能找到以它為地址的內(nèi)存單元。
地址指向了一個(gè)確定的內(nèi)存空間,所以地址形象的被稱(chēng)為指針。
int main()
{
int a = 10;
int* pa = &a;
return 0;
}
//pa是用來(lái)存放地址(指針),所以pa是指針變量。
總結(jié):指針就是變量,用來(lái)存放地址的變量。(存放在指針中的值都被當(dāng)成地址處理)。
地址是唯一標(biāo)識(shí)一塊空間的。
指針的大小在32位平臺(tái)是4個(gè)字節(jié),在64位平臺(tái)是8個(gè)字節(jié)。
2.指針和指針類(lèi)型
我們知道變量有不同的類(lèi)型(整型、浮點(diǎn)型、字符型等),其實(shí)指針也是有不同類(lèi)型的。
指針類(lèi)型的意義1:
指針類(lèi)型決定了指針解引用操作的時(shí)候,一次訪問(wèn)幾個(gè)字節(jié)(訪問(wèn)內(nèi)存的大?。?br />
char* 指針解引用訪問(wèn)1個(gè)字節(jié)
int* 指針解引用訪問(wèn)四個(gè)字節(jié)
int main()
{
char* pc = &a;
*pc = 0;
return 0;
}
指針類(lèi)型的意義2:
指針類(lèi)型決定了,指針±整數(shù)的時(shí)候的步長(zhǎng)(指針±整數(shù)的時(shí)候,跳過(guò)幾個(gè)字節(jié))
int* 指針+1 跳過(guò)四個(gè)字節(jié)
char* 指針+1 跳過(guò)一個(gè)字節(jié)
int main()
{
int a = 10;
int* pa = &a;
char* pc = &a;
printf("%p\n", pa);
printf("%p\n", pc);
printf("%p\n", pa+1);
printf("%p\n", pc+1);
return 0;
}
3.野指針
野指針就是指針指向的位置是不可知的(隨機(jī)的、不正確的、沒(méi)有明確限制的)。
3.1野指針成因
指針未初始化
int main()
{
int* p;//局部變量指針未初始化,默認(rèn)為隨機(jī)值
*p = 20;//通過(guò)p中存的隨機(jī)值作為地址,找到一個(gè)空間,這個(gè)空間不屬于我們當(dāng)前的程序
//就造成了非法訪問(wèn),p就是野指針
return 0;
}
指針越界訪問(wèn)
int main()
{
int arr[10] = 0;
int i = 0;
int* p = arr;
for(i =0; i <= 10; i++)
{
*p = i;
p++;//當(dāng)指針指向的范圍超出數(shù)組arr的范圍時(shí),p就是野指針
}
return 0;
}
指針指向的空間釋放
int* test()
{
int a = 10;
return &a;
}
int main()
{
int* p = test();
printf("%d\n",*p);
return 0;
}
3.2如何規(guī)避野指針
- 指針初始化
- 小心指針越界
- 指針指向空間釋放即使置
NULL - 避免返回局部變量的地址
- 指針使用之前檢查有效性
int main()
{
int a = 10;
int* p = &a;//明確地初始化,確定指向
int* p2 = NULL;//不知道一個(gè)指針當(dāng)前應(yīng)該指向哪里時(shí),可以初始化為NULL
return 0;
}
4.指針的運(yùn)算
4.1指針±整數(shù)
#define N_VALUES 5
float values[N_VALUES];
float* vp;
for(vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int* p = &arr[9];
printf("%p\n",p);
printf("%p\n",p-2);
return 0;
}
4.2指針-指針
指針-指針 得到的數(shù)字的絕對(duì)值是指針和指針之間元素的個(gè)數(shù)
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
printf("%d\n", &arr[9] - &arr[0]);
printf("%d\n", &arr[0] - &arr[9]);
return 0;
}
指針-指針 的前提是兩個(gè)指針指向同一塊區(qū)域
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
char ch[5] = {0};
printf("%d\n",&arr[9] - &ch[0]);//err
return 0;
}
應(yīng)用 求字符串長(zhǎng)度
int my_strlen(char* s)
{
int count = 0;
char* start = s;
while(*s!='\0')
{
s++;
}
return s - start;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
4.3指針的關(guān)系運(yùn)算
#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}
上述程序也可以寫(xiě)成這樣
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0;
}
實(shí)際在絕大部分的編譯器上是可以順利完成任務(wù)的,然而我們還是應(yīng)該避免這么寫(xiě),因?yàn)闃?biāo)準(zhǔn)并不保證它可行。
標(biāo)準(zhǔn)規(guī)定
允許指向數(shù)組元素的指針與指向數(shù)組最后一個(gè)元素后面的那個(gè)內(nèi)存位置的指針比較,但是不允許與指向第一個(gè)元素之前的那個(gè)內(nèi)存位置的指針進(jìn)行比較。
5.指針和數(shù)組
數(shù)組 - 是一塊連續(xù)的空間,放的是相同類(lèi)型的元素
數(shù)組大小和元素類(lèi)型,元素個(gè)數(shù)有關(guān)系
指針(變量) - 是一個(gè)變量,放地址
指針變量的大小 是4(32bit)/8(64bit)個(gè)byte
數(shù)組名確實(shí)是首元素地址
但是有兩個(gè)例外:
- sizeof(數(shù)組名) - 這里的數(shù)組名不是首元素的地址,是表示整個(gè)數(shù)組的,這里計(jì)算的是整個(gè)數(shù)組的大小,單位還是字節(jié)。
- &數(shù)組名 - 這里的數(shù)組名不是首元素的地址,是表示整個(gè)數(shù)組的,拿到的是整個(gè)數(shù)組的地址
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr);
printf("%d\n", sz);
return 0;
}
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;
}
for (i = 0;i < sz;i++)
{
printf("%d ", *(p + i));
}
return 0;
}
6.二級(jí)指針
我們都知道,指針變量是變量,是變量就有地址,那么指針變量的地址存放在哪里呢?
這就是我們要了解的二級(jí)指針。
int main()
{
int a = 10;
int* p = &a;
int** pp = &p;//pp就是二級(jí)指針
**pp = 20;
printf("%d\n", a);//a = 20
return 0;
}
7.指針數(shù)組
從名字上來(lái)看,大家覺(jué)得指針數(shù)組是指針還是數(shù)組?
答案是數(shù)組,是存放指針的數(shù)組。
整型數(shù)組 - 存放整型的數(shù)組就是整型數(shù)組
字符數(shù)組 - 存放字符的數(shù)組就是字符數(shù)組
指針數(shù)組 - 存放指針的數(shù)組就是指針數(shù)組
int* 整型指針的數(shù)組
char* 字符指針的數(shù)組
int main()
{
int arr[10];
char ch[5];
int* parr[5];
char* pc[6];
return 0;
}
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* parr[3] = { &a,&b,&c };
for (int i = 0;i < 3;i++)
{
printf("%d\n", *(parr[i]));
}
return 0;
}
到此這篇關(guān)于C語(yǔ)言中的指針 初階的文章就介紹到這了,更多相關(guān)C語(yǔ)言中的指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)繪制立體餅圖的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何使用C語(yǔ)言實(shí)現(xiàn)繪制立體餅圖,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
C++數(shù)據(jù)結(jié)構(gòu)之單鏈表
這篇文章主要介紹了C++數(shù)據(jù)結(jié)構(gòu)之單鏈表,鏈表是由一個(gè)個(gè)結(jié)點(diǎn)鏈結(jié)成的。結(jié)點(diǎn)包括數(shù)據(jù)域和指針域兩部分,數(shù)據(jù)域用來(lái)存儲(chǔ)數(shù)據(jù)元素的信息,指針域用來(lái)存儲(chǔ)下一個(gè)結(jié)點(diǎn)的地址,更詳細(xì)內(nèi)容請(qǐng)需要的小伙伴參考下面文章內(nèi)容2022-01-01
詳解C++中的四種類(lèi)型轉(zhuǎn)換運(yùn)算符
隱式類(lèi)型轉(zhuǎn)換是安全的,顯式類(lèi)型轉(zhuǎn)換是有風(fēng)險(xiǎn)的,C語(yǔ)言之所以增加強(qiáng)制類(lèi)型轉(zhuǎn)換的語(yǔ)法,就是為了強(qiáng)調(diào)風(fēng)險(xiǎn),讓程序員意識(shí)到自己在做什么,本文將給大家詳細(xì)介紹一下C++中的四種類(lèi)型轉(zhuǎn)換運(yùn)算符,需要的朋友可以參考下2023-09-09
matlab遺傳算法求解車(chē)間調(diào)度問(wèn)題分析及實(shí)現(xiàn)源碼
這篇文章主要為大家介紹了matlab遺傳算法求解車(chē)間調(diào)度問(wèn)題解析,文中附含詳細(xì)實(shí)現(xiàn)源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-02-02
c++如何在主函數(shù)文件中調(diào)用其他函數(shù)文件
這篇文章主要介紹了c++如何在主函數(shù)文件中調(diào)用其他函數(shù)文件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
詳解c++11以正確的姿勢(shì)輸出enum class的值
這篇文章主要介紹了詳解c++11以正確的姿勢(shì)輸出enum class的值,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10

