为什么cin没有像C中的scanf()那样的与操作符或格式说明符?

huangapple go评论52阅读模式
英文:

Why doesn't cin have ampersand operator or specifier format like scanf() does in C?

问题

我在学习C++中的动态内存分配时遇到了这个疑问,现在无法再集中注意力了。:(

    int n;
    cout << "输入数组大小:";
    cin >> n;
    int *p = new int[n];

到目前为止一切都很好,我只是在堆区域中分配了n个int内存块。

现在,在使用for循环输入时,当我尝试将p[i]写为 *(p+i) 时,我有这个疑问。

 for (int i = 0; i < n; i++)
    {
        // cin >> p[i];   // 这是正确的
        // cin >> *(p+i); // 这是正确的

        cin >> (p + i); // 与 cin >> &p[i] 相同,对吗?现在,这给了我一个错误,因为我没有解引用它,现在我为什么需要解引用它感到困惑?*(p+i) 告诉我们值应该存储在哪个块中,但 (p+i) 也不是给了我们相同的地址吗?输入值应该仍然存储在相应的内存块中,对吗?但它没有,我无法理解为什么。

还有,现在我甚至困惑于为什么写 cin >> n 有效,而写 cin >> &n 不有效?

    }

我只是期望我的值仍然应该被接受到相应的数组元素中,但实际上没有,相反,它给了我一个非常非常错误的错误,我无法理解。我尝试寻找答案,但仍然对概念的可视化和清晰性感到不明确。到目前为止,我知道的一切就是cin是istream类的对象,与cin一起使用的>>运算符在某种程度上类似于函数调用,我们在>>运算符之后写的变量名是"通过引用"传递的,或者类似于这样的东西,这似乎是为什么我们可能不需要将地址作为引用变量,因为默认情况下引用变量已经有了,但我不确定,仍然怀疑。

请有人按正确顺序和适当示例来解释它。我将不胜感激。

英文:

Like I encountered this doubt while learning dynamic memory allocation in C++, and just can't focus anymore on learning it now. 为什么cin没有像C中的scanf()那样的与操作符或格式说明符?

    int n;
    cout &lt;&lt; &quot;Enter array size: &quot;;
    cin &gt;&gt; n;
    int *p = new int[n];

So everything is fine till now, I just allocated n blocks of int memory in heap area

Now, while taking the input using a for loop, I had this doubt while I tried to write p[i] as *(p+i)

 for (int i = 0; i &lt; n; i++)
    {
        // cin &gt;&gt; p[i];   // This is correct
        // cin &gt;&gt; *(p+i); // This is correct

        cin &gt;&gt; (p + i); // same as cin &gt;&gt; &amp;p[i], right? Now, this gives me error since I didn&#39;t deference 
                        // it and now I&#39;m confused as to why we need to deference it? *(p+i) tells which 
                        // block the value is to be stored in, but doesn&#39;t (p+i) also give us the same  
                        // address? The input value should still have been stored in the respective memory                                 
                        // block, right? But it doesn&#39;t and I can&#39;t visualize it why?

        // Also, now I&#39;m even confused as to why writing cin &gt;&gt; n works and writing cin &gt;&gt; &amp;n doesn&#39;t??
    }

I was simply expecting that my value should still be accepted into the respective array element, but it didn't, rather it gave me a very very wrong error, which I'm unable to understand.

I tried looking for answers, but still unclear with the concept visualization and clarity. All I've known so far is that cin is an object of istream class, &gt;&gt; operator while used with cin is kind of like a function call, and the variable name which we write after the >> operator is "passed by reference" or something like that, which might seem like that is why maybe we don't give address as reference variable already has it by default, but I'm not sure and still in doubt.

Please someone explain it in proper sequence and with proper example. I'll be grateful.

答案1

得分: 2

*(p + i)的类型是int,而(p + i)的类型是int*。第一个表示你正在读取一个整数,所以这是清楚的。

为什么cin >> (p + i)不能读取int?当函数通过引用接受参数时,参数的类型必须完全相同。你提供的是int*,因此它将尝试读取int*

那么我们如何读取一个指针呢?我猜我们可以读取一个整数并将其赋给指针变量。我们目前正在读取临时值p + ioperator>>需要一个引用,但它无法从临时值中获取引用,这就是为什么会出现编译错误的原因。

我们可以通过使用另一个变量来解决这个问题:

int* pi = p + i;
cin >> pi;

这仍然不能编译通过,因为有一个用于读取void*的重载,但没有用于int*的重载。在C++中,不能自动在两种指针类型之间进行转换。如果你想读取int*,你可以这样做,但你必须编写一个operator>>的重载。

英文:

Type of *(p + i) is int and type of (p + i) is int*. With the first one you are reading an integer, so that is clear.

Why doesn't cin &gt;&gt; (p + i) read int? When a function takes parameter by reference, the parameter must be the same exact type. You are giving it int*, so it will try to read int*.

How would we read a pointer? I guess we could read an integer and assign it to the pointer variable. We are currently reading to the temporary value p + i. operator&gt;&gt; needs a reference, which it cannot get for a temporary value, which is why you get a compile error.

Let us skip this problem by using another variable:

int* pi = p + i;
cin &gt;&gt; pi;

This still does not compile, because there is an overload for reading void*, but not int*. In C++, you cannot automatically convert between two pointer types. If you want to read int*, you can do that, but you have to write an overload for operator&gt;&gt;.

答案2

得分: 0

以下是翻译好的部分:

"> the variable name which we write after the >> operator is "passed by reference"
在>>运算符之后编写的变量名是“通过引用传递”

This is exactly the point. One of the main goals of the C language was to build a rather simple compiler able to provide efficient code.
这正是重点。C语言的主要目标之一是构建一个相当简单的编译器,能够生成高效的代码。

As a result, it tried to remain as explicit as possible and only allowed to pass parameters to functions as values.
因此,它试图保持尽可能明确,只允许将参数作为值传递给函数。

If you want to modify something from a function you just pass a pointer to it.
如果要从函数中修改某些东西,只需将指针传递给它。

C++ language is aimed at a much higher level. Proper pointer handling is not always trivial and memory allocation is not either.
C++语言面向更高级别。正确的指针处理通常并不容易,内存分配也是如此。

The philosophy of C++ is that those are gory details that should be hidden to a high-level program.
C++的哲学观点是这些细节应该对高级程序隐藏起来。

For that reason, many SO users advise to never use new[] and delete[] (explicit allocation) but rely on containers which correctly handle the subtleties of automatic deallocation, and copy and move semantics.
因此,许多Stack Overflow用户建议永远不要使用new[]delete[](显式分配),而是依赖于能正确处理自动释放、复制和移动语义的容器。

For the same reason, references were introduced in the language.
出于同样的原因,引用被引入到语言中。

At first sight, they just look like disguised pointers to old C programmers, meaning useless syntactic sugar, and worse contradictory with the C idiom requiring a pointer to modify a variable from a function (what operator &lt;&lt; indeed is at a lower level).
乍一看,它们只是似乎是对旧C程序员伪装的指针,意味着无用的语法糖,而且与C语法相矛盾,C语法要求使用指针来从函数中修改变量(operator &lt;&lt;在较低级别确实如此)。

But that is exactly what they are for: you can act directly on the variable without explicitly dereferencing it, which removes the risk of forgetting a * somewhere in the code.
但这正是它们的用途:您可以直接对变量进行操作,而无需明确取消引用它,从而消除了在代码中某处忘记*的风险。

And actually, the signature of the stream extractor is:
实际上,流提取运算符的签名是:

istream&amp; operator &lt;&lt; (istream&amp; in, int&amp; val);

So the function is able to modify the stream itself and the passed variable.
因此,该函数能够修改流本身以及传递的变量。

英文:

> the variable name which we write after the >> operator is "passed by reference"

This is exactly the point. One of the main goals of the C language was to build a rather simple compiler able to provide efficient code. As a result, it tried to remain as explicit as possible and only allowed to pass parameters to functions as values. If you want to modify something from a function you just pass a pointer to it.

C++ language is aimed at a much higher level. Proper pointer handling is not always trivial and memory allocation is not either. The philosophia of C++ is that those are gory details that should be hidden to a high level program. For that reason, many SO users advise to never use new[] and delete[] (explicit allocation) but rely on containers which correctly handle the subtilities of automatic deallocation, and copy and move semantics.

For the same reason, references were introduced in the language. At first sight, they just look like disguised pointers to old C programmers, meaning useless syntactic suger, and worse contradictory with the C idiom requiring a pointer to modify a variable from a function (what operator &lt;&lt; indeed is at a lower level). But that is exactly what they are for: you can act directly on the variable without explicitly dereferencing it, which removes the risk of forgetting a * somewhere in the code.

And actually, the signature of the stream extractor is:

istream&amp; operator &lt;&lt; (istream&amp; in, int&amp; val);

So the function is able to modify the stream itself and the passed variable.

huangapple
  • 本文由 发表于 2023年2月16日 15:07:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75468869.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定