修仙之指針初階-創(chuàng)新互聯(lián)

1.指針是什么?
引言:變量的內(nèi)存地址:先前我們了解到,C程序中變量的值都是存儲(chǔ)在計(jì)算機(jī)內(nèi)存中特定的存儲(chǔ)單元中。而內(nèi)存中的每個(gè)單元都有唯一的地址。
1.1理解指針是什么?🔻
1.指針是內(nèi)存中一個(gè)最小的單元編號(hào),也就是地址。
2.口語(yǔ)中的指針,指的是指針變量,是用來(lái)存放變量的地址。

我們可以進(jìn)一步將指針理解為“內(nèi)存”

創(chuàng)新互聯(lián)從2013年成立,先為道外等服務(wù)建站,道外等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為道外企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

圖片描述

1.2指針變量😁
如何獲得變量的地址呢?通過(guò)&(取地址操作符)取出變量的其實(shí)地址,然后放在一個(gè)變量中,這個(gè)變量就是指針變量。 通過(guò)指針變量間接存取它指向的變量的訪問(wèn)方式稱(chēng)為間接尋址。
#includeint main()
{
    int a = 5;//在內(nèi)存中開(kāi)辟一塊空間
    int* pa = &a;//取出變量a的地址,存放到pa這個(gè)變量中。pa就是指針變量。
    printf("%p\n",&a);//需要用到取地址操作符
    printf("%p\n", pa);
? ? //打印地址格式用%p,表示輸出變量的地址值
? ? //地址值時(shí)用一個(gè)十六進(jìn)制(以16為基數(shù))的無(wú)符號(hào)整數(shù)表示。
    return 0;
}

圖片描述

//如何定義兩個(gè)相同基類(lèi)型的指針變量呢?
int*pa,*pb;
//注意不可以用int*pa,pb。這表示定義了可以指向整型數(shù)據(jù)的指針變量pa和整型變量pb。

總結(jié):?

1. 指針變量--->用來(lái)存放地址的變量。(存放在指針中的值都被當(dāng)成地址來(lái)處理)
2.那么最小的一個(gè)單元有多大呢?---- 一個(gè)字節(jié)
3.深刻剖析內(nèi)存單元如何進(jìn)行編址?
經(jīng)過(guò)仔細(xì)的計(jì)算和權(quán)衡我們發(fā)現(xiàn)一個(gè)字節(jié)給一個(gè)對(duì)應(yīng)的地址是比較合適的。
對(duì)于32位的機(jī)器,假設(shè)有32根地址線,那么假設(shè)每根地址線在尋址的時(shí)候產(chǎn)生高電平(高電壓)和低電
平(低電壓)就是(1或者0);
那么32根地址線產(chǎn)生的地址就會(huì)是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
...
11111111 11111111 11111111 11111111
這里就有2的32次方個(gè)地址。
每個(gè)地址標(biāo)識(shí)一個(gè)字節(jié),那我們就可以給 (2^32Byte == 2^32/1024KB ==
2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB) 4G的空閑進(jìn)行編址。
同樣的方法,那64位機(jī)器,如果給64根地址線,那能編址多大空間,自己計(jì)算。
也就是說(shuō):
1.在32位的機(jī)器上,地址是32個(gè)0或者1組成二進(jìn)制序列,那地址就得用4個(gè)字節(jié)的空間來(lái)存儲(chǔ),所以
一個(gè)指針變量的大小就應(yīng)該是4個(gè)字節(jié)。
2.那如果在64位機(jī)器上,如果有64個(gè)地址線,那一個(gè)指針變量的大小是8個(gè)字節(jié),才能存放一個(gè)地

總結(jié):?

1.指針是用來(lái)存放地址的,地址是唯一標(biāo)識(shí)一塊地址空間的。
2.在32位平臺(tái)上,指針的大小占4個(gè)字節(jié);在64位平臺(tái)上,指針的大小占8個(gè)字節(jié)。
接下來(lái)我們觀察一下指針變量在內(nèi)存中的存儲(chǔ)情況
int main()
{
    int num = 0;//地址編號(hào)為:0x00effcf0,存放的值為00000000
    int* pa = #//地址編號(hào)為:0x00EFFCE4,存放的值為0x00effcf0
    char* pc = (char*)#//地址編號(hào)為:0x00EFFCD8,存放的值為0x00effcf0
    return 0;
}

注意:

本例第5行:指針變量只能指向同一基類(lèi)型的變量,否則會(huì)引起warning。所以本例使用了強(qiáng)制類(lèi)型轉(zhuǎn)換。

通過(guò)上述代碼和圖片解釋?zhuān)覀儼l(fā)現(xiàn):
指向某變量的指針變量,雖然指針變量中存放的是變量的地址值,二者在數(shù)值上相等,但在概念上變量的指針并不等同于變量的地址。變量的地址是一個(gè)常量,不能對(duì)其進(jìn)行賦值。而變量的指針是一個(gè)變量,其值是可以改變的。

🌜2.指針和指針類(lèi)型🌛

我們都知道,變量有不同的類(lèi)型,如整型、浮點(diǎn)型等等。那么指針也有對(duì)應(yīng)的指針類(lèi)型。

int num=10;
int* p=#//pa是一個(gè)指針變量,它指向一個(gè)整型變量
變量p是一個(gè)指針變量,用來(lái)存放num的地址。因?yàn)閚um的類(lèi)型是整型,那么指針存放的數(shù)據(jù)類(lèi)型是整型,對(duì)應(yīng)p是一個(gè)整型指針,同時(shí)需要在int和p之間加一個(gè)*確保它是一個(gè)指針變量。
2.1指針類(lèi)型:
指針類(lèi)型定義的方式:類(lèi)型關(guān)鍵字+*+指針變量名
char* p=NULL;(存放char類(lèi)型變量的地址)
short* p=NULL;(存放short類(lèi)型變量的地址)
long* p=NULL;(存放long類(lèi)型變量的地址)
int* p=NULL;(存放int類(lèi)型變量的地址)
float* p=NULL;(存放float類(lèi)型變量的地址)
double* p=NULL;(存放double類(lèi)型變量的地址)
介紹一下 指針運(yùn)算符, 也稱(chēng) 間接尋址運(yùn)算符 或 解引用運(yùn)算符:(*)間接尋址運(yùn)算符*用來(lái)訪問(wèn)指針變量指向變量的值。 運(yùn)算時(shí),要求指針已經(jīng)被正確初始化或者已經(jīng)指向內(nèi)存中某個(gè)確定的存儲(chǔ)單元,防止野指針的出現(xiàn)。
2.2指針+-整數(shù)
int main()
{
    int num = 10;
    int* pn = #
    char* pc = (char*)#
    printf("&num=%p\n", &num);
    printf("pn=%p\n", pn);
    printf("pn+1=%p\n",pn+1);
    printf("pc=%p\n",pc);
    printf("pc+1=%p\n",pc+1);
    return 0;
}

內(nèi)存中的地址是由十六進(jìn)制顯示的:pn是整型指針,pn+1與pn相差4個(gè)字節(jié);而pc是字符型指針,pc+1與pc相差1個(gè)字節(jié)

總結(jié):指針的類(lèi)型決定了指針向前或者向后走一步是多大距離

2.3指針的解引用
int main()
{
    int num = 10;
    int* pn = #
    char* pc = (char*)#
    printf("%d\n", *pn);
    printf("%d\n", *pc);
    return 0;
}

這樣看對(duì)指針的解引用不深刻,我們換一種方法:

int main()
{
    int n = 0x11223344;
    char* pc = (char*)&n;
    int* pn = &n;
    *pc = 0; //重點(diǎn)在調(diào)試的過(guò)程中觀察內(nèi)存的變化。
    *pn = 0; //重點(diǎn)在調(diào)試的過(guò)程中觀察內(nèi)存的變化。
    return 0;
}
//接下來(lái)我們通過(guò)調(diào)試觀察在內(nèi)存中的變化
通過(guò)對(duì)pc進(jìn)行解引用操作,按ctrl+F10進(jìn)行逐語(yǔ)句調(diào)試過(guò)程,按F10到25行,再按一次調(diào)試25行代碼跳到26行,可以觀察25行程序運(yùn)行的情況:觀察內(nèi)存變化發(fā)現(xiàn)內(nèi)存由0x11223344變成了0x11223300。*pc對(duì)pc進(jìn)行解引用操作并賦值為0,因?yàn)閜c是Char類(lèi)型指針,訪問(wèn)一個(gè)字節(jié)的內(nèi)存空間,所以將內(nèi)存地址的低位44改成了00。
當(dāng)我們?cè)侔碏10的時(shí)候,語(yǔ)句調(diào)試第26行,跳到27行,觀察第26行程序的運(yùn)行:因?yàn)閜n是整型指針,對(duì)pn解引用操作會(huì)對(duì)內(nèi)存訪問(wèn)四個(gè)字節(jié)的內(nèi)存空間,將*pn賦值為0,也就是將0x11223344變成了0x00000000。

總結(jié):💗

  1. 指針的類(lèi)型決定了指針解引用操作對(duì)內(nèi)存能訪問(wèn)多大的權(quán)限(能操作幾個(gè)字節(jié))

  1. 比如: char* 的指針解引用就只能訪問(wèn)一個(gè)字節(jié),而 int* 的指針的解引用就能訪問(wèn)四個(gè)字節(jié)。

同樣,我們可以通過(guò)解引用修改變量的值,看下面程序運(yùn)行結(jié)果: 📄
int main()
{
    int num = 0;
    int* pa = #//定義指針變量的同時(shí)對(duì)其初始化
    *pa = 20;//修改指針變量pa所指向的變量的值
? ? //引用指針?biāo)赶虻淖兞康闹?,也稱(chēng)為指針的解引用。
    printf("%d\n", num);
    return 0;
}

那么:既然*pa和變量num的值一樣,我們?cè)究梢院苋菀椎膶⒆兞縜的值打印出來(lái),為什么還要舍近求遠(yuǎn)地使用指針變量來(lái)得到a的值呢?通過(guò)”標(biāo)題4展現(xiàn)指針的強(qiáng)大功能“😍

👺3.野指針👺

概念:

?野指針就是指指向的內(nèi)存是不可知的。(隨機(jī)的、不正確的、沒(méi)有明確限制的)

3.1野指針的成因😺 3.1.1指針的未初始化
int main()
{
? ? int*p;//此時(shí)指針變量p指向的內(nèi)存是不可知的
? ? *p=20;//對(duì)指針進(jìn)行解引用修改值可能會(huì)對(duì)內(nèi)存發(fā)生不可逆的影響
? ? return 0;
}
3.1.2指針的越界訪問(wèn)
int main()
{
    int arr[10] = { 0 };
    int* p=&arr;//數(shù)組的第一個(gè)元素的首地址
    int i = 0;
    for (i = 0; i< 11; i++)
    {
        *(p++) = i;//先對(duì)p賦值,后p++(詳看++的運(yùn)算規(guī)則)
? ? ? ? //指針指向的范圍超出了數(shù)組的范圍,此時(shí)p就是野指針
    }
    for (i = 0; i< 10; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}
3.1.3指針指向的空間釋放
與動(dòng)態(tài)內(nèi)存相關(guān)內(nèi)容,后續(xù)發(fā)布文章講解
3.2如何規(guī)避野指針
1.指針初始化
2.防止指針越界的情況發(fā)生
3.指針指向空間釋放即使置NULL
4.避免返回局部變量的指針
5.指針使用之前檢查有效性
int main()
{
    int* p = NULL;
    int num = 10;
    p = #
    if (p != NULL)
    {
        *p = 10;
    }
    printf("%d\n", num);
? ? //10
}
恪守準(zhǔn)則:
1.永遠(yuǎn)清楚每個(gè)指針指向了哪里,指針必須只想一塊有意義的內(nèi)存;
2.永遠(yuǎn)清楚每個(gè)指針指向的對(duì)象的內(nèi)容是什么;
3.永遠(yuǎn)不要使用未初始化的指針變量。
🌜4.指針運(yùn)算🌛 4.1指針+-整數(shù)😇
#define N_VALUES 5
float values[N_VALUES];//浮點(diǎn)型數(shù)組
float* vp;//定義一個(gè)浮點(diǎn)型指針
//指針+-整數(shù);指針的關(guān)系運(yùn)算
int main()
{
    for (vp = &values[0]; vp< &values[N_VALUES];)
    {
        *vp++ = 0;//數(shù)組從下標(biāo)為0的元素開(kāi)始賦值為0;
    }
    return 0;
}
4.2指針-指針😇
//函數(shù)功能:模擬實(shí)現(xiàn)strlen
//函數(shù)形參:字符型指針
//函數(shù)返回值:整型
int my_strlen(char* ch)
{
    char* p = ch;
    //數(shù)組名是數(shù)組首地址
    while (*p!='\0')
    {
        p++;
    }
    return p - ch;
    //指針-指針:實(shí)現(xiàn)指針之間的距離(相差的字節(jié)數(shù))
}
int main()
{
    char ch[20] = { 0 };
    fgets(ch, sizeof(ch), stdin);
    printf("%d\n", my_strlen(ch));
    return 0;
}
4.3指針的關(guān)系運(yùn)算😇
#define N_VALUES 5
float values[N_VALUES];//浮點(diǎn)型數(shù)組
float* vp;//定義一個(gè)浮點(diǎn)型指針
//指針+-整數(shù);指針的關(guān)系運(yùn)算
int main()
{
    for(vp = &values[N_VALUES]; vp >&values[0];)//vp指向下標(biāo)為5的內(nèi)存空間
? ? {
? ? ? ? *--vp = 0;//從下標(biāo)為4的位置開(kāi)始
? ? }
    return 0;
}
當(dāng)我們對(duì)代碼進(jìn)行簡(jiǎn)化時(shí):
#define N_VALUES 5
float values[N_VALUES];//浮點(diǎn)型數(shù)組
float* vp;//定義一個(gè)浮點(diǎn)型指針
//指針+-整數(shù);指針的關(guān)系運(yùn)算
int main()
{? ? 
? ? for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
? ? {
? ? ? ? *vp = 0;
? ? ? ? //當(dāng)vp=&values[0]時(shí),*vp=0,此時(shí)會(huì)進(jìn)行vp--,導(dǎo)致指針指向第一個(gè)元素之前的內(nèi)存空間,應(yīng)避免這樣? ? ? ? ? //的問(wèn)題
? ? }
    return 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)行比較。
4.4按值調(diào)用和模擬按引用調(diào)用 ?引例1?修改實(shí)參的值
void Change(int num)
{
    num = 20;
}
int main()
{
    int num = 10;
    printf("%d\n", num);
    Change(num);
    printf("%d\n", num);
    return 0;
}

程序在函數(shù)Change中改變了num的值,但是再次輸出實(shí)參的值卻發(fā)生沒(méi)有任何變化,說(shuō)明函數(shù)的形參值的改變并未影響到實(shí)參值的改變。這是因?yàn)樾螀⑹菍?shí)參的一份臨時(shí)拷貝,通過(guò)按值調(diào)用不能在被調(diào)函數(shù)中改變其調(diào)用語(yǔ)句中的實(shí)參值。這時(shí)我們就要用到指針這個(gè)秘密武器了。指針變量的一個(gè)重要作用就是用作函數(shù)參數(shù),由于傳給被調(diào)函數(shù)的這個(gè)值不是變量的值,而是變量的地址,通過(guò)向被調(diào)函數(shù)傳遞變量的地址可以在被調(diào)函數(shù)中改變主調(diào)函數(shù)中變量的值,模擬C++中的按引用調(diào)用。

void Change(int* num)
{
    *num = 20;
}
int main()
{
    int num = 10;
    printf("%d\n", num);
    Change(&num);
    printf("%d\n", num);
    return 0;
}

實(shí)際上是通過(guò)實(shí)參的地址對(duì)實(shí)參進(jìn)行修改

?引例2?實(shí)現(xiàn)兩個(gè)整數(shù)的交換
void Swap(int*a,int*b)//形參是兩個(gè)整型指針
{
    int tmp = 0;//交換兩個(gè)數(shù)的值
    tmp = *a;
    *a = *b;
    *b = tmp;
}
int main()
{
    int a = 10;
    int b = 20;
    Swap(&a, &b);//傳址
    printf("%d\n%d\n", a, b);
    return 0;
}

如果修改為Swap(a,b),void Swap(int a,int b)結(jié)果是什么呢?原理和引例1相同,我就不過(guò)多解釋啦😁

🌜5.指針和數(shù)組🌛
先看一個(gè)例子:
int main()
{
    int arr[10] = { 0 };
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    return 0;
}

結(jié)論:數(shù)組名表示的是數(shù)組首元素的地址

//也就是說(shuō)我們可以這樣寫(xiě):
int arr[10]={0};
int*pa=&arr;//pa存放的是數(shù)組首元素的地址

例如:

int main()
{
? ? int arr[] = {1,2,3,4,5,6,7,8,9,0};
? ? int *p = arr; //指針存放數(shù)組首元素的地址
? ? int sz = sizeof(arr)/sizeof(arr[0]);
? ? for(i=0; ip+%d = %p\n", i, &arr[i], i, p+i);
? ? }
? ? return 0;
}

進(jìn)一步可以表示為以下這種方式:

int main()
{
    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    int* p = arr; //指針存放數(shù)組首元素的地址
    int sz = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    for (i = 0; i< sz; i++)
    {
        printf("%d ", *(p + i));
    }
    return 0;
}
🌜6.二級(jí)指針🌛

指針變量也是變量,那么指針變量的地址存放在哪里呢?-----二級(jí)指針

int main()
{
    int a = 10;
    int* pa = &a;
    printf("對(duì)pa進(jìn)行解引用=%d\n", *pa);
    printf("變量a的地址=%p\n", &a);
    printf("變量a的地址存儲(chǔ)在pa中=%p\n", pa);
    int** ppa = &pa;
    printf("指針變量pa的地址=%p\n", &pa);
    printf("對(duì)ppa解引用得到pa的值=%p\n", *ppa);
    printf("對(duì)ppa解引用得到pa再解引用得到a=%d\n", **ppa);
    printf("變量pa的地址存儲(chǔ)在ppa中=%p\n",ppa);
    **ppa = 30;
    //**ppa相當(dāng)于*pa,*pa相當(dāng)于a
    printf("a=%d\n", a);
    return 0;
}

程序運(yùn)行結(jié)果如上

🌜7.指針數(shù)組🌛

指針數(shù)組是指針還是數(shù)組呢?答案是數(shù)組,是存放指針變量的數(shù)組。

我們知道存在整型數(shù)組、浮點(diǎn)型數(shù)組、字符數(shù)組,那指針數(shù)組是什么樣子的呢?

int* arr[5]={0};

如圖片所示

簡(jiǎn)單介紹即可,進(jìn)階版跟后續(xù)筆記😭

你是否還在尋找穩(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)查看詳情吧

當(dāng)前文章:修仙之指針初階-創(chuàng)新互聯(lián)
網(wǎng)頁(yè)URL:http://muchs.cn/article28/cdghcp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃、手機(jī)網(wǎng)站建設(shè)、網(wǎng)站收錄、網(wǎng)站建設(shè)網(wǎng)站內(nèi)鏈、外貿(mào)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化