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

时间:2012-07-20 15:31:03

标签: c++ pointers reference

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

EX1:

    #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


    }

EX2:

    #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而不解决这些问题。

感谢您的时间。

3 个答案:

答案 0 :(得分:6)

问题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...

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

答案 1 :(得分:4)

&符号可能会让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

&安培;也可以指二元和算子。这是一个完全不同的东西,你在这里没有问。

答案 2 :(得分:2)

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

第一个例子:

 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等数组的内容之类的东西时却没有那么多。