指针可以说是c语言从汇编那继承下来的!C语言中指针就跟汇编中的直接寻址,间接寻址等一样,去自直接操作内存;直接去操作内存,效率更高;
指针是C语言中的精华,在C语言中很多地方都会用到指针(函数传参,函数返回值等);指针让程序员可以写出高的数据结构,编写出简洁,紧凑,高效的程序;
所以要想熟练的使用C,指针是必不可少的;
注意:在32位的操作系统中,不管定义的是什么类型的指针都是4字节;
1. 指针带来的一些符号的理解
1. 星号* :
(1)定义指针:*和前面的类型结合,定义一个该类型的指针(int *p;定义一个int类型的指针)
(2)解引用:解引用时*p表示的是p所指向的变量;(p = &a;当操作*p时相当与操作变量a)
2.取地址符&:
(1)&a 表示变量a的内存地址;
(2)取地址符使用时直接加在一个变量的前面,取地址符和变量重新构成一个新的符号,表示这个变量的内存地址(int a = 32; int *p =&a;//将a的地址赋值给p;当下次解引用p时,相当与操作变量a)
2. 指针定义并初始化,与指针定义然后赋值的区别
1.指针定义并初始化:
1 int a = 32; 2 int *p = &a;
2.指针定义然后赋值:
1 int a = 32; 2 int *p; 3 p = &a;
3. 野指针的问题
1.野指针带来的危害:
(1)野指针就是指针指向的位置是不可知的(随机的,不正确的,没有明确限制的)
(2)野指针很可能运行时触发段错误(Sgmentation fault)
(3)因为指针变量在定义时如果没有初始化,值是随机的。指针变量的值其实就是别的变量(指针所指向的那个变量的地址),也就意味着这个指针变量很可能指向该程序中的某一个变量的地址,当这时去解 引用这个指针时将会改变这个被指向的变量;可能导致程序发生未知的错误;
2.怎么避免野指针
(1)野指针的错误来源就是指针在定义时没有初始化,也没有给赋值(也就是没有让指针指向一个可用的内存空间),然后就直接进行解引用;
(2)明白了野指针的来源,解决方法就是:在指针的解引用之前,一起确保指针指向一个绝对可用的空间。
(3)常规避免野指针的作法:
1.定义指针时,同时初始化为NULL
2.在指针使用之前,将其赋值绑定给一个可用的地址空间
3.在指针被解引用之前,先去判断这个指针是不是NULL
4.指针被解引用之后,将其赋值为NULL
1 int *p = NULL; //定义指针,并初始化为NULL 2 3 int a = 4; //定义一个变量 4 5 p = &a; //将a的地址与指针p绑定起来 6 7 if(NULL != p) //指针解引用之前,判断指针是不是NULL,是不是有绑定有效的地址 8 { 9 *p = 10; //指针p解引用 10 } 11 12 p = NULL; //指针解引用后,将其赋值为NULL
附件内容:为什么要将指针初始化为NULL?
1.NULL的实质就是0,然后给指针赋初值NULL,其实就是让指针指向0地址处;
2. 0地址处作为一个特殊的地址(我们认为指针指向0地址,就表明该指针没有被初始化,表明这是一个野指针);
3. 0地址在一般的操作系统中都不可被访问,这也就表示当指针被指向0地址时,不会在随机的指向其它的地址,也就不会不知不觉的操作其它未知的内存地址;
4. const关键字与指针
1. const修饰指针的4种形式
1.const关键字,在C语言中用来修饰变量,表示这个变量是一个常量;
2.const修饰指针的以下4种形式:
1 const int *p; //表示p不是const,而p指向的变量是const(常量) 2 int const *p; //表示p不是const,而p指向的变量是const(常量) 3 int * const p; //表示p是const,而p指向的变量不是const(常量) 4 const int * const p;//表示p是const,而p指向的变量也是const(常量)
3.关于指针变量的理解,主要涉及到2个变量:第一个是指针变量p本身,第二个是p指向的那个变量(*p)。一个const关键字只能修饰一个变量,所以弄清除这4个表达式的关键就是弄清
楚const在表达式中修饰的是哪个变量;
1.const int *p; //const修饰的是*p(也就是p所指向的那个变量(*p))
2.int const *p; //const修饰的是*p(也就是p所指向的那个变量(*p))
3.int * const p; //const修饰的是p(也就是p指针变量本身)
4.const int * const p; //前面的const修饰的是*p,后面的const修饰的是p;
5. 理解数组中a, &a, &a[0], a[0]的区别;
例如:int a[5];
1.a表示的是数组名,a做左值时表示的是a[5]这个数组的整个内存空间(5*4=20字节);但是C语言中规定数组操作时要独立操作,不能整个数组一起操作,所以a不能做左值;a做右
值时,表示数组首元素(也就是a[0])的首地址,a做右值时相当于&a[0](两者的数值是一样的);
2.&a就是数组名a取地址,就是数组的地址;&a不能做左值(&a实质是一个常量,仅仅是表示这整个数组的首地址,不是变量所以不能赋值,也就不能做左值);&a做右值时,表示整个数组
内存空间的首地址;在数值上与a,&a[0]是一样的;
3.&a[0]表示的是数组首元素(a[0])的首地址([]的优先级高于&,所以a先和[]结合再去地址);&a[0]是不能做左值的,&a[0]是a[0]的首地址是一个常量;做为右值时,表示的是
a[0]的首地址;
4.a[0]表示数组的首元素;做左值时表示a[0]对应的连续4字节空间;做右值时表示的是a[0]对应内存空间中存放的值;
总结:
1.&a和a做右值时的区别:&a是整个数组的首地址,而a是数组首元素的首地址。这两个在数值上是相等的,但是意义不同,意义不同会导致他们在参与运算时有不同的表现;
2.a和&a[0]做右值时意义和数组完全相等,完全可以互相替代;
3.&a是常量,表示整个数组内存空间的首地址,不能做左值;
4.a做左值代表整个数组所以空间,所以不能做左值;
参考内容:朱老师物联网大讲堂