-5

我检查了许多编程语言(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。

谢谢你的时间。

4

3 回答 3

6

问题一:

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

这是该语言从 C 的历史演变的产物,其中字符串通常由字符数组或指向此类数组的指针表示。为了支持这一点,<<有一个重载 take 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

于 2012-07-20T15:51:47.917 回答
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

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

于 2012-07-20T15:34:51.057 回答
2

很大一部分问题是您的示例大多是错误的。

第一个例子:

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

正确地说,这需要是;

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

在这种情况下,事情很简单:在大多数情况下(包括这种情况),数组的名称计算为该数组开头的地址(即,您分配给指针的值的类型)。主要的例外是当您使用数组作为运算符的操作数时sizeofsizeof(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 等数组的内容时却没有这么多。

于 2012-07-20T15:56:04.467 回答