怎么样快速的学习吃透C语言之指针?
想学习单片机的同学可以关注、私信我或者在评论区回复我要入门。初学者在C语言的学习过程中遇到的最头疼的知识点大概率是指针,指针在C语言中是非常重要的。下面我们就来了解一下指针的内容。
指针本身是一个变量,它存储的是数据在内存中的地址而不是数据本身的值。它的定义如下:
int a=10,*p;
p=&a
int a=10;
int *p=&a;
首先我们可以理解 int*这个是要定义一个指针p,然后因为这个指针存储的是地址所以要对a取地址(&)将值赋给指针p,也就是说这个指针p指向a。
很多新手都会对这两种定义方法感到迷惑,其实他俩的意思是一样的。第一种定义方法定义了int型的变量a和指针p,然后将a的地址赋给p。第二种是在定义指针p的同时将a的地址赋给指针p。我们姑且理解为" int * "是定义指针的标志。
指针有什么用?
这样我们就可以通过*p来找到指针所指向的变量a的地址,然后对地址中的值(值是10)进行操作。
//接着上面的代码
printf("%p",p) //结果是一个地址(p指向的变量a的地址)。
printf("%d",*p) //结果是10,变量a的值。
printf("%d",&p) //结果是一个地址(指针p的地址,因为指针也是一个变量自己也有地址的)
数组名和指针的区别?
数组名是一个地址,它可以被理解为一个常指针(它只能指向本数组首元素的地址)。而指针可以指其他的变量等等。
int str[5]={1,2,3,4,5};
int *p=str;
printf("%d",*p); //输出为1,数组的首元素。
printf("%d",*str); //输出为1,数组的首元素。
printf("%d",str[0]); //输出为1,数组的首元素。
printf("%p",p); //输出为地址,数组的地址。
printf("%p",str); //输出为地址,数组的地址。
printf("%d",*(p+1)); //输出为2,数组的第二个元素。
printf("%d",*(srt+1)); //输出为2,数组的第二个元素。
对照代码大家可以很清晰的看到数组名在对内存中存储的数据进行操作的方法和结果是一样,但是数组名存储自己数组本身的首地址。
什么是空指针,野指针?
在函数内部对指针进行赋值操作后,在函数执行完毕后,该指针就成了一个空指针(变量从栈中弹出)。但是通过动态地址分配(堆空间)的指针不会有上述问题。
free(p)后释放内存的指针为野指针。
关于const对于指针的限制问题
int a=10,b=20;
int * const p=&a; //无法使p指向其他地址。
p=&b; //这样的操作是不允许的。
*p=20; //可以这样操作。
const int * p=&a; //p可以指向其他地址。
p=&b; //可以操作。
*p=10; //操作不被允许。
const int * const p=&a //p不能指向其他地址,也不能改变地址中的值。
p=&b; //操作不被允许。
*p=20; //操作不被允许。
const在int的左边那就是不能修改地址中的值,在右边就是不能指向其他地址,左右都有那就是既不能修改地址的值也不能指向其他地址。
本期先分享到这里,想要进群学习单片机编程的同学可以私信我,回复“我要入门”,与我们一起成长,喜欢的可以点个赞关注我们!
C语言指针底层原理
如果要选出C语言中最重要、难度大的概念是什么,那就是指针!难度大,意味着使用方便、实用高效,同时也意味这个知识点复杂、实用的时候容易出错。指针用的好,可以提高代码执行效率、节约系统资源;如果用的不好,程序中就会出现一定的问题。
今天我们就来聊一下指针。从最底层的内存存储空间开始,一直到应用层的各种指针使用技巧,循序渐进,以最简洁的语言进行讲解,希望能对你有一点点帮助就够了。
说明:素材难找,为了偷懒和方便讲解和理解,文中配图的内存空间的地址是随便写的,在实际计算机中是要遵循地址对齐方式的。
变量与指针的本质
内存地址
我们编写一个程序源文件之后,编译得到的二进制可执行文件存放在电脑的硬盘上,此时它是一个静态的文件,一般称之为程序。
当这个程序被启动的时候,操作系统将会做下面几件事情:
·把程序的内容(代码段、数据段)从硬盘复制到内存中;
·创建一个数据结构 PCB(进程控制块),来描述这个程序的各种信息
·在代码段中定位到入口函数的地址,让 CPU从这个地址开始执行。
当程序开始被执行时,就变成一个动态的状态,一般称之为进程。
内存分为:物理内存和虚拟内存。操作系统对物理内存进行管理、包装,我们开发者面对的是操作系统提供的虚拟内存。
这 2个概念不妨碍文章的理解,因此就统一称之为内存。
在我们的程序中,通过一个变量名来定义变量、使用变量。
变量本身是一个确确实实存在的东西,变量名是一个抽象的概念,用来代表这个变量。
那么,我们定义一个变量之后,这个变量放在哪里呢?那就是内存的数据区。
内存是一个很大的存储区域,被操作系统划分为一个一个的小空间,操作系统通过地址来管理内存。
内存中的最小存储单位是字节(8个 bit),一个内存的完整空间就是由这一个一个的字节连续组成的。
32位与 64位系统
我们平时所说的计算机是 32位、64位,指的是计算机的 CPU中寄存器的最大存储长度,如果寄存器中最大存储 32bit的数据,我们就叫作32位系统。
在计算机中,数据一般都是在硬盘、内存和寄存器之间进行来回存取。CPU通过 3种总线把各组成部分联系在一起:地址总线、数据总线和控制总线。地址总线的宽度决定了 CPU的寻址能力,也就是 CPU能达到的最大地址范围。
刚才说了,内存是通过地址来管理的,那么 CPU想从内存中的某个地址空间上存取一个数据,那么 CPU就需要在地址总线上输出这个存储单元的地址。
假如地址总线的宽度是 8位,能表示的最大地址空间就是 256个字节,能找到内存中最大的存储单元是 255这个格子。即使内存条的实际空间是 2G字节,CPU也没法使用后面的内存地址空间。如果地址总线的宽度是 32位,那么能表示的最大地址就是 2的 32次方,也就是 4G字节的空间。
【注意】这里只是描述地址总线的概念,实际的计算机中地址计算方式要复杂的多,比如:虚拟内存中采用分段、分页、偏移量来定位实际的物理内存,在分页中还有大页、小页之分。
变量
我们在 C程序中使用变量来“代替”一个数据,使用函数名来“代替”一个函数,变量名和函数名是程序员使用的助记符。变量和函数最终是要放到内存中才能被 CPU使用的,而内存中所有的信息(代码和数据)都是以二进制的形式来存储的,计算机根据就不会从格式上来区分哪些是代码、哪些是数据。CPU在访问内存实际上是访问地址,而不是访问变量名、函数名。
在程序代码中使用变量名来指代变量,而变量在内存中是根据地址来存放的,这二者之间是通过编译器映射(关联)起来的。
变量有 2个重要属性:变量的类型和变量的值。
示例:代码中定义了一个变量
int a = 20;
类型是 int型,值是 20。这个变量在内存中的存储模型为:
我们在代码中使用变量名a,在程序执行的时候就表示使用 0x11223344地址所对应的那个存储单元中的数据。
因此,可以理解为变量名 a就等价于这个地址 0x11223344。换句话说,如果我们可以提前知道编译器把变量 a安排在地址 0x11223344这个单元格中,我们就可以在程序中直接用这个地址值来操作这个变量。
在上图中,变量 a的值为 20,在内存中占据了 4个格子的空间,也就是 4个字节。为什么是 4个字节呢?在 C标准中并没有规定每种数据类型的变量一定要占用几个字节,这是与具体的机器、编译器有关。
比如:32位的编译器中:
char: 1个字节;
short int: 2个字节;
int: 4个字节;
long: 4个字节。
比如:64位的编译器中:
char: 1个字节;
short int: 2个字节;
int: 4个字节;
long: 8个字节。
为了方便描述,下面都以 32位为例,也就是 int型变量在内存中占据 4个字节。
另外,0x11223344,0x11223345,0x11223346,0x11223347这连续的、从低地址到高地址的 4个字节用来存储变量 a的数值 20。
在图示中,使用十六进制来表示,十进制数值 20转成 16进制就是:0x00000014,所以从开始地址依次存放 0x00、0x00、0x00、0x14这 4个字节(存储顺序涉及到大小端的问题,不影响文本理解)。
根据这个图示,如果在程序中想知道变量 a存储在内存中的什么位置,可以使用取地址操作符&,如下:
printf("&a = 0x%x \n", &a);
这句话将会打印出:&a = 0x11223344。
考虑一下,在 32位系统中:指针变量占用几个字节?
指针变量
指针变量可以分 2个层次来理解:
·指针变量首先是一个变量,所以它拥有变量的所有属性:类型和值。它的类型就是指针,它的值是其他变量的地址。既然是一个变量,那么在内存中就需要为这个变量分配一个存储空间。在这个存储空间中,存放着其他变量的地址。
·指针变量所指向的数据类型,这是在定义指针变量的时候就确定的。例如:int *p;意味着指针指向的是一个 int型的数据。
在 32位系统中,一个指针变量在内存中占据 4个字节的空间。因为 CPU对内存空间寻址时,使用的是 32位地址空间( 4个字节),也就是用 4个字节就能存储一个内存单元的地址。而指针变量中的值存储的就是地址,所以需要 4个字节的空间来存储一个指针变量的值。
示例:
int a = 20;
int *pa;
pa = &a;
printf("value = %d \n", *pa);
在内存中的存储模型如下:
4.在返回到STM32CubeMX后,在Pinout&Configuration里面的pinout view,点击选择PA8 PIN脚,在弹出的小框里面选择RCC_MCO,使得PA8作为MCO输出PIN脚。同样地方式,设置PA1为GPIO Output。
5.本期先分享到这里,想要进群学习单片机编程的同学可以私信我,回复“我要入门”,与我们一起成长,喜欢的可以点个赞关注我们!
相关问答
一直没明 单片机C 语言的 指针 这块内容,在什么情况下会用到 指针 呢?作为一名长期使用C语言进行开发的老司机,我来回答一下C语言指针的问题。首先、C语言指针的本质是什么?C语言指针的本质是内存变量,是内存单元的编号。内存单...
51 单片机 的数据 指针 是什么?51架构单片机指针是C语言的灵魂,更是控制单片机的利器指针是变量:时刻记住,指针也是变量类型的一种,和intcharfloat一样,创建指针后,会在内存空间(RAM...
8位 单片机 的 指针 占几个字节?在8位单片机下,指针大小一般为1个字节。这是因为指针的大小主要与系统的寻址能力有关,而并非与具体语言相关。例如,如果系统是16位地址,那么指针就是2个字节...
51 单片机 的堆栈 指针 sp始终是指向?我学的是单片机。在堆栈里,sp加一,然后入栈;出栈,然后sp减一。所以新开的和销毁的内存都是当前sp指向的。我没学过编程思想,硬来答,或许不好,但是我坚信单...
本人小白,想学 单片机 ( C 语言编程),怎么入手?我做单片机开发8年了,那时初中毕业没考上高中,然后直接去上了技校读了5年,读的专业是电梯,然后觉得没前途就自学了单片机,那时我先学习的是51和C语言,C语言...
51 单片机 里面的地址 指针 DPTR和工作寄存器组有什么作用?都有一些什么样的功能?都用在什么地方?如果是用c语言编程,可以不必注意这些问题,因为编程软件会自动帮你分配,也不容易出错!!数据指针DPTR是80C51中一个功能比较特殊的寄存器。从结构DPTR是一个1...
C 中是什么意思- 汇财吧专业问答[回答]逻辑运算符单独使用,意思为“非”boolc=(a==b);if(,“.关系运算符,和“=”在一块使用有两个用法1!=b){}2!=”表示不等于if(ac+=2意思是c=c+2code...
51 单片机 汇编堆栈 指针 sp的活动范围一般是ram的哪个区域?问题...[最佳回答]举个例子:SP的初始化值是07H,SP从08H开始增加.当程序需要压栈操作时,就将程序的PC值压入堆栈,注意PC是两个字节的指令.先压入低字节,在压入高字节;...
C 中是什么意思- 汇财吧专业问答[回答]c+=2意思是c=c+2code是keilC51里面的关键字,一般用于定义常量数组,意思是告诉编译说把这个数组放在ROM存储。code的作用是告诉单片机,定义的数据要...
51 单片机C 语言编程,简易计算器,复位键如何编程会简单些?要求...void(*RecallBp)(void);main(){保存堆栈指针clear:RecallBp=(void*)&clear;恢复堆栈指针初始化.....}需要返回时...