间接赋值才是指针存在的最大意义,指针做函数的参数才是指针的真谛
指针类型(*):指针是为内存服务的。指针指向谁就把谁的内存地址赋给指针。
1.
指针也是一种变量,占有内存空间,用来保存内存块的地址
2.
*p操作内存:在指针声明时,*号表示所声明的变量为指针;在指针使用时,*号表示 操作 指针所指向的内存空间中的值;*p相当于通过地址(p变量的值)找到一块内存;然后操作内存;*p放在等号的左边赋值(给内存赋值);*p放在等号的右边取值(从内存获取值);
3.
指针变量和它指向的内存块是两个不同的概念,指针地址和指针地址批向的内存需要严格区分
4.
指针是一种数据类型,是指它指向的内存空间的数据类型,因为数据类型不一样,导致指针移动的步长才会不一致。
5.对于C++编译器来说,指针只是一个变量,不管是一个*还是多个*的指针,C++编译器只会分配4个字节的内存。
注意:*表示指针,p表示指针变量,p指向的内存存放的是一个地址,*p是指针p的地址指向的内存的内容。给指针变量赋值,就是不断的改变指针的指向。释放指针指向的内存块时,指针指向的地址必需是内存块的首地址。
操作符
取地址运算符&(取变量的地址)与指针运算符*(从某个地址中获取数据),两者互为逆运算
指针的理解:
1.
一 个基本的数据类型(包括结构体等自定义类型)加上“*”号就构成了一个指针类型的模子。这个模子的大小是一定的,与“*”号前面的数据类型无关。“*”号 前面的数据类型只是说明指针所指向的内存里存储的数据类型。所以,在32 位系统下,不管什么样的指针类型,其大小都为4byte。可以测试一下sizeof(void *)。
2.
对指针进行加
1
操作,得到的是下一个元素的地址,而不是原有地址值直接加
1,所以
一个类型为
T
的指针的移动,以
sizeof(T)
为移动单位。
使用:
1.
定义指针变量
的同时最好初始化为
NULL,用完指针之后也将指针变量的值设置为
NULL。也就是说除了
在使用时,别的时间都把指针“栓”到
0 地址处。这样它就老实了。
2.通过建立指针数组和行指针引用二维数组。
常见内存错误及对策:
1.指针没有指向一块合法的内存:结构体成员指针没有初始化、没有为结构体指针分配足够的内存、函数入口校验(使用指针前一定要保证指针是有效的)
2.为指针分配的内存太小:注意字符串常量末尾的'\0';
3.内存分配成功,但并未初始化:定义变量的时候第一步就进行初始化 操作,如:
char *p = NULL
;
int a[10] = {0};
4.内存越界:一般是边界问题
5.内存泄漏:malloc的使用
6.内存释放:free() 斩断指针变量与这块内存的关系,在程序中malloc 的使用次数一定要和free 相等,否则必有错误;
7.内存释放之后:使用free 函数之后指针变量p 本身保存的地址并没有改变,我们需要重新把p的值变为NULL;释放完块内存之后,没有把指针置NULL,这个指针就成为了“野指针”:
间接赋值成立的条件:
1.参数定义:主调函数定义实参和形参;
2.建立关联:把实参地址传给形参;
3.间接赋值:在被调函数通过形参间接地修改实参的值;
应用场景:
1.3个条件都在一个函数里面,如通过指针循环给能数组赋值
2.条件1和2放在一个函数里面,条件3放在另一个函数里面,如下面的例子:
间接赋值的工程意义:
用1级指针(形参),去间接修改0级指针(实参)的值;
用2级指针(形参),去间接修改1级指针(实参)的值;
......
用n级指针(形参),去间接修改n-1级指针(实参)的值;