击上方“果果小师弟”,选择“置顶/星标公众号

干货福利,第一时间送达!

摘要:大家想过没有我们用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){ }
}

总结一下

指针呢其实基本的也就是上面那些,指针就是用来记录变量的地址的。或是做地址之间的传递的。

&代表取地址符。

*代表取数据。

&{变量名} :就是把这个变量的地址取出来。

*{指针变量名} :就是把这个指针所代表的地址里面的存的值取出来

下面看一些比较常见的应用。把数组的地址赋值给指针,然后用指针操作数组

#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){ }
}

以上的指针的基本知识,多练习几遍就可以。指针真正的应用是在于代码的封装。可能对于初学者感受不到其作用,但是当你成为真正的开发人员。你会发现把好多功能函数封装起来,然后留出接口来调用是以后必不可少的。

转了吗赞了吗在看吗

老司机又开车(来不及解释,快上!)之秒懂单片机指针!相关推荐

  1. 苹果无线笔记本怎么连不上win服务器,老司机还原苹果笔记本电脑连接不上wifi该的办法?...

    老司机还原苹果笔记本电脑连接不上wifi该的办法? 使用Mac苹果电脑过程中偶尔碰到wiFi无法连接的问题,这是怎样回事?经过检查发现是与路由器模式设置有关,原因大多因为路由器的协议与苹果电脑不一致导 ...

  2. 史上最污技术解读,老司机瞬间开车!

    本文经授权转载自公众号 特大号 假设你是个妹子,你有一位男朋友,于此同时你和另外一位男生暧昧不清,比朋友好,又不是恋人.你随时可以甩了现任男友,另外一位马上就能补上.这是冷备份. 假设你是个妹子,同时 ...

  3. 程序员老司机“随意开车”,恶搞代码让你分分钟玩死程序员!

    1.问题描述 在屏幕上画出奥运五环旗 整人代码: 你打开好友的聊天对话框,然后记下在你QQ里好友的昵称,把下面代码里的xx替换一下,就可以自定义发送QQ信息到好友的次数(代码里的数字10改一下即可). ...

  4. 审车按月还是日期_@老司机,你该审车了,秒懂的审车攻略,快快揣口袋吧

    审车迎来旺季!! 近日高温持续发酵 其中还夹杂着暴雨天气 这让外出的每一时刻都成了一种折磨 一想到还要排队审车就头皮发麻 别怕 为提高审车服务质量,节省车主的宝贵时间 淄博鲁中检测正式启动 小程序审车 ...

  5. 程序员才是真正的“老司机”,30个IT术语这样解释,新手秒懂

    ​因为程序员工作的特殊性,在很多人眼里敲代码的人一般都比较木讷,话很少,给人一种智商高.情商低的感觉.只有深入了解程序员圈子的人才会知道,这些话少木讷的背后其实都是万里挑一的有趣灵魂.不仅会说段子,而 ...

  6. 老司机谈APK瘦身套路-项目优化篇

    老司机谈APK瘦身套路-项目优化篇 在上一篇文章中,老司机带领大家一起学习了图片资源的瘦身套路,收到了很多中学生读者的好评. 想了解的童鞋请点击:blog.csdn.net/mynameishua-  ...

  7. 老司机们学习STM32的技巧

    单片机用处这么广,尤其是STM32,这么火!如何快速上手学习呢? 你问,如何系统地入门学习stm32? 这本身就是一个错误的问题.假如你会使用8051 , 会写C语言,那么STM32本身并不需要刻意的 ...

  8. 新手必看一位老司机的十年开车经验

    今天,小编为大家收集整理了一个老司机的十年开车经验,新手们一定要学哦,因为这种宝贵的开车经验是我们以后开车过程中每天都要用到的常识.将来无论在什么时候,这种宝贵经验都会给我们带来更安全的行车时光. 新 ...

  9. 名悦集团:开车从不追尾,老司机分享驾驶避免事故小知识

    听交通广播,我们几乎每天都能听到高速路上,高架桥上,上班路上发生追尾事故,有时候是个平常的上下班高峰期.很多人会纳闷,车开的好好的,怎么就会发生追尾事故呢.开车在路上,难免会有磕磕碰碰.道路千万条,安 ...

最新文章

  1. UITableView学习笔记
  2. Nuget服务的搭建-打包-上传-删除
  3. TCP/IP详解--学习笔记(1)-基本概念
  4. msra数据集_ACL2020 | 香侬科技提出使用Dice Loss缓解数据集数据不平衡问题
  5. 初识HTML和WEB标准
  6. windows下获取IP和MAC地址
  7. Redis学习总结(3)——Redis整合Spring结合使用缓存实例
  8. apt-get update : pulic key error
  9. nginx IP 443 路由到其它地址
  10. 设置win10有线网络连接
  11. 武汉理工大学计算机考研专业代码,武汉理工大学代码及专业代码
  12. 苹果ipad有哪几款_别再乱买了!一篇文章讲清楚不同型号iPad之间的区别
  13. 程序员打造影响力常犯的 3 个错
  14. Centos7安装Docker并配置镜像加速器
  15. APP在后台被系统回收后,如何重新启动
  16. 二、生理信号处理 ——1.心电信号(含Matlab代码及数据)
  17. 钉钉桌面版(dingtalk)介绍:支持Linux、Windows和macOS平台
  18. 猿创征文|Java中的IO流大家族 (两万字详解)
  19. 携创教育:自考英语二可以不考吗?与英语四级哪个更难?
  20. 跨境运营培训班亚马逊产品视频如何上传

热门文章

  1. poj2718 Smallest Difference
  2. 4月13日学习笔记——jQuery动画
  3. Swift基础之控制语句
  4. hibernate和spring学习
  5. 必须要改变这样的生活
  6. MakeFile 文件的作用
  7. js动态改变下拉菜单内容示例 .
  8. IOS 多线程的一些总结
  9. UA OPTI570 量子力学4 带不含时的标量势的粒子的薛定谔方程
  10. win7构建成功helloworld驱动、WDF驱动中KMDF与UMDF区别