AKA - 对指针的这种迷恋是什么?
只使用了ActionScript,Java和C#这样的现代面向对象语言,我并不真正理解指针的重要性以及它们的用途.我在这里错过了什么?
这一切都只是间接:不处理数据的能力,但说"我会指引你到那里的一些数据".您在Java和C#中具有相同的概念,但仅以参考格式.
关键的区别在于引用是有效的不可变路标 - 它们总是指向某些东西.这很有用,也很容易理解,但不如C指针模型灵活.C指针是你可以愉快地重写的路标.你知道你要找的字符串是指向字符串的隔壁吗?好吧,只是略微改变路标.
这与C的"接近骨头,需要低水平的知识"方法很好地结合.我们知道 a char* foo
由一组字符组成,从foo路标指向的位置开始.如果我们也知道字符串长度至少为10个字符,我们可以将路标更改为指向(foo + 5)
相同的字符串,但是开始的长度的一半.
当你知道你正在做什么时,这种灵活性是有用的,如果你不知道你就知道死亡("知道"不仅仅是"知道语言",它"知道程序的确切状态").弄错了,你的路标指引你离开悬崖的边缘.参考文献不会让你弄错,所以你更有信心可以毫无风险地跟随它们(特别是当与"被引用的对象永远不会消失"这样的规则相结合时,就像在大多数垃圾收集的语言中一样).
你错过了很多!了解计算机如何在较低级别上工作在某些情况下非常有用.C和汇编程序会为你做这件事.
基本上,一个指针可以让你把东西写到计算机内存中的任何一点.在更原始的硬件/操作系统或嵌入式系统中,这实际上可能会有用.说再次打开和关闭blinkenlichts.
当然,这对现代系统不起作用.操作系统是主存和主存.如果您尝试访问错误的内存位置,您的进程将为其生命中的傲慢付出代价.
在C中,指针是传递对数据的引用的方式.调用函数时,您不希望将百万位复制到堆栈.相反,您只需知道数据驻留在主存储器中的位置.换句话说,您提供指向数据的指针.
在某种程度上,即使使用Java也会发生这种情况.您将引用传递给对象,而不是对象本身.请记住,最终每个对象都是计算机主存中的一组位.
指针用于直接操作内存的内容.
这取决于你是否认为这是一件好事,但它是在C或汇编程序中完成任何事情的基础.
高级语言隐藏了幕后的指针:例如,Java中的引用实现为几乎所有JVM中的指针,这就是为什么它被称为NullPointerException而不是NullReferenceException.但它不会让程序员直接访问它指向的内存地址,并且不能修改它以获取除正确类型的对象的地址之外的值.因此它不能提供与低级语言中的指针相同的功能(和责任).
[编辑:这是一个问题的答案'对指针的这种迷恋是什么?'.我所比较的只是带有Java引用的汇编程序/ C风格的指针.问题标题后来发生了变化:如果我开始回答我可能提到的除Java之外的其他语言的引用的新问题]
这就像在问,"对CPU指令的这种痴迷是什么?我是不是错过了一些东西,而不是在整个地方撒上x86 MOV指令?"
在低级编程时,您只需要指针.在大多数高级编程语言实现中,指针的使用与C中的一样广泛,但编译器对用户隐藏.
所以......别担心.你已经在使用指针了 - 而且没有做错的危险.:)
我认为指针是汽车中的手动变速器.如果你学会驾驶带有自动变速器的汽车,那将不会成为一个糟糕的驾驶员.而且你仍然可以完成手动变速器上学到的驾驶员可以做的大部分工作.你的驾驶知识会有一个漏洞.如果你不得不开一本手册,你可能会遇到麻烦.当然,很容易理解它的基本概念,但是一旦你必须做一个小山开始,你就搞砸了.但是,仍然存在手动变速器的地方.例如,赛车驾驶员需要能够转移以使车辆以最佳方式响应当前比赛条件.手动变速器对他们的成功非常重要.
这与现在的编程非常相似.某些软件需要进行C/C++开发.一些例子是高端3D游戏,低级嵌入式软件,速度是软件目的的关键部分,低级语言允许您更密切地访问需要处理的实际数据,这是该性能的关键.然而,对于大多数程序员而言,情况并非如此,并且不知道指针不会瘫痪.但是,我相信每个人都可以从学习C和指针以及手动传输中受益.
既然您已经使用面向对象语言进行编程,那么我就这样说吧.
您将对象A实例化对象B,并将其作为方法参数传递给对象C.对象C修改对象B中的某些值.当您返回到对象A的代码时,您可以在对象B中看到更改的值.为什么会这样?
因为您将对象B 的引用传递给了对象C,所以没有创建对象B的另一个副本.因此,对象A和对象C都在内存中保存对同一对象B的引用.从一个地方改变而在另一个地方看到.这称为参考.
现在,如果您使用原始类型(如int或float)并将它们作为方法参数传递,则对象A无法看到对象C中的更改,因为对象A仅传递副本而不是其自身的变量副本的引用.这称为按值.
你可能已经知道了.
回到C语言,函数A向函数B传递一些变量.这些函数参数是本机副本,按值.为了让函数B操作属于函数A的副本,函数A必须传递一个指向变量的指针,以便它成为一个按引用传递.
"嘿,这是我的整数变量的内存地址.把新值放在那个地址位置,我会稍后再拿."
注意这个概念是相似的,但不是100%类似的.指针可以做的不仅仅是通过"引用".指针允许函数将任意位置的内存操作到所需的任何值.指针还用于指向执行代码的新地址,以动态执行任意逻辑,而不仅仅是数据变量.指针甚至可能指向其他指针(双指针).这很强大,但也很容易引入难以检测的错误和安全漏洞.