如何解决在C语言中更改变量的值时,是创建新的原语还是当前原语被突变?
理解C的工作方式的最佳方法是将其视为高级汇编语言。变量只是内存中的位置,将值分配给变量会将值存储到该位置。从高级语言的角度来看,这将是最纯粹形式的变异。
在C中,声明/定义如
int x;
告诉编译器为该int
变量保留一些内存x
。(在函数内部,内存将来自堆栈。在全局范围内,它将来自数据段。)
像这样的作业
x = 7;
x = y;
生成代码以将int
存储在y
的存储位置的值复制到x
的存储位置。(假设y
是另一个int
。)
同样的逻辑也适用于比int
s 更复杂的类型。
在Java中,变量是引用(反正是非原始类型),并且可以在不同时间引用不同的对象。为了获得类似于C中引用的内容,您必须显式定义一个 指针 变量(一个保存地址的变量),并在不同的时间将其指向不同对象的地址(为其分配地址)。
(为方便起见,我提供了以下示例。)
的&
操作者用来得到在C变量的地址,以便&x
将地址x
例如。*
当应用于指针时,运算符将提供指向的对象。这是一个如何在不同时间使用指针来引用不同变量的示例:
int x;
int y;
/* Declares 'ptr' as a pointer, and says that it points to an int.
The pointed-to type is used by the compiler for type checking
and type conversions. */
int *ptr;
ptr = &x; // Store the address of 'x' in 'ptr'.
*ptr = 1; // Store 1 into the memory 'ptr' points to ('x').
ptr = &y; // Store the address of 'y' in 'ptr'.
*ptr = 2; // Store 2 into the memory 'ptr' points to ('y').
上面代码的最终结果将设置x
为1和y
2。这当然是一个愚蠢的示例,但希望它能使您理解。
(//
顺便说一下,C99和更高版本支持样式注释。)
问题的答案
(注意:我的Java有点生锈,因此我必须做一些阅读。希望细节应该正确。请随时纠正我。)
第1期
那作业
x = "Goodbye World";
将具有x
引用String
值为“再见世界” 的对象的效果。确切地说,String
创建此对象的时间不应该有所不同,只要在分配给对象x
(或任何其他变量)之前创建该对象即可。
它可能是在执行分配之前或程序启动时创建的。通常,您将无法分辨出差异。
第2期
听起来您已经掌握了高级概念,并且您的C代码是正确的。
(尽管说“ ptr
是一个指针”比说“ *ptr
是一个指针”
更正确。C中存在一些语法上的晦涩之处,这使得*
在声明(IMO)中放置下一个名称更为自然,但是您可以也要像这样写声明int*
ptr;
。只有在同一行中声明许多变量时,事情才开始变得怪异。)
在讨论Java的实现方式时,引用可能必须比仅是底层对象的指针要先进一些。例如,JVM可能会在内存中移动对象(这将更改它们的地址)以减少内存碎片,但是引用仍必须保持有效。一种方法是在移动对象时“固定”指针,另一种方法是使引用成为指针表的索引。不管它在JVM实现中是如何完成的,指针 至少都是正确的想法。
由于Java中的每个引用都有一个指针字段(在高层,完全忽略了实现的方式),并且由于原始类型不需要此字段,因此一种可能性是重用指针字段并将值存储在其中而不是原始类型。
例如,类似
x = 1;
可能将值1直接存储到引用的指针字段中x
。这样的技术很普遍。
附带说明一下,a union
可以用于在C中将两种不同类型(例如,anint
和指针)存储在内存中的同一位置,以便它们重叠。当然,分配给其中一种类型也会改变另一种类型的值。
解决方法
我知道“可变”和“不可变”是应该用来描述对象改变诸如Java和Objective
C之类的面向对象语言中的值的能力的术语。但是,我想提出它,因为它与我的语言有关有关原始数据的问题。我知道,当我更改持有不可变对象的变量的值时,实际上是在创建一个新对象。但是,我想知道C中的基本数据的行为是否类似于不可变对象。我的意思是,当我更改保存原始数据的变量的值时,将创建新数据并由该变量引用。还是现有的原语实际上改变/修改了存储的数据值?
编辑#1:
问题#1: 我想消除一些误解(无论是我本人还是其他人),因为当我说“当我更改持有不可变对象的变量的值时,我实际上是在创建一个新对象。”
当我这么说时,我并不是要将变量分配给现有对象。例如:
// Example 1: I did not mean this
-------------------------
String x = "Hello World";
String y = x;
-------------------------
// Example 2: What I meant is this
-------------------------
String x = "Hello World";
//This will print out "Hello World"
System.out.println(x);
x = "Goodbye World";
//This will print out "Goodbye World"
System.out.println(x);
-------------------------
当然,就像示例1中那样,将变量y分配给变量x,这就是你们提出的情况,只将变量y引用给x所引用的对象。当然,在这种情况下,没有新对象。只是同一对象“
Hello World”被两个变量引用。
我的意思是,在示例2中,当x =“ Goodbye World”时,变量x引用一个具有值“ Goodbye
World”的新String对象,而不是用x初始化的第一个String对象“ Hello
World”。字符串是Java中的不可变对象。更改String变量的值的唯一方法是让变量引用现有对象 或 新的String对象。如果没有现有对象(“
Goodbye World” String对象尚未在任何地方创建),则以上代码仅创建了一个新的String对象,并对其引用了x。我对吗?如果没有,请纠正我。
问题2: 我想总结一下答案,尤其是来自 Ulfalizer 的答案:
1)实际上,变量可以存在2种形式:
a)“内存地址”-对于C语言变量以及Java和Objective C有关原始类型数据的情况就是如此。例如:int x
=1。这里的变量x是一个实际的内存地址本身,它的类型为integer,并用值1初始化。
b)“参考”-对于非原始类型数据(对象),Java中的大多数变量都是这种情况。例如:String x =“ Hello
World”。变量x只是指向“存在于某处的内存地址”的指针/引用,其内容为“ Hello World”值。
2)C,Java和目标C中的原始类型数据的变量充当“内存地址”。因此,当我这样做时:
-------------------------
int x = 10;
x = 2;
-------------------------
x变量的值(又名-内存地址)实际上从10更改为2。换句话说,可以修改/更改存储在“ Memory Address”变量中的值。
3)在C语言中,如果变量以’‘-指针类型声明,则它也可以充当引用。我将使用 Ulfalizer* 的示例:int *
ptr。ptr是一个指针变量,可以指向另一个变量(即内存地址),例如:ptr =&x。如果x初始化为:int x =
10,则x是保存值为10的实际内存地址。因此在下面的代码中
-------------------------
int x;
int *ptr;
ptr = &x;
*ptr = 1;
-------------------------
我实际上可以通过ptr指针变量修改存储在x变量(又名-内存地址)中的值。
请确认我的解释是否正确/错误。谢谢。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。