您的位置:首页 > 其它

学完·指针你必须知道这些知识点

2018-02-04 16:14 465 查看

1.内存和地址

     提到指针,不得不提到内存和地址,这几者之间确实有着很密切的关系,因此今天我也会把这几个概念串联在一起描述。在上一篇讲指针的博文中,我把指针比喻成一栋大厦的门牌号,当你想要找到某个人的时候,你就可以通过门牌号进行查找,这样目的性就很明确,也可以很快的找到。但是我现在必须补充的是,单单把指针这样定义是不对的。举个很简单的例子。计算机的内存一个位只能存放0或者1,但是一般情况下,都是多个位连在一起来存储数据。这样的话,你要找的数据可能就会存在一种情况,它可能同时具有多个地址,那么你要找的话,到底是用哪个呢?所以这时候那个比喻就显得有所欠缺了。不过,计算机也自然有解决的办法。通常情况下,以数据开始存储的第一个位置作为标准,这样就可以只需要考虑一个数据的一个地址了,这样做同时也可以避免数据存储的混乱。我在下面插入一张图片更好的说明一下

2.值和类型

[align=left]         指针既然是指向不同的数据,那么不同的数据也肯定有不同的数据类型,那么也就说指针也具有不同的类型。常见的有 int float double char long 这几种类型,这些都是你们很熟悉的了,那么接下来要说的,或许你们不是很了解。[/align]
int a=112,b=-1;
float c=3.14;
int *d=&a;
float *e=&c;
[align=left]       在上面我定义了两个整型,一个浮点型数据,同时也定义了两个指针,一个指向a,一个指向c,c在这里是一个浮点型,但是如果之前定义了一个整型的,那么到底是使用它的那种类型呢?这里有个条件,如果它参与的是整形运算,那么他就当做整型使用,如果是参与小数运算,那就是浮点型。你问我为什么?因为该变量包含了一序列内容为0或者1的位,他们的使用可以根据操作而定,没有绝对的定义,这点记清楚啊。[/align][align=left]       那么也就是说,不能简单的通过检查一个值的位来判断他的类型哦[/align]

3.指针变量的内容与间接访问操作符

[align=left]     指针变量既然是变量,那么它所存储的值也就可能发生变化。比如说,我先定义了一个指针指向数组的第一个元素,我想遍历这个数组,那么我就需要数组每次下标加1,对应的指针地址也要加4,因为一个整型数据占用四个内存空间。每一次指针向前走,它的内容都会发生改变,但是它变得是地址而不是值得改变。一个变量的值就是分配给该变量的内存位置所存储的数值,但是对于指针变量,它其中存储的一定是这个数值的地址,所以你要直接使用指针那是会报错的,因为数据的操作是不能涉及到内存空间内部的。[/align][align=left]      因此要想或许到内存指向的值时,你必须使用间接访问符号*,这样你才可以合法的使用这个数值。指针有个特点,他不能取直接改变指向的变量的值,但是它会一直指向哪个内存空间,即使空间里面存储的数值已经发生了改变,这就会涉及到数值安全性的一些问题。所以,一般在使用指针的时候,会事先声明它指向的内容为const类型,这样就无法改变数值了。[/align]

4.未初始化和非法的指针

[align=left]     指针变量和普通的变量是有区别的。普通的静态变量在声明之后可以不用初始化,而系统在缺省的情况下会自动给其赋值为0,而指针不进行初始化会出现很大的问题。如果声明了一个指针没有进行初始化,那么它可能会指向一个你根本不知道的位置,而且这个位置可能会有一个非法的值。而当你看到下面这段代码的时候,你就知道问题多麽大了[/align]
int *a;

a=12;
[align=left]因为指针a没有被初始化,所以你根本不知道a指向的是哪一个存储位置,运气好的话,会出现一个整形数据,但是这样带来的结果就是你修改了一个不知道位置的存储空间的数据,虽然你不想这么做。[/align][align=left]    所以,为了避免这些不必要的错误出现,在使用指针的时候一定要记得初始化。还有就是再使用完指针以后也一定要置空,这样才可以把内存空间还回去,避免出现野指针。[/align]

5.指针为何可以作为左值

[align=left]     间接访问操作符所需要的操作数是一个右值,但是这个操作符所产生的结果却是一个左值。下面我就告诉你们为何就可以[/align][align=left]     1.指针变量可以作为左值,不是因为它是一个指针,而是因为它是一个变量。[/align][align=left]      看一个有趣的例子[/align]
*d=10-*d;
d=10-*d;
[align=left]       在这个例子里面,上面的一定没有问题。因为左边的间接访问符作为左值使用,所以d把它指向的位置把赋值号右侧的表达式的计算结果作为它的新值[/align][align=left]       而第二句是非法的,因为他把一个整型数值存储于一个指针变量中,左右的数值类型不一致,编译器也会因此报错,这个问题是我们经常犯得一个错误,但是很少能够被察觉到。如果实在要用,那就是需要用到强转为(int *)这样就可以通过编译了。这个时候,d就是一个指针常量了,那么他会被当做地址使用,那么这句语句的意思就是把10-*d的值存储在内存地址为d的位置[/align]

6.指针的指针

[align=left]先给大家看一张图[/align]

[align=left]在这里面,定义了一个整型a,它的值是12,而指针b指向的是a,所以指针b里面存放的值就是a的地址,现在在指针b的后面又定义了一个指针c指向指针b,那么指针c里面存放的便是指针b的地址了。找这样说的话,要想通过指针c得到a的值,那就需要解引用两次,实际上也确实是这样,只要这样做就可以正确的取得a的值,表达式如下[/align][align=left] [/align]
a=12;
*b=&a;
*c=&b;

7.指针的运算

[align=left]     指针由于其特殊的性质,因此它只能进行很简单的几种运算操作,常用的有 + - ,还有就是关系操作比如  > <。[/align][align=left]1. 指针进行加法操作的话,由于实际上进行的是内存上的操作,所以,指针加一,要根据它指向的数据的类型相应的乘上整数倍,这才是正确的值。由于地址一般都是整数,因此,指针的加法操作得到的值也一定是一个整型[/align][align=left] 2. 指针进行减法操作,只有当两个指针指向同一个数组时才有实际意义,这样做的结果是指出两个指针指向元素相差几个位置。现在还不知道如果指向的不同数组会有什么影响,但是能知道的一定是这样做没有多大的意义。[/align][align=left]3.指针的操作通常需要注意数组下标越界的问题。在vs编译器里面,允许数组可以越界一位,但是多了就会报错了。虽然数据越界不会报错,但是问题就是那个多出一位的数据也没有任何实际作用,因此,为了避免这种错误,那就最好提前检查好,保持代码的健壮和稳定[/align]

8.对于指针使用常见警报的总结

[align=left]1.错误的对一个为初始化的指针变量进行解引用[/align][align=left]2.错误的对一个NULL指针进行解引用[/align][align=left]3.向函数错误的传递NULL指针[/align][align=left]4.未检测到指针表达式的错误,从而导致不可预料的结果[/align][align=left]5.对一个指针进行减法运算,使它非法的指向了数组第一个元素的前面的内存位置。[/align][align=left][/align][align=left][/align][align=left]总的来说,指针是一个很好用的工具,因此我们很有必要熟练地使用它,这在我们数据结构的学习也会带来很大的好处,今天就说这么多了,有的地方可能有些赘述,欢迎指正。[/align]


[align=left]
[/align][align=left]
[/align][align=left]
[/align]


[align=left]
[/align]


[align=left][/align]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: