老司机又开车(来不及解释,快上!)之秒懂单片机指针!
擊上方“果果小師弟”,選擇“置頂/星標公眾號”
干貨福利,第一時間送達!
摘要:大家想過沒有我們用keil寫單片機的代碼,你的函數啊、變量啊最終都放在了哪里?我們一直說的內存五區,到底是哪五區?到底放在芯片的哪個地方呢?還有為什么你學完C語言指針和結構體,32單片機里面的關于結構體指針的內容還是搞不清楚呢?如果你有這些問題,今天就帶你研究研究!
這張圖學過STM32單片機的小伙伴應該都不陌生,我們看到的STM32芯片已經是已經封裝好的成品,主要由內核和片上外設組成。若與電腦類比,內核與外設就如同電腦上的CPU與主板、內存、顯卡、硬盤的關系。芯片和外設之間通過各種總線連接。連接被控總線的是FLASH,RAM和片上外設,這些功能部件共同排列在一個4GB的地址空間內。上面這些張圖是STM32F40XXX系列單片機的內存地址映射圖。
我們的代碼就是放在Flash里面(0x8000000~0x80FFFFF)。代碼就是你寫得各種函數,而在程序中聲明的各種變量都放在RAM中,局部變量就是在函數運行完空間釋放,全局變量就是程序運行完了再釋放,可以這樣簡單的理解。
CPU使用的變量是存儲在RAM里面的,要問我RAM是啥,RAM就是個芯片。就是上圖的Block1的SRAM區。CPU是通過導線和RAM芯片連接的,然后可以通過導線往RAM芯片里面存儲數據和讀數據。首先RAM需要有個一開始的地址,對于STM32單片機來說開始地址是0x20000000,要問我為啥要規定地址。只有規定了地址CPU才好對數據進行存儲,要是沒有地址,瞎幾把存,瞎幾把取......
1、變量
1.定義一個int型的變量,通過打印可以看到這個變量存儲的地址是:0x20000000。這也證明了我們內存的首地址是0x20000000。我們定義的value變量就放在這里。
2.再定義一個變量
通過打印可以看到這個變量存儲的地址是:0x20000004。因為int類型在內存中占據4個字節,所以第二個變量就存放在0x20000004這個地方。
綜上所述,定義的兩個變量在內存里面是下面這樣子。
0x2000 0000地址里面存儲的是 0
?0x2000 0004地址里面存儲的是 1
2、指針變量
定義指針其實和定義變量一樣的,只不過變量名前頭有個*
下面就定義一個int型的指針變量,變量的名字是p。然后有人會問,為啥變量名字前面加個*就是指針了?
答:搞C語言那幫家伙們規定的。
定義指針和定義變量一樣,然后可以定義各種類型的。
然后記住一句話:
“指針這個變量是存變量的地址的! 指針這個變量是存變量的地址的! 指針這個變量是存變量的地址的!
”所以給指針賦值自然是把變量的地址給它。
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"int?value?=?0; int?value2?=?1; int?*p;int?main(void) {?uart_init(115200);delay_init();p=&value;//把變量value的地址復制給這個指針printf("Address?of?a:?%p\n",p);//打印下這個指針指向的地址while(1){?}? }一般什么類型的指針變量就應該賦值什么類型變量的地址。如再定義個char型
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"int?value?=?0; int?value2?=?1; int?*p;//定義一個指針char?value3=1; char?*q;int?main(void) {?uart_init(115200);//串口初始化delay_init();p=&value;//把變量value的地址復制給這個指針q=&value3;//把變量value的地址復制給這個指針printf("Address?of?a:?%p\n",q);//打印下這個指針指向的地址while(1){?}? }那些規定C語言的大佬弄出來指針這個玩意有啥用?
3、指針有啥用?
1.咱先使用下指針,然后具體有啥用就自己體會了。前面咱把一個變量的地址賦值給了指針了,然后搞C語言的那幫家伙們又規定。*{指針變量名} :代表了這個指針所指向的變量。
啥意思呢?
對照下面的程序p=&value,p記錄的就是變量value的地址, 然后*p就代表value。
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"int?value?=?0; int?*p;//定義一個指針int?main(void) {?uart_init(115200);//串口初始化delay_init();p=&value;//把變量value的地址復制給指針變量pprintf("Address?of?a:?%d\n",value);printf("Address?of?b:?%d\n",*p);while(1){?}? }有人會想......就這?
這不是脫了褲子放屁
多此一舉?
其實我一開始也是這樣想的......
既然 * p就代表value,那么* p=XXXX
不就是相當于value=XXXX
看看下面這個例子
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h" int?value?=?0; int?*p;//定義一個指針? int?main(void) {?uart_init(115200);//串口初始化delay_init();p=&value;//把變量value的地址復制給指針變量pprintf("value?of?a:?%d\n",value);*p=520;?printf("value?of?b:?%d\n",value);while(1){?}? }還是沒感覺到指針有啥用?別著急,先把基本的知識點學完哈。沒有最基本的知識儲備是不可以的,因為厚積而薄發!
見過返回值是指針的函數沒?
4、函數指針
先看一下,如果感覺不理解就接著往下看
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"int?value?=?0; int?*p;//定義一個指針int?*function(void) {return?&value;//把value的地址返回 }int?main(void) {?uart_init(115200);//串口初始化delay_init();p=function();//調用函數,其實就是把value的地址賦值給了pprintf("Address1?of?a:?%p\n",&value);//打印value的地址printf("Address2?of?a:?%p\n",p);//打印p所代表的地址while(1){?}? }很多人用過返回值是int、char的函數,但是在int,char 后面加個*
估計對于初學者沒有用過。其實就是指針之間賦值。下面就是把p(int*類型的指針) 代表的地址賦值給q
變量之間可以互相賦值吧,指針之間也一樣,可以互相之間賦值。
其實和上面是一樣的道理,那個函數function返回值是一個int*類型的指針,然后賦值給了p而已
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"int?value?=?0; int?*p;//定義一個指針 int?*q;//定義一個指針int?main(void) {?uart_init(115200);//串口初始化delay_init();p=&value;//把value的地址賦值給了p?q=p;//把p代表的地址給qprintf("Address1?of?a:?%p\n",&value);//打印value的地址printf("Address2?of?a:?%p\n",q);//打印p所代表的地址while(1){?}? }姑且再問一句,函數名字是啥?
咱們都知道這樣調用函數
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"void?function() {printf("zhiguoxin\n"); } int?main(void) {?uart_init(115200);//串口初始化delay_init();?function();?while(1){?}? }但是這樣的見過沒
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"void?(*fun)();void?function() {printf("zhiguoxin\n"); }int?main(void) {?uart_init(115200);//串口初始化delay_init();fun?=?function;fun();while(1){?}? }這里采用了函數指針
先記住一句話
“函數名就是這個函數的地址! 函數名就是這個函數的地址! 函數名就是這個函數的地址!
”既然是地址,那么這個地址應該可以賦值給一個指針。因為是函數的地址,所以咱定義的指針也一定是一個函數類型的。
上面的函數void function()是一個沒有返回值,沒有形參的函數。那么咱需要定義一個這種的指針類型,其實就是void (*指針變量名字,隨意寫) ()。上面寫的是 void (*fun)(); fun就是一個函數類型的指針,是一個沒有返回值,沒有形參的函數指針。
咱可以把這種函數賦值給這個指針變量。就是上面的fun=function。那么這個函數指針便代表了那個函數fun就等同于function。所以調用 fun(); 就等同于調用function()。
如果函數有形參怎么辦? 好辦,它有咱就+
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"void?(*fun)(int?a);void?function(int?value) {printf("value=?%d\r\n",value); }int?main(void) {?uart_init(115200);//串口初始化delay_init();fun?=?function;//把function賦值給funfun(520);//fun就等同于functionwhile(1){?}? }如果函數有返回值怎么辦?照+不誤
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"int?res;int?(*fun)(int?a);int?function(int?value) {return?value; } int?main(void) {?uart_init(115200);//串口初始化delay_init();fun?=?function;//把function賦值給funres?=?fun(520);//fun就等同于functionprintf("res?=?%d",res);while(1){?}? }總結一下
指針呢其實基本的也就是上面那些,指針就是用來記錄變量的地址的?;蚴亲龅刂分g的傳遞的。
&代表取地址符。
*代表取數據。
&{變量名} :就是把這個變量的地址取出來。
*{指針變量名} :就是把這個指針所代表的地址里面的存的值取出來
”下面看一些比較常見的應用。把數組的地址賦值給指針,然后用指針操作數組
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"char?temp[3]={1,2,3}; char?*p;int?main(void) {?uart_init(115200);//串口初始化delay_init();p=temp;//將數組名賦值給指針變量p,p就指向數組temp的首地址printf("value0?=?%d\r\n",*p);????//p就代表數組的第一個數據的地址printf("value1?=?%d\r\n",*(p+1));//p+1就代表數組的第二個數據的地址printf("value2?=?%d\r\n",*(p+2));//p+2就代表數組的第三個數據的地址printf("temp[0]?=?%d\r\n",p[0]);//p[0]等同于temp[0]printf("temp[1]?=?%d\r\n",p[1]);//p[1]等同于temp[1]printf("temp[2]?=?%d\r\n",p[2]);//p[2]等同于temp[2]?while(1){?}? }5、函數的形參是一個指針
#include?"sys.h" #include?"led.h" #include?"delay.h" #include?"usart.h"char?temp[3]={1,2,3};void?function(char?*value) {printf("value0?=?%d\r\n",value[0]);printf("value1?=?%d\r\n",value[1]);printf("value2?=?%d\r\n",value[2]); } int?main(void) {?uart_init(115200);//串口初始化delay_init();function(temp);while(1){?}? }以上的指針的基本知識,多練習幾遍就可以。指針真正的應用是在于代碼的封裝。可能對于初學者感受不到其作用,但是當你成為真正的開發人員。你會發現把好多功能函數封裝起來,然后留出接口來調用是以后必不可少的。
轉了嗎贊了嗎在看嗎 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的老司机又开车(来不及解释,快上!)之秒懂单片机指针!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android工具】远程登录会话工具免
- 下一篇: 树莓派小车参考方案,了解一下