C語言指針初階-創(chuàng)新互聯(lián)

1. 指針是什么?

在計(jì)算機(jī)中,所有的數(shù)據(jù)都是存放在存儲器中的,不同的數(shù)據(jù)類型占有的內(nèi)存空間的大小各不相同。內(nèi)存是以字節(jié)為單位的連續(xù)編址空間,每一個(gè)字節(jié)單元對應(yīng)著一個(gè)獨(dú)一的編號,這個(gè)編號被稱為內(nèi)存單元的地址。比如:int 類型占 4 個(gè)字節(jié),char 類型占 1 個(gè)字節(jié)等。系統(tǒng)在內(nèi)存中,為變量分配存儲空間的首個(gè)字節(jié)單元的地址,稱之為該變量的地址。地址用來標(biāo)識每一個(gè)存儲單元,方便用戶對存儲單元中的數(shù)據(jù)進(jìn)行正確的訪問。在高級語言中地址形象地稱為指針。

成都創(chuàng)新互聯(lián)專業(yè)提供綿陽電信機(jī)房機(jī)柜租用服務(wù),為用戶提供五星數(shù)據(jù)中心、電信、雙線接入解決方案,用戶可自行在線購買綿陽電信機(jī)房機(jī)柜租用服務(wù),并享受7*24小時(shí)金牌售后服務(wù)。

指針理解的2個(gè)要點(diǎn): 1. 指針是內(nèi)存中一個(gè)最小單元的編號,也就是地址 2. 平時(shí)口語中說的指針,通常指的是指針變量,是用來存放內(nèi)存地址的變量

總結(jié):指針就是地址,口語中說的指針通常指的是指針變量。

編號 - 地址 - 指針

指針變量
我們可以通過&(取地址操作符)取出變量的內(nèi)存其實(shí)地址,把地址可以存放到一個(gè)變量中,這個(gè) 變量就是指針變量
#includeint main()
{
 int a = 10;//在內(nèi)存中開辟一塊空間
 int *p = &a;//這里我們對變量a,取出它的地址,可以使用&操作符。
    //a變量占用4個(gè)字節(jié)的空間,這里是將a的4個(gè)字節(jié)的第一個(gè)字節(jié)的地址存放在p變量
? ? //中,p就是一個(gè)之指針變量。
 return 0;
}
指針變量,用來存放地址的變量。(存放在指針中的值都被當(dāng)成地址處理)。

那這里的問題是:

  1. 一個(gè)小的單元到底是多大?(1個(gè)字節(jié))

  1. 如何編址?

經(jīng)過仔細(xì)的計(jì)算和權(quán)衡我們發(fā)現(xiàn)一個(gè)字節(jié)給一個(gè)對應(yīng)的地址是比較合適的。 對于32位的機(jī)器,假設(shè)有32根地址線,那么假設(shè)每根地址線在尋址的時(shí)候產(chǎn)生高電平(高電壓)和低電 平(低電壓)就是(1或者0); 那么32根地址線產(chǎn)生的地址就會是:

這里就有2的32次方個(gè)地址。 每個(gè)地址標(biāo)識一個(gè)字節(jié),那我們就可以給 (2^32Byte == 2^32/1024KB == 2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB) 4G的空閑進(jìn)行編址。 同樣的方法,那64位機(jī)器,如果給64根地址線,那能編址多大空間,自己計(jì)算。

這里我們就明白:

  • 在32位的機(jī)器上,地址是32個(gè)0或者1組成二進(jìn)制序列,那地址就得用4個(gè)字節(jié)的空間來存儲,所以 一個(gè)指針變量的大小就應(yīng)該是4個(gè)字節(jié)。

  • 那如果在64位機(jī)器上,如果有64個(gè)地址線,那一個(gè)指針變量的大小是8個(gè)字節(jié),才能存放一個(gè)地 址。

總結(jié):

  • 指針是用來存放地址的,地址是唯一標(biāo)示一塊地址空間的。

  • 指針的大小在32位平臺是4個(gè)字節(jié),在64位平臺是8個(gè)字節(jié)。

2.指針和指針類型

這里我們在討論一下:指針的類型 我們都知道,變量有不同的類型,整形,浮點(diǎn)型等。那指針有沒有類型呢? 準(zhǔn)確的說:有的。

int num = 10;
p = #

要將&num(num的地址)保存到p中,我們知道p就是一個(gè)指針變量,那它的類型是怎樣的呢? 我們給指針變量相應(yīng)的類型。

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

這里可以看到,指針的定義方式是: type + * 。

其實(shí):

char* 類型的指針是為了存放 char 類型變量的地址。 short* 類型的指針是為了存放 short 類型變量的地址。 int* 類型的指針是為了存放 int 類型變量的地址。

那指針類型的意義是什么?

2.1 指針+-整數(shù)
int main()
{

    int arr[10] = { 0 };
    int *p = arr;
    char *pc = arr;
    printf("%p\n", p);
    printf("%p\n", p + 1);

    printf("%p\n", pc);
    printf("%p\n", pc + 1);
    return 0;
}

指針類型決定了指針走一步走多遠(yuǎn)(步長)

整形指針+1步長是4,字符指針+1步長是1,double類型+1步長是8

2.2 指針的解引用
#includeint main()
{
 int n = 0x11223344;
 char *pc = (char *)&n;
 int *pi = &n;
 *pc = 0;   //重點(diǎn)在調(diào)試的過程中觀察內(nèi)存的變化。
 *pi = 0;   //重點(diǎn)在調(diào)試的過程中觀察內(nèi)存的變化。
 return 0;
}

總結(jié):指針的類型決定了,對指針解引用的時(shí)候有多大的權(quán)限(能操作幾個(gè)字節(jié))。

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

f10調(diào)試觀察內(nèi)存變化



int:

int main()
{
    int arr[10] = { 0 };
    int* p = arr;
    int i = 0;
    for (i = 0; i< 10; i++)
    {
        *(p + i) = 1; //p + i 其實(shí)是下標(biāo)為i的地址

    }
    return 0;
}

p + i 是下標(biāo)為i的地址,整形指針加1跳過一個(gè)整形(4個(gè)字節(jié))


char

int main()
{
    int arr[10] = { 0 };
    char* p = arr;

    int i = 0;
    for (i = 0; i< 10; i++)
    {
        *(p + i) = 1; //p + i 其實(shí)是下標(biāo)為i的地址

    }
    return 0;
}

char類型指針加1跳過一個(gè)字節(jié)

指針類型是有意義的,用什么類型訪問取決于想要的功能。

p + 1跳過幾個(gè)字節(jié)只取決于指針類型,跟指向誰沒關(guān)系。

3. 野指針
概念: 野指針就是指針指向的位置是不可知的(隨機(jī)的、不正確的、沒有明確限制的)
3.1 野指針成因 1. 指針未初始化
#includeint main()
{ 
 int *p;//局部變量指針未初始化,默認(rèn)為隨機(jī)值
    *p = 20;
 return 0;
}

這里的p就是一個(gè)野指針,p是一個(gè)局部的指針變量,局部變量不初始化的話,默認(rèn)是隨機(jī)值

非法訪問內(nèi)存

2. 指針越界訪問
#includeint main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
        //當(dāng)指針指向的范圍超出數(shù)組arr的范圍時(shí),p就是野指針
        *(p++) = i;
   }
    return 0;
}
3. 指針指向的空間釋放
int* test()
{
    int a = 10;
    return &a;
}

int main()
{

    int* p = test();
    *p = 20;
    return 0;
}

a是局部變量,要把20放入*p時(shí) 地址已經(jīng)被返回給操作系統(tǒng),指向的空間被釋放也會導(dǎo)致野指針。

3.2如何規(guī)避野指針

1. 指針初始化 2. 小心指針越界 3. 指針指向空間釋放及時(shí)置NULL 4. 避免返回局部變量的地址 5. 指針使用之前檢查有效性

#includeint main()
{
    int *p = NULL;
    //....
    int a = 10;
    p = &a;
    if(p != NULL)
   {
        *p = 20;
   }
    return 0;
}
4. 指針運(yùn)算
  • 指針+- 整數(shù)

  • 指針-指針

  • 指針的關(guān)系運(yùn)算

4.1 指針+-整數(shù)
#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指針+-整數(shù);指針的關(guān)系運(yùn)算
for (vp = &values[0]; vp< &values[N_VALUES];)
{
     *vp++ = 0;
}

指針由低到高

int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    int* p = arr;
    int* pend = arr + 9;
    while (p<= pend)
    {
        printf("%d\n", *p);
        p++;
    }
    return 0;
}
4.2 指針-指針
int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

    //char c[5];
    指針和指針相減的前提:
    兩個(gè)指針指向同一塊空間
    //printf("%d\n", &arr[9] - &c[0]);//err

    printf("%d\n", &arr[9] - &arr[0]); //- 9
    //指針減去指針得到的兩個(gè)指針之間的元素個(gè)數(shù)
    return 0;
}
4.3 指針的關(guān)系運(yùn)算
for(vp = &values[N_VALUES]; vp >&values[0];)
{
    *--vp = 0;
}

代碼簡化, 這將代碼修改如下:

for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
    *vp = 0;
}

實(shí)際在絕大部分的編譯器上是可以順利完成任務(wù)的,然而我們還是應(yīng)該避免這樣寫,因?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ù)組
int main()
{
    int arr[10] = { 0 };
    //數(shù)組名是數(shù)組首元素的地址
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    return 0;
}

運(yùn)行結(jié)果:

可以得出:數(shù)組名和數(shù)組首元素地址相同

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

那么這樣寫代碼是可行的:

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是數(shù)組首元素的地址

既然可以把數(shù)組名當(dāng)成地址存放到一個(gè)指針中,我們使用指針來訪問一個(gè)就成為可能。

#includeint 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("&arr[%d] = %p<====>p+%d = %p\n", i, &arr[i], i, p + i);
    }
    return 0;
}

運(yùn)行結(jié)果:

所以 p+i 其實(shí)計(jì)算的是數(shù)組 arr 下標(biāo)為i的地址。 那就可以直接通過指針來訪問數(shù)組。

如下:

int main()
{
    int arr[10] = { 0 };
    int* p = arr;
    int i = 0;
    for (i = 0; i< 10; i++)
    {
        //printf("%p<==>%p\n", &arr[i], p + i);
        *(p + i) = i;
    }

    for (i = 0; i< 10; i++)
    {
        printf("%d ", *(p + i));
    }
    return 0;
}

運(yùn)行結(jié)果:

指針指向的不同寫法

int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    int* p = arr; //數(shù)組名
    printf("%d\n", arr[2]);
    printf("%d\n", p[2]); //p[2] -->*(p + 2)

    // [] 是一個(gè)操作符   2和arr是兩個(gè)操作數(shù)
    //a + b 
    //b + a
    printf("%d\n", 2[arr]);
    printf("%d\n", *(2 + arr));
    //arr[2] -->*(arr + 2) -->*(2 + arr) -->2[arr]


    //arr[2]<==>*(arr + 2)<==>*(p + 2)<==>*(2 + p)<==>*(2 + arr) == 2[arr]
    //2[arr]<==>*(2 + arr)
    return 0;
}
6. 二級指針

指針變量也是變量,是變量就有地址,那指針變量的地址存放在哪里? 這就是 二級指針 。

對于二級指針的運(yùn)算有: *ppa 通過對ppa中的地址進(jìn)行解引用,這樣找到的是 pa , *ppa 其實(shí)訪問的就是 pa .

int b = 20;
*ppa = &b;//等價(jià)于 pa = &b;

**ppa 先通過 *ppa 找到 pa ,然后對 pa 進(jìn)行解引用操作: *pa ,那找到的是 a .

**ppa = 30;
//等價(jià)于*pa = 30;
//等價(jià)于a = 30;

int main()
{
    int a = 10;
    int* pa = &a; //pa是指針變量,一級指針

    int* *ppa = &pa; //pa也是個(gè)變量,&pa取出pa在內(nèi)存中起始地址
    //ppa就是一個(gè)二級指針變量

    int** *pppa = &ppa;

    return 0;
}
7. 指針數(shù)組
int main()
{
    int arr[10];//整形數(shù)組 - 存放整形的數(shù)組就是整形數(shù)組
    char ch[5];//字符數(shù)組 - 存放的是字符
    //指針數(shù)組 - 存放指針的數(shù)組
    int* parr[5];//整形指針的數(shù)組
    char* pch[5];

    return 0;
}

指針數(shù)組是數(shù)組。是存放指針的數(shù)組。

已知整形數(shù)組,字符數(shù)組。

指針數(shù)組:

int* arr3[5];//是什么?

arr3是一個(gè)數(shù)組,有五個(gè)元素,每個(gè)元素是一個(gè)整形指針。

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

新聞名稱:C語言指針初階-創(chuàng)新互聯(lián)
標(biāo)題網(wǎng)址:http://bm7419.com/article48/gejep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營銷推廣用戶體驗(yàn)、電子商務(wù)網(wǎng)站策劃、企業(yè)建站外貿(mào)建站

廣告

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

成都定制網(wǎng)站建設(shè)