我对指针/引用中C++"&"运算符的不一致应用感到困惑?

I'm confused by the inconsistent application of the "&" operator in C++ in pointers/references?

本文关键字:应用 不一致 指针 引用 C++ 运算符      更新时间:2023-10-16

我已经检查了许多编程语言(Java,Erlang,python等(但我发现 C/C++ 集会很难学。仅仅因为我认为它有时不合理;

例1:

    #include <iostream>
    int main() {
     int ar1 = {1,2,3};
     int *p1 = ar1;
     char *msg = "message";
     std::cout << "addr: " << p1 << std::endl ;//prints the array address
     std::cout << "value: " << *p1 << std::endl ;//prints the first element

     std::cout << "addr: " << msg << std::endl ;//prints "message" , wtf why not    the addr?how can i get its address?
     std::cout << "value: " << *msg << std::endl ;//prints the first character

    }

例2:

    #include <iostream>
    int main() {
     int n1 = 5;
     int *p1 = &n1;
     int &r1 = *p1; // why not: int &r1 = p1; ,*p1 is NOT an address,p1 is.This does not make any sense...

     }

你能给我解释一下这些例子吗?如果不解决这些问题,我就不能继续研究Cplusplus。

谢谢你的时间。

问题 1:

char *msg = "message";
std::cout << "addr: " << msg << std::endl ;
//prints "message" , wtf why not    the addr?

这是该语言从 C 开始的历史演变的人工制品,其中字符串通常由字符数组或指向此类数组的指针表示。为了支持这一点,<<有一个重载char const *,它将其视为指向字符串的指针并打印字符串内容。

可以通过使用 std::string 类来表示字符串来避免混淆,并避免使用 C 样式字符串,除非在(非常罕见的(情况下它们很有用。

how can i get its address?

您可以将其转换为通用指针:

std::cout << "addr: " << static_cast<void*>(msg) << std::endl;
                         ^^^^^^^^^^^^^^^^^^

问题2:

int n1 = 5;
int p1 = &n1;

这不会编译,因为&n1是一个地址,因此只能用于初始化指针,而不是int。我假设你的意思是:

int *p1 = &n1;
int &r1 = *p1; 
// why not: int &r1 = p1; ,*p1 is NOT an address,p1 is.This does not make any sense...

因为引用不是指针,并且不使用地址初始化。引用必须使用(有效(对象初始化,并成为该对象的别名。 *p1 是一个类型为 int 的对象,因此可以用来初始化对int的引用。

&符号可能会让C++中的新人感到困惑。这是因为&可以有多种含义。

这:

int* p1 = &n1;

表示获取 n1 的地址并将其存储在指向 int 的指针中。 p1是一个指针,保存n1的地址。

这:

int &r1 = *p1;

表示创建称为引用的特殊类型的变量。(在C++引用实际上只是其他东西的别名(。R1 被告知在 *p1 处为值指定别名。 *p1 表示跟随指针 p1 并获取基础值。在这种情况下,我们知道p1指向n1因此我们在这里知道r1是对n1的引用。意思是如果我这样做:

r1 = 5;

然后

std::cout << n1;

输出将是5

也可以表示二进制和运算符。这是你在这里不问的完全不同的事情。

问题的很大一部分是你的例子大多是错误的。

第一个例子:

 int ar1 = {1,2,3};
 int *p1 = ar1;

为了正确起见,这需要;

int ar1[] = {1, 2, 3};
int *p1 = ar1;

在这种情况下,事情非常简单:在大多数情况下(包括这种情况(,数组的名称计算为该数组开头的地址(即,您分配给指针的值类型(。主要的例外是当您使用数组作为sizeof运算符的操作数时,因此sizeof(ar1)会给出数组的实际大小(3 *sizeof(int)(,而不是指针的大小。

在第二个示例中:

 int n1 = 5;
 int p1 = &n1;
 int &r1 = *p1; // why not: int &r1 = p1; ,*p1 is NOT an address,p1 is.This does not make any sense...

你是对的 - 这没有任何意义,正常运行的编译器不应该按原样编译它。你显然想要的是这样的东西:

int n1 = 5;
int *p1 = &n1;   // p1 is a pointer to int, holding address of n1
int &r1 = *p1;   // r1 is a reference to int, referring to what p1 points at (n1).
就打印内容而言

,这很简单:任何类型如何打印出来纯粹是由编写库的人做出的决定。他们认为,当您将指针传递给 char 时,它会假设您想要打印指向的字符串,这是最有意义的。对于其他指针类型,他们决定打印出指针本身的值。不过,这些都不是关于语言本身的——这只是某人做出的决定,因为这对他们来说是有意义的。

如果你有一个指向 char 的

char/指针数组,并且想要打印出地址而不是它指向的字符,你通常将其强制转换为指向 void 的指针:

 char *msg = "message";
 std::cout << static_cast<void *>(msg);

至于他们为什么选择这个,我认为很简单:因为当人们说cout << mystring时,他们通常希望将字符串的内容打印出来。这通常仅限于字符串,因为(几乎(每个人都同意如何打印出字符串的内容,但在涉及 int、double 等数组的内容时就不那么多了。