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

95 Views Asked by At

Like I encountered this doubt while learning dynamic memory allocation in C++, and just can't focus anymore on learning it now. :(

    int n;
    cout << "Enter array size: ";
    cin >> 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 < n; i++)
    {
        // cin >> p[i];   // This is correct
        // cin >> *(p+i); // This is correct

        cin >> (p + i); // same as cin >> &p[i], right? Now, this gives me error since I didn't deference 
                        // it and now I'm confused as to why we need to deference it? *(p+i) tells which 
                        // block the value is to be stored in, but doesn'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't and I can't visualize it why?

        // Also, now I'm even confused as to why writing cin >> n works and writing cin >> &n doesn'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, >> 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.

2

There are 2 best solutions below

2
VLL On

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 >> (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>> 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 >> 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>>.

0
Serge Ballesta On

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 << 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& operator << (istream& in, int& val);

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