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

1.指針是什么?
引言:變量的內存地址:先前我們了解到,C程序中變量的值都是存儲在計算機內存中特定的存儲單元中。而內存中的每個單元都有唯一的地址。
1.1理解指針是什么?🔻
1.指針是內存中一個最小的單元編號,也就是地址。
2.口語中的指針,指的是指針變量,是用來存放變量的地址。

我們可以進一步將指針理解為“內存”

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

圖片描述

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

圖片描述

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

總結:?

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

總結:?

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

注意:

本例第5行:指針變量只能指向同一基類型的變量,否則會引起warning。所以本例使用了強制類型轉換。

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

🌜2.指針和指針類型🌛

我們都知道,變量有不同的類型,如整型、浮點型等等。那么指針也有對應的指針類型。

int num=10;
int* p=#//pa是一個指針變量,它指向一個整型變量
變量p是一個指針變量,用來存放num的地址。因為num的類型是整型,那么指針存放的數(shù)據(jù)類型是整型,對應p是一個整型指針,同時需要在int和p之間加一個*確保它是一個指針變量。
2.1指針類型:
指針類型定義的方式:類型關鍵字+*+指針變量名
char* p=NULL;(存放char類型變量的地址)
short* p=NULL;(存放short類型變量的地址)
long* p=NULL;(存放long類型變量的地址)
int* p=NULL;(存放int類型變量的地址)
float* p=NULL;(存放float類型變量的地址)
double* p=NULL;(存放double類型變量的地址)
介紹一下 指針運算符, 也稱 間接尋址運算符 或 解引用運算符:(*)間接尋址運算符*用來訪問指針變量指向變量的值。 運算時,要求指針已經(jīng)被正確初始化或者已經(jīng)指向內存中某個確定的存儲單元,防止野指針的出現(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;
}

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

總結:指針的類型決定了指針向前或者向后走一步是多大距離

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

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

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

總結:💗

  1. 指針的類型決定了指針解引用操作對內存能訪問多大的權限(能操作幾個字節(jié))

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

同樣,我們可以通過解引用修改變量的值,看下面程序運行結果: 📄
int main()
{
    int num = 0;
    int* pa = #//定義指針變量的同時對其初始化
    *pa = 20;//修改指針變量pa所指向的變量的值
? ? //引用指針所指向的變量的值,也稱為指針的解引用。
    printf("%d\n", num);
    return 0;
}

那么:既然*pa和變量num的值一樣,我們原本可以很容易的將變量a的值打印出來,為什么還要舍近求遠地使用指針變量來得到a的值呢?通過”標題4展現(xiàn)指針的強大功能“😍

👺3.野指針👺

概念:

?野指針就是指指向的內存是不可知的。(隨機的、不正確的、沒有明確限制的)

3.1野指針的成因😺 3.1.1指針的未初始化
int main()
{
? ? int*p;//此時指針變量p指向的內存是不可知的
? ? *p=20;//對指針進行解引用修改值可能會對內存發(fā)生不可逆的影響
? ? return 0;
}
3.1.2指針的越界訪問
int main()
{
    int arr[10] = { 0 };
    int* p=&arr;//數(shù)組的第一個元素的首地址
    int i = 0;
    for (i = 0; i< 11; i++)
    {
        *(p++) = i;//先對p賦值,后p++(詳看++的運算規(guī)則)
? ? ? ? //指針指向的范圍超出了數(shù)組的范圍,此時p就是野指針
    }
    for (i = 0; i< 10; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}
3.1.3指針指向的空間釋放
與動態(tà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
}
恪守準則:
1.永遠清楚每個指針指向了哪里,指針必須只想一塊有意義的內存;
2.永遠清楚每個指針指向的對象的內容是什么;
3.永遠不要使用未初始化的指針變量。
🌜4.指針運算🌛 4.1指針+-整數(shù)😇
#define N_VALUES 5
float values[N_VALUES];//浮點型數(shù)組
float* vp;//定義一個浮點型指針
//指針+-整數(shù);指針的關系運算
int main()
{
    for (vp = &values[0]; vp< &values[N_VALUES];)
    {
        *vp++ = 0;//數(shù)組從下標為0的元素開始賦值為0;
    }
    return 0;
}
4.2指針-指針😇
//函數(shù)功能:模擬實現(xiàn)strlen
//函數(shù)形參:字符型指針
//函數(shù)返回值:整型
int my_strlen(char* ch)
{
    char* p = ch;
    //數(shù)組名是數(shù)組首地址
    while (*p!='\0')
    {
        p++;
    }
    return p - ch;
    //指針-指針:實現(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指針的關系運算😇
#define N_VALUES 5
float values[N_VALUES];//浮點型數(shù)組
float* vp;//定義一個浮點型指針
//指針+-整數(shù);指針的關系運算
int main()
{
    for(vp = &values[N_VALUES]; vp >&values[0];)//vp指向下標為5的內存空間
? ? {
? ? ? ? *--vp = 0;//從下標為4的位置開始
? ? }
    return 0;
}
當我們對代碼進行簡化時:
#define N_VALUES 5
float values[N_VALUES];//浮點型數(shù)組
float* vp;//定義一個浮點型指針
//指針+-整數(shù);指針的關系運算
int main()
{? ? 
? ? for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
? ? {
? ? ? ? *vp = 0;
? ? ? ? //當vp=&values[0]時,*vp=0,此時會進行vp--,導致指針指向第一個元素之前的內存空間,應避免這樣? ? ? ? ? //的問題
? ? }
    return 0;
}
實際在絕大部分的編譯器上是可以順利完成任務的,然而我們還是應該避免這樣寫,因為標準并不保證
它可行

?標準規(guī)定?

允許指向數(shù)組元素的指針與 指向數(shù)組最后一個元素后面的那個內存位置的指針比較,但是 不允許與
指向第一個元素之前的那個內存位置的指針進行比較。
4.4按值調用和模擬按引用調用 ?引例1?修改實參的值
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的值,但是再次輸出實參的值卻發(fā)生沒有任何變化,說明函數(shù)的形參值的改變并未影響到實參值的改變。這是因為形參是實參的一份臨時拷貝,通過按值調用不能在被調函數(shù)中改變其調用語句中的實參值。這時我們就要用到指針這個秘密武器了。指針變量的一個重要作用就是用作函數(shù)參數(shù),由于傳給被調函數(shù)的這個值不是變量的值,而是變量的地址,通過向被調函數(shù)傳遞變量的地址可以在被調函數(shù)中改變主調函數(shù)中變量的值,模擬C++中的按引用調用。

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

實際上是通過實參的地址對實參進行修改

?引例2?實現(xiàn)兩個整數(shù)的交換
void Swap(int*a,int*b)//形參是兩個整型指針
{
    int tmp = 0;//交換兩個數(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)結果是什么呢?原理和引例1相同,我就不過多解釋啦😁

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

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

//也就是說我們可以這樣寫:
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;
}

進一步可以表示為以下這種方式:

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.二級指針🌛

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

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

程序運行結果如上

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

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

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

int* arr[5]={0};

如圖片所示

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

你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

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

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

廣告

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

搜索引擎優(yōu)化