![]() |
1
79
这都只是间接的:不处理数据的能力,但是说“我会把你引向那边的一些数据”。你在爪哇和C中有相同的概念,但只是参考格式。 关键的区别在于引用实际上是不可变的路标——它们总是指向某个东西。这是有用的,并且容易理解,但是比C指针模型的灵活性要差。C指针是您可以愉快地重写的路标。你知道你要找的绳子在被指向的绳子旁边吗?好吧,只是稍微改变一下路标。
这与C的“接近骨骼,需要低水平知识”方法很好地结合。我们
知道
那一
这种灵活性在你知道你在做什么的时候很有用,如果你不知道死亡(其中“知道”不仅仅是“知道语言”,而是“知道程序的确切状态”)。弄错了,你的路标正把你引向悬崖边。引用不会让你胡乱摆弄,因此你更确信你可以毫无风险地遵循它们(尤其是当与诸如“被引用对象永远不会消失”之类的规则结合在一起时,就像在大多数垃圾收集语言中那样)。 |
![]() |
2
28
你错过了很多!在某些情况下,了解计算机在较低级别上的工作方式非常有用。C和汇编程序将为您做这件事。 基本上,一个指针可以让你把东西写到计算机内存中的任何一个点上。在更原始的硬件/操作系统或嵌入式系统中,这实际上可以做一些有用的事情。说,打开和关闭闪烁的图标。 当然,这在现代系统上不起作用。操作系统是主存储器的主人。如果你试图访问一个错误的内存位置,你的进程将为它的傲慢付出生命的代价。 在C语言中,指针是传递数据引用的方式。调用函数时,不希望将一百万位复制到堆栈中。相反,您只需告诉主内存中的数据位置。换句话说,你给 指针 数据。 在某种程度上,即使是Java也会发生这种情况。传递对象的引用,而不是对象本身。记住,最终每个对象都是计算机主存储器中的一组位。 |
![]() |
3
14
指针用于直接操作内存的内容。 这取决于您是否认为这是一件好事,但它是在C或汇编程序中完成任何事情的基础。 高级语言隐藏了幕后的指针:例如,Java中的引用被实现为几乎所有JVM中的指针,这就是为什么它被称为Null PoExtExchange,而不是Null ReavyExpRebug。但是它不允许程序员直接访问它指向的内存地址,并且它不能被修改为获取正确类型对象的地址以外的值。因此,它并不像低级语言中的指针那样提供相同的能力(和责任)。 [编辑:这是一个问题的答案,‘这是什么困扰着指针?’我比较的是用Java引用的汇编程序/C风格指针。问题标题已经改变:如果我开始回答这个新问题,我可能会提到除Java以外的其他语言的引用。 |
![]() |
4
12
这就像在问,这是什么困扰着CPU指令?我是不是错过了一些东西,不把x86 MOV指令撒得到处都是?艾斯 你只是 需要 在低级别上编程时的指针。在大多数高级编程语言实现中,指针的使用与在C中一样广泛,但编译器对用户隐藏。 所以…别担心。你已经在使用指针了——而且没有错误使用指针的危险。:) |
![]() |
5
10
我把指针看作是汽车上的手动变速器。如果你学着驾驶一辆自动变速器的车,那就不会成为一个坏司机。而且你仍然可以做司机们在手动变速器上学到的大部分事情。你的驾驶知识只会有一个漏洞。如果你必须开一本手册,你可能会遇到麻烦。当然,这很容易理解它的基本概念,但一旦你必须做一个希尔开始,你就完蛋了。但是,仍然有一个手动变速器的地方。例如,赛车手需要能够换档,使汽车以最理想的方式响应当前的赛车条件。手动变速器对他们的成功非常重要。 这与现在的编程非常相似。有些软件需要C/C++开发。一些例子包括高端3D游戏、低层嵌入式软件、速度是软件用途的关键部分的东西,以及允许您更接近需要处理的实际数据的低层语言,这些都是性能的关键。然而,对于大多数程序员来说,情况并非如此,而且不知道指针也不会造成严重影响。不过,我相信每个人都能从学习C和指针,以及手动变速器中受益。 |
![]() |
6
5
既然您一直使用面向对象的语言进行编程,那么让我这样说。 你得到对象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%相似。指针可以做的不仅仅是通过“引用”传递。指针允许函数将内存的任意位置操作到所需的任何值。指针还用于指向 执行代码 动态执行任意逻辑,而不仅仅是数据变量。指针甚至可以指向 其他指针 (双指针)。这很强大,但也很容易引入难以检测的漏洞和安全漏洞。 |
![]() |
7
4
如果你以前没见过指针,你肯定错过了这个迷你宝石:
|
![]() |
8
4
历史上,使编程成为可能的是认识到内存位置可以保存计算机指令,而不仅仅是数据。 指针来自于这样一种认识,即内存位置也可以保存其他内存位置的地址,从而给我们提供间接的方向。如果没有指针(低级别),最复杂的数据结构将是不可能的。没有链表、二叉树或哈希表。不通过引用,仅通过值。由于指针可以指向代码,没有它们,我们也没有虚拟函数或函数查找表。 |
![]() |
9
4
|
![]() |
10
2
我目前正在设计一些高级企业软件,其中一个或多个其他实体引用了大量数据(在本例中存储在SQL数据库中)。如果当没有更多的实体引用数据块时,数据块仍然存在,那么我们就是在浪费存储空间。如果一个参考点的数据不存在,那也是个大问题。 我们的问题与使用指针的语言中的内存管理有着很强的相似性。能用这种类比和我的同事交谈是非常有用的。不删除未引用的数据是“内存泄漏”。无处可去的引用是一个“悬空指针”。我们可以选择显式的“frees”,或者使用“引用计数”实现“垃圾收集”。 因此,了解低级内存管理有助于设计高级应用程序。 在Java中,你一直在使用指针。大多数变量都是指向对象的指针——这就是为什么:
…打印“Hello Boys”而不是“Hello”。 C语言的唯一区别是,从指针中加和减是很常见的——如果逻辑错误,最终可能会弄乱不应该触及的数据。 |
![]() |
11
2
字符串是C(和其他相关语言)的基础。在C语言中编程时, 你 必须管理你的记忆。你不只是说“好吧,我需要一串字符串”;你需要考虑数据结构。你需要多少记忆?你什么时候分配?你什么时候释放它?假设您需要10个字符串,每个字符串不超过80个字符。 好的,每个字符串都是一个字符数组(81个字符-不能忘记空值,否则会很抱歉!)然后每个字符串本身就在一个数组中。最终结果将是一个多维数组,类似于
顺便注意一下,dict不是“string”、“array”或“char”。它是一个指针。当您试图打印这些字符串中的一个时,您所要做的就是传递单个字符的地址;C假定如果它只是开始打印字符,那么它最终将达到一个空值。它假设如果你在一个字符串的开头,向前跳81个字节,你将在下一个字符串的开头。实际上,获取指针并向其添加81个字节就是 唯一可能的方法 跳到下一个字符串。 那么,为什么指针很重要?因为没有他们你什么都做不了。你甚至不能做一些简单的事情,比如打印出一串字符串;你 当然 不能做任何有趣的事情,比如实现链表、哈希、队列、树、文件系统、一些内存管理代码、内核等等。你需要理解它们,因为C只是给你一块内存,让你做剩下的,用一块原始内存做任何事情都需要指针。 许多人也认为理解指针的能力与编程技巧高度相关。乔尔提出了这个论点。例如
从 here . 优秀的文章。 |
![]() |
12
2
老实说,如果您不知道指针,大多数经验丰富的开发人员都会笑(希望是友好的)。 在我以前的工作中,去年我们有两个新雇员(刚刚毕业),他们不知道什么是指点,仅此一个星期就成为了与他们交谈的话题。没有人会相信一个人不知道指点就可以毕业… |
![]() |
13
2
C++中的引用与Java或.NET语言中的引用有很大的不同;.NET语言有一些特殊的类型,称为“ByReFS”,它们的行为非常类似于C++的“引用”。 C++引用或.NET ByReF(我将使用后一个术语来区分.NET引用)是一个不包含变量的特殊类型,而是保存足够的信息来标识一个变量(或者可以作为一个行为,比如数组时隙)保存在别处。ByRef通常只用作函数参数/参数,并且是短暂的。将ByRF传递给函数的代码保证了至少在函数返回之前将存在被识别的变量,并且函数通常保证在返回后不保留任何ByRf的副本(注意在C++中没有执行后者的限制)。因此,byrefs不能超过由此确定的变量。 在Java和.NET语言中,引用是一种标识堆对象的类型;每个堆对象都有一个关联类,堆对象类中的代码可以访问对象中存储的数据。堆对象可以授予代码受限或完全访问其中存储的数据的外部权限,和/或允许外部代码在其类中调用某些方法。使用对调用其类的方法的引用将导致该方法可以使用该引用,然后该方法可以使用该引用访问堆对象中的数据(甚至私有数据)。 是什么使得Java和.NET语言中的引用保持绝对不变,即每个非空引用都将继续标识同一堆对象,只要该引用存在。一旦对堆对象的引用在宇宙中的任何地方都不存在,堆对象将简单地停止存在,但当对堆对象的任何引用存在时,堆对象就不可能停止存在,也没有任何方法可以使对堆对象的“正常”引用自动成为对该对象的引用以外的任何对象。Java和.NET都有特殊的“弱引用”类型,但它们都支持不变量。如果宇宙中任何地方都不存在对某个对象的非弱引用,那么任何现有的弱引用都将无效;一旦出现这种情况,就不会有任何对该对象的引用,因此它可能无效。
指针与C++引用和Java/net引用一样,可以标识对象,但是不同于上述类型的引用,它们可以超出它们标识的对象。如果指针标识的对象不再存在,但指针本身不存在,则任何使用指针的尝试都将导致未定义的行为。如果一个指针也不知道
指针和引用(无论是哪种类型)之间的关键区别在于,可以始终询问引用是否有效(它们是有效的还是可标识为空的),如果观察到它们是有效的,则只要它们存在,它们就保持有效。无法询问指针是否有效,系统将不采取任何措施确保指针不会变为无效,也不允许将变为无效的指针识别为无效指针。 |
![]() |
14
1
很长一段时间我不懂指针,但我懂数组寻址。所以我通常会为数组中的对象设置一些存储区域,然后使用该数组的索引作为“指针”概念。
这种方法的一个问题是,在我修改了“a”之后,我必须将其重新分配到“store”数组,以使更改永久:
在后台,编程语言正在执行一些复制操作。大多数情况下,这不会影响性能。它主要使代码容易出错和重复。 在学会理解指针之后,我不再使用数组寻址方法。这个类比仍然很有道理。只需考虑“store”数组是由编程语言的运行时管理的。
现在,我只能在无法合法复制对象时使用指针。原因有很多:
|
![]() |
15
0
指针是在低级编程语言中表示间接性的最实用的方法。 |
![]() |
16
0
指针很重要!它们“指向”内存地址,许多内部结构表示为指针,即字符串数组实际上是指向指针的指针列表!指针也可用于更新传递给函数的变量。 |
![]() |
17
0
如果要在运行时生成“对象”,而不在堆栈上预先分配内存,则需要它们 |
![]() |
18
0
参数有效性-传递指针(int-4字节),而不是复制整个(任意大的)对象。 Java类通过引用(基本上是指针)也传递BTW,它只是在Java中隐藏的程序员。 |
![]() |
19
0
C语言和C++语言的编程更接近于“金属”。指针保存变量、数据、函数等所在的内存位置。您可以传递一个指针,而不是传递值(复制变量和数据)。 使用指针有两个困难:
您可以将指针行为与Java对象是如何传递的进行比较,但在Java中,您不必担心释放内存,因为这是垃圾收集处理的。这样你就可以得到关于指针的好东西,但不必去处理负面的东西。当然,如果你不去引用你的对象,你仍然可以在Java中获得内存泄漏,但这是另一回事。 |
![]() |
20
0
同样需要注意的是,通过将代码块标记为不安全,您可以在C(与普通引用相反)中使用指针。然后你可以直接跑来跑去改变内存地址,做指针算术和所有有趣的事情。它非常适合快速的图像处理(我个人唯一使用过的地方)。 据我所知,Java和ActionScript不支持不安全的代码和指针。 |
![]() |
21
0
我总是为在高级语言中关注诸如指针或引用之类的事情而苦恼。从更高的抽象层次上考虑对象(甚至只是函数)的行为是非常有用的,而不是从“让我看看,如果我把这个东西的地址发送到那里,那么这个东西会给我一个指向其他东西的指针”的角度来思考。 甚至考虑一个简单的交换函数。如果你有 无效交换(int&a、int&b) 或 过程交换(变量A,B:整数) 然后将其解释为可以更改这些值。事实上,通过传递变量的地址来实现这一点只会分散人们的注意力。 对象也一样——不要把对象标识符当作指向“东西”的指针或引用。相反,只需将它们视为可以向其发送消息的对象。即使在像C++这样的原始语言中,你也可以通过思考(和写作)尽可能高的速度。 |
![]() |
22
-3
写超过2行的C或C++,你会发现。 它们是指向变量内存位置的“指针”。这就像是通过引用传递一个变量。 |
![]() |
Kris · 有没有办法获得可变结构字段的“引用” 3 年前 |
![]() |
Jora Karyan · IF语句未按预期引发错误 3 年前 |
![]() |
nedzad · 如何访问引用Firebase中其他对象的对象 7 年前 |
![]() |
Empha · 从成员函数对对象所做的更改不会持续。范围/参考问题? 7 年前 |