您的位置:首页 > 编程语言 > C语言/C++

c语言指针详解

2017-11-20 10:45 78 查看
什么是指针

指针究竟是什么,是地址还是类型,有一些人认为是地址因为存放的是地址,有些人认为是一种类型因为国际标准已经指明指针是一种类型,但其实说指针是地址有些不太严谨,因为从编译角度来看指针是一种数据类型,其存储的地址也就是指针存储的值是才是地址,所以实际上指针的值是地址和指针本身是一个类型这两者之间是不冲突的。

为什么很多人对于指针并不理解,因为他们对于指针的理解是一个笼统的概念就像一个泛称,在说到某一个细节的时候可能没有进行区分,导致对于问题的理解很冲突,所说的一个指针其实代表了很多东西。

指针常量和指针变量

所以大家应该分清指针常量和指针变量的区别,所有的数据都存放在存储器中,一般把存储器的一个字节称为一个内存单元,内存单元的编号也叫做地址,内存单元的指针和内存单元的内容是两回事,指针的变量是用来存储计算机内有效的内存地址,而且这个有效的内存地址又叫做指针常量又叫做变量的指针,也就是各个变量的地址,而指针变量则是用来存储指针常量的变量。为了表明指针变量和它所指向的变量之间的关系,在程序中用*符号表示指向。地址是由编译系统分配的对用户完全透明。

指针常量是常量不能进行运算,而指针变量可以进行某些运算但运算的种类有限只有赋值运算和部分算术运算和及关系运算。

*号和指针

在指针里*是一个非常关键的符号,是一元间接寻址运算符,即它将指针的值转换为左值,间接寻址运算符的操作数必须是指向类型的指针,间接寻址表达式的结果是从中派生指针类型的类型,这里的*运算符的使用与作为二元运算符的意义不同,后者是惩罚运算符。

如果指向函数,则结果是函数指示符,如果指向存储位置,结果是指定位置的左值,可以累积使用间接寻址运算符来取消引用指向指针的指针。

需要注意的是,指针运算符*和指针变量声明中的指针说明符*不是一回事,在指针变量说明中*是类型说明的一部分,表示其后的变量是指针类型,而表达式中出现的*则是一个运算符用以表示指针变量所指的变量。

指针类型

c语言的指针类型包括两个信息,一个是地址,存放在指针变量中,二是类型信息,和读写移动字节长度有关,它没有存储在指针变量中。指针存储了内存地址同时指针具有指向的变量的类型,那么指针变量应该存储这两方面的信息:地址和被指向的类型这两个信息,但是打印sizeof(int *)的值为4,这四个字节是存储内存地址的,说明指针并没有存储类型信息的地方,那么指针所指向的类型信息存放在哪?通过返汇编就能看出位于该指针读写的时候mov指令中不同的读写长度对应的mov指令也不同,mov指令的byte说明了被指向变量的类型信息

使用指针常见的错误

如果一个指针的值无效,则结果是为定义的,一些比较常见的错误。

(1)该指针是null指针

(2)该指针指定引用时不可见的本地项的地址

(3)该指针指定未针对所指向的对象类型正确对齐的地址

(4)该指针指定执行程序未使用的地址

为什么需要指针

大家可能有一些疑问一些问题使用基本类型的变量就可以完成为什么还需要指针,指针的内涵是地址先于指针存在的,先有地址然后出现了语法让我们对地址进行操作 ,变量的本质也是一个内存地址的别名。

在早期的CPU不像现在那么强大,当时对于内存读写的指令是直接在操作内存和寄存器,那个时候还没有变量所以对于内存读写都要把具体的数字(这个数字就是类似于123这样的字面量)写进程序,这样就会出现一个情况因为每条指令只能对内存中的一个字节进行操作,这样就会随着处理数据的膨胀,程序也要跟着膨胀,这在当时是一个大问题,因为数据的增多是必然的。而为了缓解程序指令的不断增多,就发明了控制流程的指令,比如“如果符合什么条件就略过下一条指令”和“无条件跳转到首地址为多少的地方从那里继续运行”,这样就可以写出循环来缩减程序了。但是问题只解决了一部分,虽然减少了代码的多少,但是还不能自由修改代码因为程序里只能写常量,就出现了自修改程序,利用了指令本身也是编码成字节码存在内存里的这个特征,来通过修改内存来修改指令,这就是自修改程序通过一个指令不断修改之前的指令。但自修改程序很容易出错,就又发明了间接寻址,出现了新的指令“把某个寄存器储存的数据当作地址,取出该地址处的字节放到寄存器里”和“把某个寄存器储存的数据
/地址,把另一个寄存器的字节写入到该地址”。这样的好处是指令本身被固化了行为更加稳定不需要冒险去修改指令 。而指针就是间接寻址里的内存块,它存了一片地址,而指针解引用就对应的是间接寻址读写的指令。而指针是间接寻址的体现,指令集里面有一种间接寻址方式抽象出来就是指针。这样问题就回归到了为什么需要指针,就转化为为什么需要间接寻址,而在冯诺伊曼体系结构里需要间接寻址去对地址进行操作,语言是迭代发展的c是为了解决汇编语言的易用性和更好的逻辑性,所以需要一些操作来替代模拟汇编的寻址。

在别的语言中不是没有指针,只是在c/c++中将指针的语法暴露给了使用者。c语言发明的时候为了满足性能要求并要兼顾思维逻辑性做了一个折衷,对地址的访问产生了两种方式,比较符合人话的助记符变量交给编译器去管理,另一种就是和之前相同对地址访问的指针,之后为了更加符合人的逻辑在c++中就进一步出现了引用,再后来硬件速度就不在那么令人担忧没有必要为了一点运行效率非加一个不太符合逻辑的指针所以指针就不再暴露给使用者,但是对于内存的操作依然像指针一样只不过不需要亲自管理了。所以指针的作用就是为了让使用者能亲自管理内存,为了更高的效率在设计上更接近计算机本身而不是开发者,考虑的是计算机有什么而不是人需要什么,之后的语言因为为了让更多的精力放在逻辑本身提供了自己的内存管理机制,指针依旧存在只是系统帮你维护了。

指针的优势

使用一个指针时既可以使用它存储的内存地址也可以使用这个地址里的存储的值,使用指针可以省去了检索的过程,在内存分配的时候,有时不一定是顺序的,那么遍历内存的速度肯定没有直接去找地址快。

(1)可以提高程序的编译效率和执行速度,使程序更加简洁。

(2)通过指针被调用函数可以向调用函数处返回除正常的返回值之外的其他数据,从而实现两者间的双向通信。

(3)利用指针可以实现动态内存分配。

(4)指针还用于表示和实现各种复杂的数据结构,从而为编写出更加高质量的程序奠定基础。

(5)利用指针可以直接操纵内存地址,从而可以完成和汇编语言类似的工作。

(6)更容易实现函数的编写和调用。

(7)C 语言只有值的传递,无法直接传递引用,要想传递引用必须通过指针间接实现。如果一切都通过值传递,所有的结构体只要参与运算都具有极高的开销,因为每传递进函数一次就必须全体复制一次。而且无法在参数中传递数组,一切数组在函数参数传递时退化为指针,因此如果没有指针,数组将无法通过函数参数传递。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: