底层驱动的操作离不开指针,驱动程序的目的是为了管理硬件,驱动程序管理硬件的媒介是寄存器(一种特殊的内存),通过对寄存器的读写,实现对硬件的功能设置以及数据的存取。
1.1 什么是指针
1.1.1 普通变量
普通变量的目的是为了存放普通数据,对于变量空间来说,不管是读还是写,变量是存放数据的手段。
1.1.2 指针变量
在大多数情况下,指针指的是指针变量,指针变量存放的数据是内存地址。一般情况,如果不考虑强制转换,要求某个类型地址必须放到对应类型的指针变量中,如下所示
int a = 10;
int *p = &a;
1
2
指针变量p里面存放的地址指向了空间a,&a代表的是第一个字节的地址。
变量空间的首字节地址,作为整个空间的地址
(1)指针变量的类型作用
类型是由普通变量+星号构成,星号的个数表明指针变量的级数。使用指针的目的是为了更加方便地访问空间。
(2)为什么需要指针
地址是扩大变量或者函数作用域的有效手段
1.1.3 指针使用三部曲
(1)定义(声明)
int *p = NULL; //初始化一下,防止野指针
1
(2)关联
int a = 10;
p = &a; //a空间的首地址给了p,所以p里面的地址常量指向a空间
1
2
(3)引用
读空间:读值操作,前提是里面有数据才行
int b = *p; //等价于b=a
1
写空间:向空间写值
*p = 30 ; //等价于a=30
1
1.2指针符号
1.2.1星号*
(1)用在指针定义时,与前面的类型结合,用于表示被定义指针变量的类型,星号的个数表示定义的指针变量的级数。
(2)解引用时, * p表示p所指向的空间,这时的* 称为取空间操作,找到p所指向的空间。* 作为解引用时,得到的p所指向的空间后,有两种用途:一是读空间内容,二是向空间写入新的内容。
1.2.2取地址符&
表示变量空间的首地址,准确地讲是变量的首字节地址
1.2.3指针变量的初始化和指针变量赋值的区别
初始化只能有一次,而赋值可以有多次
1.2.4左值和右值
左值都是变量空间,最左值执行的操作都是写空间操作;
右值可以直接写入一个数值,又可以是一个变量;
当变量作为左值时,对变量实现的是写操作,当变量是右值时,对变量实现的是读操作。
1.3野指针和段错误
1.3.1什么是野指针
所谓的野指针,是指针指向一个不确定的地址空间,或者虽然指向一个确定的地址空间,但引用空间的结果是不可预知的。
//p是自动局部变量,由于p没有被初始化,也没有被赋值,
那么p中存放的是一个随机值,所以p指向的空间地址是不确定的
int main (void)
{
int *p;
*p = 10;
return 0;
}
1
2
3
4
5
6
7
8
//p虽然指向一个确定的地址0x12232142135435的空间,但它对应的
空间是否存在,其读写权利是否满足程序的访问要求,都是未知的
int main (void)
{
int *p = 0x12232142135435;
*p = 10;
return 0 ;
}
1
2
3
4
5
6
7
8
1.3.2 野指针的危害
(1)引发段错误
段错误
1)什么是段错误
段错误本质上是指针错误(地址错误),因为C语言内存结构是由不同的内存段组成的,所以指针错误又称为段错误。
2)产生段错误的原因
大段错误:指针变量指向的地址空间根本不存在
小段错误:指针变量指向的地址空间存在,但对应该空间的操作权限受到限制
(2)未产生任何结果
(3)引发程序连环式错误
1.3.3野指针产生的原因
(1)使用指针前,忘记将指针变量初始化或复制一个有校的空间地址,导致指向不确定
(2)不清楚地址空间的访问权限
(3)访问空间是,内存越界导致野指针
1.3.4 如何避免野指针
(1)定义指针变量时,将其值赋值为NULL
(2)在使用指针变量前,对指针变量初始化或赋值,指向一个有效且确定的空间
(3)检查指针的有效性,使用指针前,做指针是否为空的判断
1.4 指针类型和强制类型转换
类型对于编译器来说,主要就是用于说明数据存储空间的大小以及数据的存储结构。
类型 字节
char 1
short 2
int 4
float 4
double 8
1.4.1 数据的存入和读取
(1)利用变量名或者直接利用地址,找到空间首地址
(2)根据类型制定的空间大小,从首字节地址开始,找出向后顺序延长后的空间大小
(3)按照类型数据存储格式要求,将数据写入空间或从空间读出
1.4.2 普通变量的强制转换
是将数据的空间大小和数据的存储结构转变后,存入另一个变空间。一般具有相同的存储结构,从小空间向大空间转换,数据不会丢失,short-int,float-double。从存储结构简单的数据向存储结构复杂的数据类型转换(比如int-float),只能说数据可能不会丢失,但反过来一定会导致数据丢失。
隐式数据类型转换
(1)“=”
(2)返回值
显式数据类型转换
所谓的显示强制转换,就是明确的告诉编译器我们的意图。
1.4.3 指针变量数据类型
一是说明变量本身的类型,二是说明指向变量的类型
指针变量数据类型的强制转换
对指针来说只有显式强制类型转换,不能使用隐式强制类型转换
(1)指向空间的强制类型转换
*pa = (int) *pb; //等价于a=(int)b
本质上就是普通变量的强制类型转换
(2)指针本身的强制类型转换
pb = (float * )pa; //或者pb = (float * )&pa
指针变量类型本身的强制转换,改变是对其指向空间的引用方式指针本身强制类型转换需注意一下问题:
1)引用空间大小的变化
指针变量做强制转换时,多数情况只会将引用空间缩小,而不会将引用空间扩大。防止引用别的空间,导致内存越位操作。
2)引用空间时数据结构变化
数据访问乱码
1.5 二重指针
1.5.1 二重指针的本质
和普通指针的差别就是它指向的变量类型是一个一重指针,二重指针起始也是一种数据类型,编译器在编译时会根据二重指针的数据类型来做静态类型检查,一旦返现运算时数据类型不匹配,就会报错。
1.5.2 二重指针的用法
二重指针存放一重指针地址;
二重指针可以指向指针数组;
大部分和指针数组结合使用;
在函数传参时为了通过函数内部改变外部的一个指针变量,会换地这个变量的地址(也就是二重指针)进去。
---------------------
作者:超级峰
来源:CSDN
原文:https://blog.csdn.net/weixin_40569915/article/details/84478479
版权声明:本文为博主原创文章,转载请附上博文链接!