最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言小知識之為什么要使用指針詳析

 更新時間:2021年10月15日 12:42:46   作者:嵌入式@hxydj  
指針是C語言中一個非常重要的概念,也是C語言的特色之一,使用指針可以對復雜數(shù)據(jù)進行處理,能對計算機的內(nèi)存分配進行控制,在函數(shù)調用中使用指針還可以返回多個值,這篇文章主要給大家介紹了C語言小知識之為什么要使用指針的相關資料,需要的朋友可以參考下

剛開始學習C語言的時候,感覺最難理解的就是指針,什么指針變量,變量指針,指向指針的變量,指向變量的指針?一堆概念,搞得人云里霧里的,今天不討論這些概念的問題,從最底層來分析C語言中為什么要使用指針,指針存在的意義又是什么呢?

首先從一個簡單的例子來看,寫一段代碼來交換x、y的值。

void main( void )
{
    u8 x = 10, y = 20;
    u8 temp;

    __asm( "sim" );                             //禁止中斷
    SysClkInit();
    delay_init( 16 );
    LED_GPIO_Init();
    Uart1_IO_Init();
    Uart1_Init( 9600 );
    ADC_GPIO_Init();
    __asm( "rim" );                             //開啟中斷
    while( 1 )
    {
        LED = ~LED;

        printf( "x = %d,y = %d\r\n", x, y );

        temp = x;
        x = y;
        y = temp;

        printf( "---> x = %d,y = %d \r\n\r\n\r\n", x, y );

        delay_ms( 200 );
    }
}

在STM8單片機中,交換x、y的值,并將值打印出來,打印結果如下:

image.png

通過第三個變量temp很輕松的就將x、y的值交換了。

但是為了程序的美觀性,不想再主程序中寫這么多的代碼,于是決定用一個函數(shù)在外部來實現(xiàn)這個功能。

void swap( u8 x, u8 y )
{
    u8 temp;
    temp = x;
    x = y;
    y = temp;
}

void main( void )
{
    u8 x = 10, y = 20;
    __asm( "sim" );                             //禁止中斷
    SysClkInit();
    delay_init( 16 );
    LED_GPIO_Init();
    Uart1_IO_Init();
    Uart1_Init( 9600 );
    ADC_GPIO_Init();
    __asm( "rim" );                             //開啟中斷
    while( 1 )
    {
        LED = ~LED;

        printf( "x = %d,y = %d\r\n", x, y );
        sawp( x, y );
        printf( "---> x = %d,y = %d \r\n\r\n\r\n", x, y );

        delay_ms( 200 );
    }
}

在主函數(shù)外面定義一個函數(shù),專門用來交換x,y的值。程序運行結果如下:

image.png

此時發(fā)現(xiàn)x和y的值并沒有交換,這是怎么回事?那么在交換函數(shù)內(nèi)部,也將x和y的值打印出來。修改代碼如下:

void swap( u8 x, u8 y )
{
    u8 temp;
    
    printf( "in: x = %d,y = %d\r\n", x, y );
    temp = x;
    x = y;
    y = temp;
    
    printf( "in: ---> x = %d,y = %d \r\n\r\n\r\n", x, y );
}

打印結果如下:

image.png

可以看到在交換函數(shù)內(nèi)部,x和y的值已經(jīng)交換了,但是在函數(shù)外部,x和y的值并沒有交換。這是為什么呢?單步調試直接觀察x和y在單片機內(nèi)部分存儲情況。

image.png

進入主程序之后,首先觀察主函數(shù)內(nèi)的x和y在內(nèi)存中的存儲情況,x值為10,也就是16進制的0x0A,在內(nèi)存中0x000009的位置存儲,y的值為20,也就是16進制的0x14,在內(nèi)存中0x00000B,位置存儲。

接下里進入到swap函數(shù)中。為了方便觀察,將swap函數(shù)內(nèi)部的x和y替換成了m和n。

image.png

可以看出在進入子函數(shù)之后,m和n的地址和值,都和main函數(shù)中的x和y一樣。接下來交換m和n的值。

image.png

交換完成后發(fā)現(xiàn),內(nèi)存中0x000009位置的值和0x00000B位置的值亞發(fā)生了交換。然后退出子函數(shù),返回到main函數(shù)中。

image.png

這時候奇怪的事情發(fā)生了,剛才內(nèi)存中交換的值又變回來了?這是為什么呢?在這里就不得不說在C語言中關于局部變量的問題,局部變量在C語言中是沒有固定的存儲位置的,它是由系統(tǒng)的堆棧統(tǒng)一來管理的,當進入函數(shù)內(nèi)部時,系統(tǒng)就會給這些局部變量臨時分配一個存儲空間存儲它的值,當程序要離開函數(shù)時,系統(tǒng)就會將局部變量的值保存在堆棧中,然后變量的存儲位置就被釋放了。當程序進入另一個函數(shù)中時,又會給這個函數(shù)內(nèi)部局部變量分配空間,這時候可能就會出現(xiàn)兩個函數(shù)中的局部變量都使用了同一個內(nèi)存空間。此時這個內(nèi)存空間的值改變后,并不影響上一個函數(shù)中局部變量的值,因為上一個函數(shù)中的局部變量值此時在堆棧中存放。當程序要離開當前的這個函數(shù)時,又會將當前的局部變量值保存在堆棧中。回到上一個函數(shù)后,又將堆棧中存儲的值恢復給變量,此時變量的地址又是臨時申請的,可能此刻申請的地址值還是和上一次一樣。但是并不代表這個地址就永遠屬于這個局部變量。

這個就很類似于超市中的儲物柜,你要進去超市買東西,先將東西存到一個柜子中,買完東西后,又將東西存儲物柜取了出來。然后隔了幾個小時,又要去這個超市買東西,又需要將東西存起來,但是此時存儲的柜子編號還是上上一次存儲時一樣。但是這并不能代表這個柜子的編號就是專屬于你的了。它只是儲物柜臨時分配給你的空間,當你取出東西后這個空間就會被系統(tǒng)收回,如果你下一次還需要用,系統(tǒng)又會自動給你分配,但是這兩次分配的剛好是一個編號而已。

那么要如何解決這種變量交換的問題呢?有兩種方法,第一種就是直接將要交換的這個兩個變量定義為全局變量,讓它在程序運行的過程中獨占一個地址空間,這樣就不會有其他變量來使用這個位置了。但是這樣的話就會比較浪費內(nèi)存空間,只使用了一次,但是卻要永久的占用。第二種方法就是直接使用指針。

下面將代碼改成使用指針的方式。

void swap( u8 *m, u8 *n )
{
    u8 temp;   
    temp = *m;
    *m = *n;
    *n = temp;    
}
void main( void )
{
    u8 x = 10, y = 20;
    __asm( "sim" );                             //禁止中斷
    SysClkInit();
    delay_init( 16 );
    LED_GPIO_Init();
    Uart1_IO_Init();
    Uart1_Init( 9600 );
    ADC_GPIO_Init();
    __asm( "rim" );                             //開啟中斷
    while( 1 )
    {
        LED = ~LED;

        printf( "x = %d,y = %d\r\n", x, y );
        sawp( &x, &y );
        printf( "---> x = %d,y = %d \r\n\r\n\r\n", x, y );

        delay_ms( 200 );
    }
}

在向swap函數(shù)傳遞參數(shù)的時候需要使用&符號。打印輸出結果

image.png

此時x和y的值已經(jīng)成功交換了?,F(xiàn)在也將子函數(shù)內(nèi)部的交換情況打印一下。

void swap( u8 *m, u8 *n )
{
    u8 temp;
    
    printf( "in: m = %d,n = %d\r\n", m, n );
    temp = *m;
    *m = *n;
    *n = temp;
    
    printf( "in: ---> m = %d,n = %d \r\n\r\n\r\n", m, n );
}

image.png

從輸出的結果來看,怎么m和n的值一個時1021,一個時1020.這個值是什么呢?直接單步調試看。

image.png

此時main函數(shù)中x的地址變成了0x0003FD,y的地址變成了0x0003FC.接著進入子函數(shù)。

image.png

這時可以看出m的值為0x03FD,n的值為0x03FC.*m的值為0x0A也是就10,*0x14也就是20.
接下來開始交換值。

image.png

可以看出m和n的值沒變,但是m和n的值交換了。接下來回到主函數(shù)中。

image.png

此時主函數(shù)中x和y的值也交換了。

那剛才串口打印出來的1021和1020是什么呢?1021的十六進制是0x03FD,1020的十六進制是0x03FC.也就是說剛才打印的m的值和x的地址一樣,n的值和y的地址一樣。

那為什么m和n會變成x和y地址,*m 和 *n又會變成 x 和 y 的值。這里就要說指針的本質了。在存儲器內(nèi)部,它是不認識什么變量和指針的,對于存儲空間來說,它只有地址和值。也就是說在什么地址處,存儲什么值。對于普通的變量來說,變量的名稱就會被編譯器編譯成地址,也就是說x和y就是它自己地址的別名。x和y的值就是地址中對應的值。

當操作普通變量x和y的時候,系統(tǒng)默認操作的就是它的值。而指針剛好和它相反,指針默認是把地址作為它的值,當操作指針的時候,默認操作的就是地址。為了將普通變量和指針進行區(qū)分,那么如果要使用指針的時候,就需要給它貼一個標簽,告訴系統(tǒng),我這個是特殊變量,它是直接操作地址的,不是操作值的。

所以在定義指針的時候給變量前面加一個*號,就表示告訴系統(tǒng),我這個是特殊的。比如定義了一個int *m。就表示告訴系統(tǒng),當我默認操作m的時候,你就給我它的地址,而不要給我它的值。當需要取值的時候就需要添加上標簽 *m,告訴系統(tǒng)我現(xiàn)在要取的值,不是地址,這是特殊情況,不要把默認的地址給我。

當要將普通變量傳遞給指針時,因為直接操作變量默認就是普通變量的值,而指針存貯的是地址,所以當普通變量和指針傳遞數(shù)據(jù)的時候,也要給普通變量添加一個標簽 & ,這個符號就告訴系統(tǒng),我現(xiàn)在不要默認的值,我要的是特殊情況的地址。

所以將x和y傳遞給指針的時候,前面要加&符號。

swap( &x, &y );對應的就是 swap( u8 *m, u8 *n );

剛才上面不是說了嗎,指針默認的是地址,加上*號就是值了。那么這樣直接傳遞過去不就是相當于 *m = &x 了嗎?

由于這個子函數(shù)是定義和傳值在一起操作了,省略了一步,標準操作應該是。

int *m;

m=&x;

先定義一個指針,然后將普通變量的特殊情況,也就是取普通變量的地址,傳遞給指針的默認情況。這樣m的默認情況下就代表的值x的地址,而x的值就是*m。

如果定義變量和給變量賦值在一條語句時,上面的代碼就可以簡寫為

int *m = &x;

所以上面的函數(shù) swap( &x, &y ); 給指針傳遞值的時候,指針的定義和賦值是在一條語句完成的, swap( u8 *m, u8 *n ); 這是一種常用的簡寫形式。

在swap函數(shù)內(nèi)部操作 *m 也就相當于直接操作的是x,操作 *n 就是直接操作的y,所以交換 *m 和 *n的值,就相當于交換x和y的值。

在沒有使用指針時通過子函數(shù)交換,此時傳遞的是變量的值,相當于把變量的值拷貝了一份,給了子程序。

而有了指針之后,相當于將變量的地址直接給了子函數(shù)。相當于給變量x和y又起了一個別名。操作別名的時候,也就相當于直接操作的是x。

由此可見,指針只是為了方便編寫程序而設置的一種給變量起別名的方法,也就是相當于給自己柜子配了了一把鑰匙。只要別人有這個鑰匙,也就可以打開你的柜子。所以指針在使用的時候會有危險性。

如果系統(tǒng)中有關鍵數(shù)據(jù),那么如果這個數(shù)據(jù)用指針傳遞給了外部函數(shù),那么當外部函數(shù)修改數(shù)據(jù)的時候,系統(tǒng)就會存在風險。有可能外部函數(shù)修改了一個值,而這個值是非法的,自己的系統(tǒng)就奔潰了。所以在使用指針的時候一定要注意安全性問題。

通過上面的例子,相信對指針就有了更深層次的理解了。它是為了方便操作變量而設置的特殊情況,是被貼了標簽的變量。至于什么指針變量,變量指針,那都是起的名字而已,搞不清楚這些概念也不用去糾結,只要在使用的時候,知道如何使用就行了。

總結

到此這篇關于C語言小知識之為什么要使用指針的文章就介紹到這了,更多相關C語言使用指針內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • jquery ready函數(shù)深入分析

    jquery ready函數(shù)深入分析

    本文主要介紹jquery ready,這里整理了相關資料及相關示例代碼幫助大家學習參考,有興趣的小伙伴可以參考下
    2016-08-08
  • c++ 基于opencv 識別、定位二維碼

    c++ 基于opencv 識別、定位二維碼

    這篇文章主要介紹了c++ 基于opencv 識別、定位二維碼,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下
    2021-03-03
  • c語言獲取用戶輸入字符串是scanf和gets的區(qū)別詳解

    c語言獲取用戶輸入字符串是scanf和gets的區(qū)別詳解

    今天小編就為大家分享一篇c語言獲取用戶輸入字符串是scanf和gets的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • C語言實現(xiàn)企業(yè)員工管理系統(tǒng)開發(fā)

    C語言實現(xiàn)企業(yè)員工管理系統(tǒng)開發(fā)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)企業(yè)員工管理系統(tǒng)開發(fā),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 利用C語言編寫一個無限循環(huán)語句

    利用C語言編寫一個無限循環(huán)語句

    這篇文章主要介紹了利用C語言編寫一個無限循環(huán)語句問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C++程序中添加.c.h的實現(xiàn)方法

    C++程序中添加.c.h的實現(xiàn)方法

    這篇文章主要介紹了C++程序中添加.c.h的實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C語言strcat函數(shù)詳解:字符串追加的利器

    C語言strcat函數(shù)詳解:字符串追加的利器

    strcat函數(shù)用于將源字符串追加到目標字符串的末尾,并返回一個指向目標字符串的指針,它可以實現(xiàn)字符串的拼接操作
    2024-08-08
  • C++實現(xiàn)基于控制臺界面的吃豆子游戲

    C++實現(xiàn)基于控制臺界面的吃豆子游戲

    這篇文章主要介紹了C++實現(xiàn)基于控制臺界面的吃豆子游戲,實例分析了吃豆子游戲的原理與C++實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-04-04
  • C語言所有經(jīng)典排序方法的實現(xiàn)代碼

    C語言所有經(jīng)典排序方法的實現(xiàn)代碼

    這篇文章給大家分享C語言所有經(jīng)典排序方法,文章給大家提供完整的實例代碼幫助大家快速學習掌握C語言排序方法,感興趣的朋友一起看看吧
    2021-06-06
  • C語言詳細分析講解關鍵字enum與sizeof及typedef的用法

    C語言詳細分析講解關鍵字enum與sizeof及typedef的用法

    在?C?語言中經(jīng)常會見到?enum、sizeof、typedef,那么我們今天就來講解下它們?nèi)齻€,enum是C語言中的一種自定義類型,它是一種枚舉類型,sizeof是編譯器的內(nèi)置指示符,用于計算類型或變量所占內(nèi)存打小,typedef用于給一個已經(jīng)存在的數(shù)據(jù)類型重命名,本質上不能產(chǎn)生新的類型
    2022-04-04

最新評論

楚雄市| 松江区| 惠安县| 凉山| 通化县| 四子王旗| 海阳市| 利津县| 寻乌县| 芮城县| 聊城市| 合川市| 呼图壁县| 得荣县| 延川县| 井研县| 景洪市| 凯里市| 丹东市| 苍溪县| 时尚| 城固县| 宁化县| 嘉黎县| 池州市| 班戈县| 吐鲁番市| 启东市| 萍乡市| 丰城市| 垫江县| 灵台县| 冀州市| 海城市| 南开区| 黄浦区| 吴桥县| 西吉县| 花莲县| 锡林浩特市| 微山县|