一、了解什么是指针
第一点: 指针并不可怕,指针其实只是地址,由于通过地址可以找到它所对应的内存单元,就可以说地址指向了一个内存单元,所以就把地址形象化的说成指针。 地址指向一个内存单元,管理着一个内存单元,即可以对内存单元进行访问。 变量向内存申请空间之后,申请到的空间的名字就是变量名,地址指向变量名,意思就是指向了那一块空间。 通过地址,就可以找到内存单元,打个比方,将地址比作门牌号,只要知道了门牌号,根据门牌号就可以找到对应房间。 *,这个解引用操作符,就相当于“找”这个动作,根据这个门牌号去找对应的房间去。 第二点: 得到一个地址之后,将他保存到一个变量中,这个变量就叫做指针变量。 指针变量和普通的变量没有任何区别,普通变量保存一个值,指针变量也是为了保存一个值,只不过值是地址,地址又形象化的理解为指针,所以这个变量就叫做指针变量。 对指针变量操作时,其实就是对存放在里面的地址操作 打个比方,将水倒在瓶子里面,拿起瓶子这个动作,其实也就是拿起了水。 我们口头语说的指针其实是指针变量。 以下有几个问题解答:
1:为什么内存会分为很多个内存单元? 2:为什么一个内存单元会对应一个地址? 3:地址是如何产生的? 4:指针变量在内存中所申请的空间是多大?
1:为什么内存会分为很多个内存单元? 在一台电脑中,内存是很大的,有4G和8G或者更大,对一整个内存进行管理,是不方便的,将内存分为一个一个的内存单元,对每一个内存单元分别管理,就很方便了。 打个比方说,将这内存比作一栋楼房,此时这一栋楼房就是一整个房间,向这里面放东西,很多件东西全放在一个房间里了,如果将来要找东西是不是不好找?所以就将这一栋楼房分成很多个房间,对每一个房间进行管理,将东西放到一个一个的房间里面,将来要找东西时,也就好找。所以就将内存分成很多个内存单元,方便进行管理。
2:为什么一个内存单元会对应一个地址? 上文说到将内存分为一个一个的内存单元,对每一个内存单元管理,如何分别进行管理呢?如何去找到想要的那个内存单元呢? 为了满足上面的要求,所以将每一个内存单元进行编号,通过编号,就可以对内存单元进行管理,就可以找到内存单元,这个编号就是地址,通过地址就可以找到内存单元,就可以对内存单元管理。 打个比方说,内存比作一栋楼房,将楼房划分出很多个房间之后,每个房间就相当于一个内存单元,如何对每个房间管理?如何找到每一个房间? 通过对房间进行编号,每一个房间对应一个门牌号,通过门牌号就可以找到每一个房间。 所以就将每个内存单元编号,通过编号就可以找到对应的内存单元,对内存单元进行管理,这个编号就是地址。
3:地址是如何产生的? 地址是由一组二进制数组成的,这二进制数是由电信号转化为数字信号形成的,电信号是由地址线通电形成的。 地址线决定了地址的个数和位数。 位数:地址线有多少根,一个地址就有多少位 地址是由二进制数组成的,一根地址线能产生一位二进制数,如果地址线有32根,则地址就有32位,如果地址线有64根,则地址就有64位。 个数:地址线联合起来会产生多少种组合,就有多少个地址 如果地址线有32根,一根产生的二进制数有两种可能,可能是0或者1,两根地址线联合产生的二进制数的组合有2的2次方种,所以32根地址线来拟合产生的二进制数的组合有2的32次方种,这一种组合就对应着一个地址。
4:指针变量在内存中所申请的空间是多大? 指针变量是存放地址的,地址需要占用多少空间,指针变量就会申请的空间就有多大。 打个比方说,一个人要穿鞋,他的脚有多大,鞋就要做多大的,所以说地址要占用多大,指针变量就要有多大。 地址如果是由32位的二进制数组成,32位二进制数是32个比特位的大小,一个字节=八个比特位,所以地址的大小是4个字节的大小,所以存放时,指针变量要申请四个字节大小的空间,进行存放指针。 地址如果是由64位的二进制数组成,64位二进制数是8个字节的大小,所以地址的大小是八个字节的大小,所以存放时,指针变量要申请8个字节大小的空间,进行存放。
二、指针类型
指针类型可以比作社会上的大哥,将指针(地址)比作小弟,大哥对小弟具有管理权。
学习指针类型之前,应该先明白两件事: 一个地址对应一个内存空间,管理一个内存空间。 指针变量和地址是一样的,指针变量只不过只是存放了地址而已,它只是有个存储的功能,仅此而已。对指针变量的操作,就是对地址的操作。 指针类型对指针变量的操作其实也就是对地址的操作,为了方便理解,我们这里直接以地址为例子,进行操作。
指针类型规定地址的两个方面 第一个方面:规定了地址可以访问多少个字节大小的空间。 一个地址对应一个字节大小的空间,一个地址可以访问一个字节大小的空间。如果是int类型修饰地址,则规定指针对应四个字节大小的空间,可以访问四个字节大小的空间。 第二个方面:当地址+1时,规定了地址可以跳多少个字节大小的空间。 原本地址对应一个字节大小的空间,对地址+1,就是要找到下一块内存空间对应的地址,上一个地址对应一个字节大小的空间,所以地址跳过一个字节大小的空间,指向下一个字节大小的空间。 当地址被int*这个指针类型管理第一个方面之后,一个地址对应四个字节大小的空间,对地址+1,就是要找到下一块内存空间所对应的地址,上一个地址对应四个字节大小的空间,所以地址应该跳过四个字节大小的空间,指向下一块四个字节大小的空间。
三、野指针
1、野指针的定义
野指针的定义:指针变量里的地址所指向的内存空间是不确定的,不正确的,没有明确限制的。 打个比方说:指针就是地址,对于地址来说,将地址比作孩子,如果孩子的家是不正确的,不确定的,随机的,这个孩子就是野孩子。 重点就是要看这个孩子的家。
2、野指针形成的原因
形成野指针有三种情况:
1:指针变量没有初始化,没有向指针变量里面放地址。 如果没有初始化,编译器就会自动向变量里面放随机值,在对指针变量解引用之后,这个随机值所对应的空间是随机的,编译器没有向内存申请,不属于编译器,没有使用权限。 >打个比方:将地址比作孩子,如果这个孩子是从天上掉下来的,那这个孩子的家就是随机的,哪都有可能是他的家,不知道将这个孩子送到哪里,那这个孩子就是野孩子。 2:指针变量越界访问 指针变量中的地址所对应的空间不是我们申请到的空间,这个空间不属于我们。 >打个比方:将地址比作孩子,我们得到的这个孩子的家,不归我们管,我们没有办法将孩子送回去,这个孩子就成了野孩子。 3:指针变量里的地址所指向的空间被释放 空间被释放之后,那个空间就不属于我们了,没有了对那一部分空间的使用权 >打个比方:将地址比作孩子,我们得到的孩子的家,原来是归我们管的,但是后来不归我们管了,也无法送孩子回家,孩子就变成了野孩子。
2、如何避免野指针
1:对指针变量初始化 2:小心指针变量越界访问 3:在函数中,避免返回局部变量的地址。
四、指针变量的运算
1、指针变量的加减
指针变量的加减就是对地址的加减,对地址+1,意味着找到下一个地址,地址由于被指针类型修饰,意味着地址管理n个字节的空间,对地址+1,意味着找到接着管理后面n个字节的空间的地址。 对地址+1,就意味着这个地址要跳过n个字节的空间,对地址+2,意味着这个地址要跳过2n个字节的空间,跳过之后,这个地址所对应的内存空间不对,所以地址变成此时内存空间所对应的地址。
2、指针与指针的运算
指针与指针相减,就是两个地址相减,地址相减得到的结果是两个地址之间的元素个数。
五、指针和数组
指针变量和数组两者没有关联,但将数组名放到指针变量中,两者就有了关联,数组名代表首元素的地址。 指针变量得到数组中首元素的地址,指向了数组,对指针变量解引用可以对数组进行访问。 首元素的地址对应着首元素的内存空间,可以访问首元素的内存空间,通过对地址+1,就可以得到下一个元素的地址,指向下一个元素的内存空间,对内存空间进行访问,依次进行,就可以对数组完全访问完。
|