c中的指针,引用和取消引用有什么区别?
答案 0 :(得分:20)
这是一张记忆图;将记忆表示为一系列块:
address 01 02 03
+----+----+----+...
data within | 23 | 6f | 4a |
+----+----+----+...
现在假设我们创建了一个角色:
char c = 'z'; // 'z' is 7a in hex
进一步假设c
存储在地址01
,所以我们的记忆如下:
address 01 02 03
+----+----+----+...
data within | 7a | 6f | 4a |
+----+----+----+...
现在,让我们创建一个指针:
char* p = &c; // point at c
p
可能会存储在地址02
:
address 01 02 03
+----+----+----+...
data within | 7a | 01 | 4a |
+----+----+----+...
此处指针p
位于地址02
,而指向位于地址01
。这就是p = &c;
的含义。当我们取消引用指针p
(在地址02
)时,我们会查看p
指向的地址中的内容。也就是说,p
指向地址01
,因此取消引用p
意味着查看地址01
。
最后,让我们创建一个参考:
char& r = c;
此处内存布局不会改变。也就是说,没有内存用于存储r
。 r
是c
的一种别名,所以当我们引用r
时,我们实际上是指c
。 r
和c
在概念上是一个。更改r
表示更改c
,更改c
表示更改r
。
创建引用时必须初始化,一旦初始化,就无法使用其他目标重新初始化它。也就是说,高于参考r
意味着永远意味着c
。
还有 const references 。这些与引用相同,除了它们是不可变的:
const char& r = c;
r = 'y'; // error; you may not change c through r
c = 'y' // ok. and now r == 'y' as well
当我们有兴趣阅读数据时,我们使用const引用,但在更改数据时皱眉。通过使用const引用,编译器不会复制数据,因此这为我们提供了理想的性能,但也禁止我们更改数据,以确保正确性。
从某种意义上说,您可以说引用是编译时功能,而指针是运行时功能。因此,引用比指针更快,更便宜,但具有某些约束和含义。与其他编译时与运行时替代方案一样,我们有时会选择一个用于性能,有时用于静态分析,有时用于灵活性。
答案 1 :(得分:6)
时间进行抨击狂热,因为这些事情总会造成混乱。
指针本身就是一个内存地址。提示在内存中如何发生的花哨图:
| Address | Value |
|----------|----------------|
|0x1111 |0x1112 | <-- Pointer!
|0x1112 |42 | <-- Pointed value
|0x1113 |42 | <-- Some other value
为了简单起见,我使用了更小的地址大小。基本上,0x1111
是一个指针,因为它的内容是另一个值的地址。
解除引用意味着检查指针值中保存的地址的值。这种奇特的语言可能令人困惑;基本上,如果我取消引用0x1111
,我会查看0x1112
并从该地址中获取值。为什么?因为它非常有用,而且汇编让我们也可以这样做,
mov rax, [r8]
是否使用nasm / intel语法“查看r8,找到该内存地址,按照它查找该内存地址的值并将其放在rax中”。
按值传递。传递值意味着当您创建一个函数堆栈帧(即函数周围的堆栈内容)时,您复制作为参数的每个值。寄存器,堆栈,无论在哪里。当然,如果复制指针的值,则复制内存地址,从而创建指向同一内存的另一个指针。这就是这样的函数:
void add(int* x)
{
*x = *x + 7;
}
工作。
通过引用传递。上面的函数基本上是通过引用语义传递的,因为你会在C ++中看到它们。在程序集级别实现可能相同的关键且可能唯一的区别是引用是C ++编译器理解的内容。由于编译器是语言,这很重要。 C理解指针和操作内存,C编译器也是如此,但它们会让你做任何你喜欢的事情。您无法重新分配参考,例如
void cppadd(int& x)
{
int a = 7;
x = &a; // doesn't work.
}
因此,总而言之,引用在一个级别上是一种语言特性,编译器可以在此处了解源内存的位置并防止修改该源内存地址。它理解你想要玩这个价值。指针就是这样,内存地址保存其他内存地址。
Wikipedia总结得非常好:
在C ++编程语言中,引用是一种简单的引用数据类型,它比从C继承的指针类型更强大但更安全。名称C ++引用可能会引起混淆,因为在计算机科学中引用是一般概念数据类型,指针和C ++引用是特定的引用数据类型实现。
是的,当这个问题只是C时,我提到了C ++,但我觉得澄清一个术语如何与后来的语言的添加有些混淆是明智的。
答案 2 :(得分:5)
在C ++中没有C语言中的显式引用类型。任何人在C语言的上下文中都说“引用”,你可以假设一个指针。
答案 3 :(得分:2)
C有指针,你几乎可以用这些指针做任何你想做的事情,你可以尊重它们,然后改变指针的值。实际上,指针算法是C编程中非常常见的技术。在我作为C程序员的年轻时代,在与其他C开发人员交谈时,引用并不是常用术语。
作为术语的引用通常与Java,C#和面向对象语言一起使用。在Java和面向对象语言的上下文中,引用是指向内存中对象实例的指针。使用引用你不能做指针运算,这是我视图中指针和引用之间的关键区别。
指针允许指针算术和解除引用,引用只允许解除引用和更改引用所指向的内容。
答案 4 :(得分:2)
引用意味着获取现有变量的地址(使用&amp;)来设置指针变量。为了有效,必须将指针设置为与指针相同类型的变量的地址,而不是星号:
int c1;
int* p1;
c1 = 5;
p1 = &c1;
//p1 references c1
取消引用指针意味着使用*运算符(星号字符)来访问存储在指针中的值:注意:存储在指针地址处的值必须是值相同类型作为指针变量的类型&#34;点&#34; to,但除非指针设置正确,否则无法保证是这种情况。指针指向的变量类型是最外面的星号。
int n1;
n1 = (*p1);
无效的解除引用可能会导致崩溃,也可能不会导致崩溃:
任何取消引用任何未初始化的指针都可能导致崩溃 使用无效类型转换取消引用可能会导致崩溃。 取消引用指向动态分配并随后取消分配的变量的指针可能会导致崩溃 取消引用指向已超出范围的变量的指针也会导致崩溃。 无效的引用更可能导致编译器错误而不是崩溃,但依赖编译器并不是一个好主意。
参考文献:
http://www.codingunit.com/cplusplus-tutorial-pointers-reference-and-dereference-operators
& is the reference operator and can be read as “address of”.
* is the dereference operator and can be read as “value pointed by”.
http://www.cplusplus.com/doc/tutorial/pointers/
& is the reference operator
* is the dereference operator
你也可以阅读维基 解除引用运算符*也称为间接运算符。
本文摘自此链接,他们为同一问题提供了相同的答案: meaning of "referencing" and "dereferencing"
答案 5 :(得分:1)
指针的值是内存地址。
int a;
int* b = &a;
// b holds the memory address of a, not the value of a.
引用是一个带有值(内存地址)的指针,该值引用所需的项目。
int a;
int* b = &a;
// b is a reference to a.
取消引用是一种获取指针引用的内存内容的技术。
int a;
int* b = &a;
int c = *b;
// c dereferences b, meaning that c will be set with the value stored in the address that b contains.
请注意,C ++引用与C引用不同。 C ++参考是一个抽象的概念,其中C ++决定允许您对大多数调用使用非指针语法,但会自动地做出正确的事情&#34;在需要时传递指针。
答案 6 :(得分:0)
指针是某些数据的地址,例如
int* a
。
这里a
实际上只是存储int值的地址。
相反,引用是某个变量的另一个名称,一个别名,例如,
int a;
int &b = a
此处b
只是a
的另一个名称:b++
与a++
具有相同的效果。
答案 7 :(得分:0)
如“C ++ ...”:
在某些情况下,编译器可以优化远离引用 在运行时没有表示该引用的对象。
答案 8 :(得分:0)
根据我的经验,让我回答。
在C ++中,有变量(普通变量,指针变量等)和引用。
编译器将为每个变量分配一个地址。显然,该变量的地址不能相同。可以说每个变量实际上是一个地址。什么是引用&,引用不是变量而是标签,因此编译器不会为他分配地址,但这并不意味着它没有地址,它的地址是它引用的变量或对象的地址。 ,因此它用作标记,用于将其地址设置为编译器对其进行解析时引用的变量或对象的地址。这会导致地址与其引用的变量或对象的地址相同,难以置信地可以编译和考虑或尝试使用GDB!
由于引用和引用的对象地址相同,因此C ++为什么要引入引用的概念?指针也可以达到目标,这不是多余的动作。我说这是我认为的主要原因!
为了保持一致性和一致性!例如:
class box {
private:
int l;
public:
box(int length = 0) : l(length){};
box operator+(const box& that) {
box b;
b.l = this->l + that.l;
return b;
}
box operator+(const box* that) {
box b;
b.l = this->l + that->l;
return b;
}
};
int main() {
box b1(2);
box b2(4);
box b3 = b1 + b2;
box b4 = b1 + &b2;
return 0;
}
以上,我使用引用和指针作为参数重载了box对象的+运算符。在主体上两个表达式不是以相同的方式编写的,两者都可以实现相同的功能,显然使用引用的方式可以方便地表达,指针的使用更为复杂,在大量代码的情况下,你可能是这个事情变得头晕。如果您认为还有其他重要原因,请通过评论告知我!