0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C語言指針詳細(xì)解析

嵌入式單片機(jī)MCU開發(fā) ? 來源:嵌入式單片機(jī)MCU開發(fā) ? 作者:嵌入式單片機(jī)MCU開 ? 2022-11-14 16:53 ? 次閱讀

概述

指針也就是內(nèi)存地址,指針變量是用來存放內(nèi)存地址的變量, 不同類型的指針變量所占用的存儲單元長度是相同的,而存放數(shù)據(jù)的變量因數(shù)據(jù)的類型不同,所占用的存儲空間長度也不同 。有了指針以后,不僅可以對數(shù)據(jù)本身,也可以對存儲數(shù)據(jù)的變量地址進(jìn)行操作。 指針是一個占據(jù)存儲空間的實(shí)體在這一段空間起始位置的相對距離值。在C/C++語言中,指針一般被認(rèn)為是指針變量,指針變量的內(nèi)容存儲的是其指向的對象的首地址,指向的對象可以是變量(指針變量也是變量),數(shù)組,函數(shù)等占據(jù)存儲空間的實(shí)體。

指針

數(shù)據(jù)存儲在內(nèi)存中,內(nèi)存又被分為一塊一塊的,每一塊都有一個特有的編號。而這個編號可以暫時(shí)理解為指針,就像房屋的編號。特點(diǎn)的房間可以找到特點(diǎn)的人,例如張三要去找李四,那么就要去到李四家,才能找到李四。 總結(jié)一下,其實(shí)指針就是變量,用來存放地址的變量(存放在指針中的值都當(dāng)成地址處理)。

在這里插入圖片描述

指針運(yùn)算符

&:取地址運(yùn)算符&是用來取操作對象的地址,它返回運(yùn)算對象的內(nèi)存地址。 *:指針運(yùn)算符&作用是通過操作對象的地址,獲取存儲的內(nèi)容也稱為“間接引用操作符”。

示例

#include 
int main()
{
    int a = 10;    //定義一個普通變量a,賦值為10
    int* pa;//定義指針變量pa
    pa = &a;//通過取地址符&,獲取a的地址,賦值給指針變量pa
    printf("a的值為:%d,pa的地址為=%p,*pa的值為=%d
",a,pa,*pa);
    return 0;
}

在這里插入圖片描述

指針類型

變量有不同的類型,整型,浮點(diǎn)型等等。指針同樣是有類型的,定義如下。

char*   pa = NULL;
int*    pb = NULL;
short*  pc = NULL;
long*   pd = NULL;
float*  pe = NULL;
double* pf = NULL;

指針類型的定義方式就是type + 。其實(shí)上面代碼中char 就是為了存放char類型變量的地址,short*就是為了存放short類型變量的地址。其他同樣。

示例

#include 
int main()
{
    char   a = 'a';
    int    b = 10;
    short  c = 20;
    long   d = 30;
    float  e = 40.0;
    double f = 50.0;
    char*   pa = NULL;
    int*    pb = NULL;
    short*  pc = NULL;
    long*   pd = NULL;
    float*  pe = NULL;
    double* pf = NULL;
    pa = &a;
    pb = &b;
    pc = &c;
    pd = &d;
    pe = &e;
    pf = &f;
    printf("a的值為:%d,pa的地址為=%p,pa的下一個地址為=%p
", a, pa, pa + 1);
    printf("b的值為:%d,pb的地址為=%p,pb的下一個地址為=%p
", b, pb, pb + 1);
    printf("c的值為:%d,pc的地址為=%p,pc的下一個地址為=%p
", c, pc, pc + 1);
    printf("d的值為:%d,pd的地址為=%p,pd的下一個地址為=%p
", d, pd, pd + 1);
    printf("e的值為:%f,pe的地址為=%p,pe的下一個地址為=%p
", e, pe, pe + 1);
    printf("f的值為:%lf,pf的地址為=%p,pf的下一個地址為=%p
", f, pf, pf + 1);
    return 0;
}

在這里插入圖片描述 從上述例程得知,指針加1或減1運(yùn)算,表示指針向前或向后移動一個單元(不同類型的指針,單元長度不同),指針的類型決定了指針向前或者向后走一步有多大距離。

指針變量的自增自減運(yùn)算。指針加 1 或減 1 運(yùn)算,表示指針向前或向后移動一個單元(不同類型的指針,單元長度不同)。這個在數(shù)組中非常常用。 指針變量加上或減去一個整形數(shù)。和第一條類似,具體加幾就是向前移動幾個單元,減幾就是向后移動幾個單元。

指針變量的初始化

指針初始化是將變量的地址分配給指針變量的過程,指針變量與其它變量一樣,在定義時(shí)可以賦值,即初始化。也可以賦值“NULL”或“0”,如果賦值“0”,此時(shí)的“0”含義并不是數(shù)字“0”,而是 NULL 的字符碼值。 指針變量在定義時(shí)如果未初始化,那么該指針就是野指針,野指針就是指針指向的位置是不可知的(隨機(jī)的、不正確的、沒有明確限制的),其值是隨機(jī)的,指針變量的值是別的變量的地址,意味著指針指向了一個地址是不確定的變量,此時(shí)去解引用就是去訪問了一個不確定的地址,所以結(jié)果是不可知的。

關(guān)系運(yùn)算

假設(shè)有指針pa,pb,那么其關(guān)系運(yùn)算主要有下列三種。

  1. pa > pb,表示 pa 指向的存儲地址大于 pb 指向的地址。
  2. pa == pb,表示 pa 和 pb 指向同一個存儲單元。
  3. pa == 0 ,表示 pa 是否為空指針。

示例

#include 
int main()
{
    int    a = 10;
    int       b = 20;

    int*    pa  = NULL;
    int*    paa = NULL;
    int*    pb  = NULL;
    int*    pc  = NULL;

    pa  = &a;
    paa = &a;
    pb  = &b;
    printf("pa的地址是%p,pb的地址是%p,",pa,pb);
    if (pa > pb)
        printf("pa指向的存儲地址大于pb指向的地址
");
    else
        printf("pa指向的存儲地址小于pb指向的地址
");

    printf("pa的地址是%p,paa的地址是%p,", pa, paa);
    if (pa == paa)
        printf("pa和paa是否指向同一個存儲單元
");

    printf("pc的地址是%p,", pc);
    if (pc == 0)
        printf("pc是空指針");

    return 0;
}

在這里插入圖片描述

數(shù)組

一維數(shù)組

不管什么變量都有地址,數(shù)組包含若干個元素,但是每個數(shù)組元素也在內(nèi)存中占用存儲單元,所以也有相對應(yīng)的地址。指針變量既然可以指向變量,同樣也可以指向數(shù)組元素。 在數(shù)組中,數(shù)組名即為該數(shù)組的首地址,對該指針進(jìn)行加減,就可以實(shí)現(xiàn)指針訪問數(shù)組元素。 在這里插入圖片描述

示例

#include 
int main()
{
    int Num[5] = {11,22,33,44,55};
    int* p;
    int* pp;

    p = &Num[0];//指向數(shù)組第一個元素,即數(shù)組首地址
    pp = &Num;//直接指向數(shù)組,數(shù)組名即為數(shù)組的首地址

    printf("數(shù)組的首地址Num=%p
", Num);
    printf("pp所指向的地址%p
", pp);
    printf("p所指向的地址是%p,數(shù)據(jù)是%d
",p,*p);
    printf("Num所指向的下一個地址是%p,數(shù)據(jù)是%d
", Num + 1, *(Num + 1));//數(shù)組名即為該數(shù)組的首地址,對該指針進(jìn)行加減,就可以實(shí)現(xiàn)指針訪問數(shù)組元素。
    printf("p所指向的下一個地址是%p,數(shù)據(jù)是%d
", p+1, *(p+1));
    return 0;
}

在這里插入圖片描述 由上述的結(jié)果可以得知:

  1. p 指向數(shù)組Num的第一個元素,則此操作將 Num第一個元素11,即Num[0] = 11。

  2. 數(shù)組名是地址,可以稱作數(shù)組地址,也可以看成第一個元素的地址,通過+整數(shù)可以移動到想要操作的元素。

  3. p+1操作為指針加整數(shù)操作,即向前移動一個單元。此時(shí) p + 1 指向Num[0]的下一個元素,即Num[1]。通過p + 整數(shù)的操作可以移動到想要操作的元素。

  4. 在 p+整數(shù)的操作要考慮邊界的問題,如一個數(shù)組長度為5,p+6的意義對于數(shù)組操作來說沒有意義。## 二維數(shù)組

    二維數(shù)組其實(shí)可以看成是一個矩陣,zai C語言中,定義一個數(shù)組num[3][4],可以看成是一個3行4列的矩陣,在內(nèi)存中每一個位置存儲一個數(shù)據(jù),用a[i][j]表示。 二維數(shù)組實(shí)際上就是元素為一維數(shù)組的數(shù)組,二維數(shù)組名可以看做指向其第一個元素(一維數(shù)組)的指針。 在這里插入圖片描述### 示例

#include 
int main()
{
    int Num[2][3] = {
        {11,22,33},
        {111,222,333}
        };
    int* p;

    p = &Num[0];//指向數(shù)組第一個元素,即數(shù)組首地址
    //二維數(shù)組名可以看做指向其第一個元素(一維數(shù)組)的指針,所以一級指針指向大小為一位數(shù)組大小
    printf("數(shù)組的首地址是%p,一級指針的大小為%d,二級指針?biāo)赶驍?shù)據(jù)為%d
", Num, sizeof(*Num),**Num);
    printf("p所指向的地址是%p,數(shù)據(jù)是%d
",p,*p);
    printf("Num所指向的下一個地址是%p,數(shù)據(jù)是%d
", Num + 1, **(Num + 1));
    printf("p所指向的第四個地址是%p,數(shù)據(jù)是%d
", p+3, *(p+3));
    return 0;
}

在這里插入圖片描述

字符串指針

對于字符,在計(jì)算機(jī)內(nèi)部都是用數(shù)字(字符編碼)來表示的,而字符串是“字符連續(xù)排列”的一種表現(xiàn)。字符串就是每個元素內(nèi)都存儲著字符的一維數(shù)組,通常稱之為字符數(shù)組。

在 C語言中,因?yàn)樽址麛?shù)組的元素內(nèi)存儲的都是 char 型的字符,所以字符數(shù)組的數(shù)據(jù)類型是 char 型,因而字符串實(shí)際上就是一個 char 型的一維數(shù)組。 在 C語言中,可以用兩種方法訪問一個字符串:

  1. 用字符數(shù)組存放一個字符串,然后輸出該字符串
  2. 用字符指針指向一個字符串

字符串中包含的字符的個數(shù)就是這個字符串的長度。C語言中用字符數(shù)組存儲字符串時(shí)在字符串的末端都要加一個字符“”來表示這個字符串的結(jié)束,這個“”稱為字符串結(jié)束符。因而在定義字符數(shù)組時(shí),數(shù)組大小應(yīng)為要存儲的字符串長度的最大值加 1。

示例

#include 
int main()
{
    /*字符數(shù)組賦初值*/
    char string1[] = { 'h','e', 'l', 'l', 'o'};
    /*字符數(shù)組賦初值添加結(jié)束符*/
    char string2[] = { 'h','e', 'l', 'l', 'o','' };
    /*字符串賦初值*/
    char string3[] = "hello";
    /*用sizeof()求長度*/
    printf("string1的長度=%d
", sizeof(string1));//輸出出現(xiàn)亂碼就是因?yàn)樽址Y(jié)尾并沒有結(jié)尾符''。
    printf("string2的長度=%d
", sizeof(string2));//
    printf("string3的長度=%d
", sizeof(string3));
    /*用printf的%s打印內(nèi)容*/
    printf("string1的內(nèi)容=%s
", string1);
    printf("string2的內(nèi)容=%s
", string2);
    printf("string3的內(nèi)容=%s
", string3);
    return 0;
}

在這里插入圖片描述

字符串指針變量本身是一個變量,用于存放字符串的首地址。而字符串本身是存放在以該首地址為首的一塊連續(xù)的內(nèi)存空間中并以 作為串的結(jié)束。字符數(shù)組歸根結(jié)底還是一個數(shù)組,字符串名也可以認(rèn)為是一個指針。 字符串儲存方式:

  1. 字符數(shù)組由一個或若干元素組成,每個元素存放一個字符;
  2. 而字符指針變量只存放字符串的首地址,不是整個字符串;

字符串存儲位置:

  1. 數(shù)組是在內(nèi)存中開辟了一段空間用于存放字符串;
  2. 字符指針是在文字常量區(qū)開辟了一段空間存放字符串,將字符串的首地址賦值給指針變量。### 示例
#include 
int main()
{
    char str[] = "hello world";// 棧(局部)
    char* string = "hello";//文字常量區(qū)
    char* string1;
    string1 = "hello world";//字符指針變量另外一種賦值方法
    printf("str=%s,數(shù)據(jù)大小=%d
", str, sizeof(str));//數(shù)據(jù)大小為所保存的字符大小
    printf("string=%s,數(shù)據(jù)大小=%d
", string,sizeof(string));//數(shù)據(jù)大小只是保存的指針大小
    printf("string1=%s,數(shù)據(jù)大小=%d
", string1,sizeof(string1));//數(shù)據(jù)大小只是保存的指針大小
    return 0;
}

在這里插入圖片描述 由上圖可以得知,數(shù)組是在內(nèi)存中開辟了一段空間用于存放字符串,故數(shù)組越大,所占的數(shù)據(jù)大小越大;字符指針是在文字常量區(qū)開辟了一段空間存放字符串,故字符指針是只想這個文字常量區(qū)的地址。

指針函數(shù)

指針函數(shù)就是一個返回值為指針的函數(shù),指針函數(shù)是指帶指針的函數(shù),函數(shù)返回類型是某一類型的指針,即本質(zhì)是一個函數(shù)。 函數(shù)定義:類型標(biāo)識符 * 函數(shù)名(參數(shù)表) 普通的函數(shù)定義如下所示:

int  fun(int x,int y);

指針函數(shù)定義如下所示:

int* fun(int x,int y);

普通的函數(shù)與指針函數(shù)只是多了一個 *號的區(qū)別。上述定義的指針函數(shù)其返回值是一個 int 類型的指針,是一個地址,而上述普通函數(shù)返回的是一個int值。所以指針函數(shù)一定有函數(shù)返回值 ,同時(shí)函數(shù)返回值必須賦給同類型的指針變量。

示例

#include 
int* fun(int x, int y);//函數(shù)申明
int* fun1(int x, int y);//函數(shù)申明
int main()
{
    int* p = fun(3, 4);
    int* p1 = fun1(3, 4);
    printf("p的地址為=%p,p所指向的數(shù)據(jù)是=%d
",p,*p);
    printf("p1的地址為=%p,p1所指向的數(shù)據(jù)是=%d
", p1, *p1);
    return 0;
}
/*實(shí)現(xiàn)x+y,同時(shí)返回存儲的地址*/
int* fun(int x, int y)
{
    static int sum = 0;//靜態(tài)變量
    int* p = ∑
    sum = x + y;
    return p;
}
/*實(shí)現(xiàn)x+y,同時(shí)返回存儲的地址*/
int* fun1(int x, int y)
{
    int sum = 0;
    int* p = ∑
    sum = x + y;
    return p;
}

在這里插入圖片描述 上面示例定義了fun和fun1函數(shù),同時(shí)在函數(shù)內(nèi)用指針p指向了sum變量,但是函數(shù)執(zhí)行完之后會釋放函數(shù),雖然最后return返回了該地址的指針,但是由于空間以及釋放,故不一定會得到正確的值,需要用static去修飾變量,使得其變?yōu)殪o態(tài)變量。靜態(tài)變量一旦生成,只有在程序結(jié)束才會釋放,所以指針能一直訪問該變量。 同樣的使用全局變量也能解決這個問題。

函數(shù)指針

函數(shù)指針是指帶指針的函數(shù),函數(shù)指針的本質(zhì)是一個指針,該指針的地址指向了一個函數(shù),所以它是指向函數(shù)的指針。函數(shù)指針就是指向代碼段中函數(shù)入口地址的指針。

函數(shù)定義:類型標(biāo)識符 (*函數(shù)名) (參數(shù)) 普通的函數(shù)定義如下所示:

int  fun(int x,int y);

函數(shù)指針聲明格式:

int (*fun)(int x,int y);

其中,int 為返回值,(*fun)作為一個整體,代表的是指向該函數(shù)的指針,(int x,int y)為形參列表。其中fun被稱為函數(shù)指針變量 。函數(shù)指針本質(zhì)是一個指針,其指向一個函數(shù)。 函數(shù)指針與數(shù)組類似,在數(shù)組中,數(shù)組名代表著該數(shù)組的首地址,函數(shù)也是一樣,函數(shù)名即是該數(shù)組的入口地址,因此,函數(shù)名就是該函數(shù)的函數(shù)指針。 函數(shù)指針是需要把一個函數(shù)的地址賦值給它,因此,可以采用如下的兩種方式:

p=fun;//第一種寫法
p=&fun;//第二種寫法

示例

#include 
int (*fun)(int, int); // 聲明函數(shù)指針,指向返回值類型為int,有兩個參數(shù)類型都是int的函數(shù)
//int (*fun)(int a, int b);   //也可以使用這種方式定義函數(shù)指針
int sum(int a, int b);
int Difference(int a, int b);

int main()
{
    fun = sum; // 函數(shù)指針fun指向求和的函數(shù)sum

    int c = (*fun)(1, 2);
    printf("兩數(shù)之和為=%d
", c);
    fun = &Difference; // 函數(shù)指針fun指向求差值的函數(shù)Difference
    c = (*fun)(5, 3);
    printf("兩數(shù)之差為=%d
", c);

    return 0;
}
/*求最大值*/
int sum(int a, int b) {
    return a+b;
}

/*求差值*/
int Difference(int a, int b) {
    return a-b;
}

在這里插入圖片描述 上面示例定義了sum求和函數(shù)和Difference求差函數(shù),可見函數(shù)指針fun指向函數(shù)的時(shí)候,可以添加取址符&,也可以不添加,所指向的為函數(shù)的入口。

指針函數(shù)和函數(shù)指針

定義

指針函數(shù)本質(zhì)是一個函數(shù),其返回值為指針。 函數(shù)指針本質(zhì)是一個指針,其指向一個函數(shù)。

寫法

指針函數(shù):int* fun(int x,int y); 函數(shù)指針:int (* fun)(int x,int y);

用途

當(dāng)項(xiàng)目比較大,代碼變得復(fù)雜了以后,有許多的函數(shù)的返回值,包括函數(shù)入?yún)⒍际窍嗤?,這時(shí)候如果要調(diào)用不同的排序方法,就可以使用指針函數(shù)來實(shí)現(xiàn),我們只需要修改函數(shù)指針初始化的地方,而不需要去修改每個調(diào)用的地方。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7575

    瀏覽量

    134003
  • 指針
    +關(guān)注

    關(guān)注

    1

    文章

    475

    瀏覽量

    70457
收藏 人收藏

    評論

    相關(guān)推薦

    C語言指針詳細(xì)解析

    可以對數(shù)據(jù)本身,也可以對存儲數(shù)據(jù)的變量地址進(jìn)行操作。 指針是一個占據(jù)存儲空間的實(shí)體在這一段空間起始位置的相對距離值。在C/C++語言中,指針
    發(fā)表于 09-14 10:03

    C語言入門教程-指針

    指針C語言中,指針被廣泛使用。所以要想完整地掌握C語言,您需要對
    發(fā)表于 07-29 11:30 ?634次閱讀

    C語言指針電子教程

    本資料是一份不錯的關(guān)于C語言指針的電子教程,希望對大家有所幫助... 指針簡介 指針C
    發(fā)表于 07-30 16:00 ?77次下載

    C語言中指針的介紹非常詳細(xì)

    C語言中指針的介紹非常詳細(xì) C語言中指針的介紹非常詳細(xì)
    發(fā)表于 12-25 10:39 ?57次下載

    C語言指針函數(shù)和函數(shù)指針詳細(xì)介紹

    C語言指針函數(shù)和函數(shù)指針詳細(xì)介紹。。。。。。。
    發(fā)表于 03-04 15:27 ?5次下載

    c語言函數(shù)指針定義,指針函數(shù)和函數(shù)指針的區(qū)別

     往往,我們一提到指針函數(shù)和函數(shù)指針的時(shí)候,就有很多人弄不懂。下面就由小編詳細(xì)為大家介紹C語言中函數(shù)指針
    發(fā)表于 11-16 15:18 ?3551次閱讀

    C語言的精髓——指針詳解

    C語言的精髓——指針詳解
    發(fā)表于 11-30 14:43 ?17次下載

    基于C語言中指針的基本用法解析

    C語言中其它的知識都學(xué)得可以,唯獨(dú)指針搞不懂。如果是這樣,我可以很負(fù)責(zé)的告訴你,對于這門編程語言,你等于是沒學(xué)。所以學(xué)好指針對于初學(xué)者是非
    的頭像 發(fā)表于 01-09 15:12 ?4711次閱讀

    為什么C語言要引入指針_引入指針的好處是什么

    讓你知道什么是 C語言 指針,為什么用指針,從此不在害怕指針。
    的頭像 發(fā)表于 07-28 10:12 ?2.2w次閱讀

    C語言教程之指針詳細(xì)資料說明

    本文檔的主要內(nèi)容詳細(xì)介紹的是C語言教程之指針詳細(xì)資料說明 學(xué)習(xí)目標(biāo)1.指針
    發(fā)表于 02-21 11:11 ?9次下載
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>教程之<b class='flag-5'>指針</b>的<b class='flag-5'>詳細(xì)</b>資料說明

    C語言指針指針變量的簡介和運(yùn)算實(shí)例程序免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是C語言指針指針變量的簡介和運(yùn)算實(shí)例程序免費(fèi)下載
    發(fā)表于 11-05 17:38 ?14次下載

    C語言中的指針(重點(diǎn))超詳細(xì)

    C語言中的指針1、指針是什么2、指針指針類型2.1、指針
    發(fā)表于 01-13 14:10 ?11次下載
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>中的<b class='flag-5'>指針</b>(重點(diǎn))超<b class='flag-5'>詳細(xì)</b>

    C語言進(jìn)階】C語言指針的高階用法

    C語言進(jìn)階】C語言指針的高階用法
    的頭像 發(fā)表于 08-31 13:24 ?2147次閱讀

    底層解析C指針(一)

    指針C語言中的精髓部分,同樣也是C語言的難點(diǎn)所在,下面從最底層來分析C
    的頭像 發(fā)表于 02-15 14:47 ?728次閱讀
    底層<b class='flag-5'>解析</b><b class='flag-5'>C</b><b class='flag-5'>指針</b>(一)

    詳解C語言指針底層基本原理

    說到指針,估計(jì)還是有很多小伙伴都還是云里霧里的,有點(diǎn)“知其然,而不知其所以然”。但是,不得不說,學(xué)了指針,C語言才能算是入門了。指針
    的頭像 發(fā)表于 04-06 10:43 ?1120次閱讀