C语言指针详解一

正文开始

一、内存和地址

再讲之前,我们以一个生活中的案列来理解什么是内存和地址。

假设有一栋宿舍楼,楼上有100个房间,但是房间没有门牌号,这时有个朋友来找你,只能一间一间的找,这样效率就很低,如果可以根据楼层的情况,按照楼层给每层的每个房间编号如:、

一楼:101   102    103    104

二楼:   201   202    203    204

有了房间编号,你的朋友就会很快的找到你。

对比计算机,我们都知道计算机中的cpu在处理数据时,要从内存中读取数据,处理完毕后放回内存中,我们买电脑时,电脑上的内存有8G/16G/32G等,那么计算中的这些内存空间是如何进行管理的?

其实就是把这些内存划分为一个一个内存单元,每个内存单元大小是1个字节。这里要对字节这个内存单元大小有所概念。如下

1byte(字节)   =   8bit(比特)

1KB     =     1024byte

1MB    =    1024KB

1GB     =     1024MB

1TB      =     1024GB

注:一个比特位可以存储一个二进制位(0或1)

也就是每个内存单元相当于一个学生宿舍,一个宿舍可以住八个人,相当于一个字节空间可以存放八个比特位。每个内存单元也有编号就相当于房间编号。cpu可以通过内存单元编号快速找到该内存空间。生活中比如你点外卖要填写你家地址的楼层的几单元门牌号是多少,在计算机中也一样把内存单元的编号称为地址。在C语言中取名叫指针。 总结就是:房间编号==内存单元编号==地址==指针

了解了地址与内存的关系,下面讲解一下如何理解编址

1.1编址

cpu在访问内存单元时,首先要知道其地址,但内存单元地址有很多,如果不对它们进行排列,就跟宿舍房间没有编号一样,所要要对其进行编制。计算机的编制,并不是每个记录下来,而是由硬件设计完成,就如同钢琴中的多来买法索莱希,虽然没有具体编号,但是演奏者可以精确的找到钢琴的每一个键位,因为制造商已经把它设计好了,并且演奏者都知道,也就是一种约定俗成的东西。接下来先来了解一下计算机中的硬件如何进行数据传输,以及数据处理。

cpu1内存
0
1
0
地址总线
0
1
0
控制总线
1
0
数据总线
1

计算机中的硬件是协调工作的而连接它们的桥梁就是线,这里重点讲解地址总线。假如一个计算机是32位机器,相当于有32跟地址总线,每根线有0/1两种脉冲,那么一根线就能表示0或1其中一种电脉冲,那么32根线,每个都有两种状态也就是2^32次方,每一个就代表一个地址。地址信息被下达给cpu在内存中就能找到相应的地址对应的数据,然后将数据通过数据总线传递给cpu内的寄存器。

二、指针变量和地址。

2.1&取地址操作符

在上面已经理解了内存与地址的关系,回到C语言中,请看如下代码。

这里创建了变量a,申请了4个字节空间,来存放10,图中4个内存空间都有地址如图红色框所示。

那么如何获取a的地址呢?这里就要学习一个取地址操作符了。

如图所示&a表示取出a所占4个字节中较小字节地址。

2.2拆解指针类型

*是指针变量和解引用操作符,&a是将a的地址取出来,有时候需要把它存储起来,方便后期的使用,那么这个地址存储在哪里呢?答:指针变量,入下代码所示。

指针变量也是一种变量,用来存放地址的,存放在指针变量中的值也可以理解为地址。

将上图所示代码拆分来看。

1*表示pa是指针变量

2int表示pa指向变量的a的类型是int。

*也可以作为解引用操作符如下代码所示

三、指针变量的大小。

以一段代码演示

注:X86是32位平台

       X64是64位平台

由此可知,指针变量的大小与所属类型是无关的,只要是指针变量,在相同的平台下大小是一样的。

四、指针加减整数

前三个地址一样,后三个分别对它们进行加1操作,int类型的站4个字节所以加1跳过4个字节,而char类型占1个字节,加以跳过一个字节。

总结就是

五、void* 指针一种特殊的指针类型(无具体类型,可接受任意类型地址,缺点不能进行+-和解引用操作

一般这种类型使用在函数参数部分,用来接收不同类型的指针变量地址,可以实现一种泛型编程的效果,使得一个函数可以处理多种数据类型。

六、const修饰指针

6.1const修饰变量

变量是可以修改的,也可以通过指针解引用修改,如果要加上一些限制,让变量不能被修改,const就发挥了作用。请看下面代码。

这里const修饰了变量a,加上语法的限制,如果此时修改了变量a的值就会报错。那么如果想要修改a的值怎么办呢?其实可以利用指针。但是这样会打破语法规则。如下所示。

这样确实可以修改,如果不想打破const的语法限制,让a变量无法修改应该怎么办呢?

6.2const修饰指针变量

const可以放在*的左边或者*的右边,只不过含义不一样。请看下面代码。

情况1:const放在*左边时

限制的是指针指向的内容,也就是不能通过指针来改变它所指向的内容,但是可以修改指针变量本身。

情况2:const放在*右边时

 限制的指针变量本身,不能改变其指向,但是可以改变其指向的内容。

6.3*两边都有const

这样都不能被修改。

七、指针运算

7.1指针加整数

7.2指针减整数

7.3指针减指针

这里用一个模拟strlen函数来举例。

指针减去指针就是计算元素之间的个数,因为数组的地址是连续的。

八、野指针

含义:野指针就是指向的位置是不确定的。就像一条野狗一样,乱咬人。

8.1野指针的成因

形成野指针的成因有很多种,这里举例讲解三种

        1:指针未初始化

         2指针越界访问

这里循环了11次但是数组只有10个所以出现了指针的越界访问情况,就会出现一个随机值。

       3指针指向的空间释放

8.2野指针的避免

1指针初始化

如果明确知道指针指向哪⾥就直接赋值地址,如果不知道指针应该指向哪⾥,可以给指针赋值NULL. NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使⽤的,读写该地址 会报错。

2⼩⼼指针越界

如果指针指向那块空间就访问那块空间,不要访问空间以外的内存。

3指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性

4避免返回局部变量的地址

九、传值调用与传址调用

这里调用函数,发现a和b的值并没有进行交换。这里我们调试来看看。

通过调试可以看到a和b确实传递了Swap函数,形参x和y也接收了a和b的址,x和y也确实交换了,但注意请看a和b的地址,与x和y的地址很明显不一样,说明形参x和y是一块独立的空间,形参的改变并没有影响实参,所以a和b的值并没有交换。这就叫传值调用。如何解决这里问题呢?请看下列代码。

这里只需要将a和b的地址传递给函数的参数,通过指针来间接操作a和b这样就完成了交换。这就是传址调用

总结:传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量;所 以未来函数中只是需要主调函数中的变量值来实现计算,就可以采⽤传值调⽤。如果函数内部要修改 主调函数中的变量的值,就需要传址调⽤。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值