C语言指针进阶


下面为了让大家更好的理解上面两个概念,我们来举几个例子来查看一下。



解释第一个概念:大小一样的盒子存储指针


代码如下


我们声明了两个类型的变量,它们的类型是不同的。我们通过sizeof来查看这两个指针变量的大小。


2.png


运行结果如下


这是在Ubuntu操作系统下的运行结果,下面两句命令分别是编译命令和运行的命令,可以看到虽然它们的指针指向的类型不一样,但是存储指针的空间是一样的,都是4个字节,指针变量的大小与指向类型无关。


3.png



解释第二个概念:指针指向的地址读取是与类型有关的


我们申请了一个int类型的变量a并将0x12345678这个数值存储到内存中去了。那我们申请了一个int类型的指针,里面怎么放指针呐?如下图所示可以吗?我们将一个整型0x1122放到本应该存储指针的指针变量中去,这个写法是没有语法错误的。因为0x1122并没有超越2^32,但是在我们看来它是一个整型,当放进去指针变量之后,这个整型就被解释为一个地址,也就是门牌号。那么0x1122这个地址里面对应的资源是什么呐?这个资源是否合法呐?如果我们对一个非法空间进行操作的话,系统就会禁止我们这么做。


4.png


所以在指针中,我们还将引入一个新的概念:指针指向的内存空间一定要保证合法性。


合法就是这个内存地址确确实实存在,还要保证它能读能写。


比如我们想通过CPU去控制一个LED灯,这个灯的资源肯定也有一个门牌号,对于这段资源,我们是否能够读取。这个时候我们就不能读取出来,因为他就是一个状态,高低电平的状态。如果寄存器不允许我们读取我们就读取不出来,如果我们向它申请去读,读出来的结果就可能会是随机的,这样的结果就会误导我们。


如果有同学在学习C的时候出现段错误,那么这种段错误百分之九十都是跟指针指向内存的非法性有关。所以出现这个错误的时候,我们第一个就应该去查找代码中的指针,看看指针有没有非法操作。


指针赋值


所以我们应该给指针变量一个地址,而不是一个整型或者是其它类型的变量。所以我们介绍一个新的运算符:取址运算符&,它可以对一个变量取地址。


int *p1=&a;//将a的首地址赋值给p1,a应该拥有4个字节,它将这4个门牌号中的第一个门牌号(也是门牌号中的最小值)给它


指针读取


我们声明指针变量之后,C就将变量名看做是一个地址-指针变量存储的地址。p1就是变量名,里面存储的是地址,当我们对p1进行读写的时候,读取的都是地址。所以我们通过*p1来访问它所指向的内存。*p1在这里和变量名a的效果是一样的。我们可以对它进行读写操作。


测试代码和操作代码如下:变量a的写入和读取都是采用十六进制的。


5.png


在这段代码中,我们声明了一个char类型的指针来存放一个int类型变量的地址,不管int指针变量还是char指针变量存储一个地址都是没有问题的,但是它们的读取方式是不同的,char类型只会读取一个字节的内存,而int类型的会读取4个字节。我们将一个int类型的变量赋值给了char类型的指针,读取这个指针的值的时候按照char类型来读取一个字节,就是存储在指针中的那个字节。那int类型中的四个字节怎么从其中选择一个存储到指针中去呐?


下面的黑色方框中,存储在内存中的内容按照高地址到低地址来存储,int类型的变量如下图所示。而赋值的时候会选取四个字节地址中值小的字节来赋值给指针变量。就将存储0x78的地址给p了。这样的类型不同的赋值是会有警告的,但是依然可以访问。以后我们会介绍怎么消除这条警告。


6.png


运行结果如下:可以看到结果确实是将一个字节的内存读取了。


7.png



【本文由麦子学院独家原创,转载请注明出处并保留原文链接】

logo
© 2012-2016 www.maiziedu.com
蜀ICP备13014270号-4 Version 5.0.0 release20160127

免费领取价值1888元求职宝典!

客服热线 400-862-8862

回到顶部