1

The second assignment gives an error (a value of type "int" cannot be assigned to an entity of type "int *"), why isn't the same error showing up for the first assignment?

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int* x = new int[100];
    x[5] = 3;

    int* y[100];
    y[5] = 3;

    return 0;
}
  • 3
    `int* y[100];` is an **array** of pointers to `int`. `x` **is** a pointer to `int`. – Andrew Henle Nov 20 '19 at 20:30
  • 4
    Sidenote: Don't `#include ` ([reason](https://stackoverflow.com/Questions/31816095/Why-Should-I-Not-Include-Bits-Stdc-H.)) and don't `using namespace std;` ([reason](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice)). – Ted Lyngmo Nov 20 '19 at 20:37

4 Answers4

4

x is of type pointer to int and y is of type array of 100 pointers to int.

Then, x[0] is of type int& (reference to int) and y[0] is of type int*& (reference to pointer to int).

Thus x[0] = 5 is assigning int value to int reference (perfectly valid), but y[0] = 5 is trying to assign int value to a pointer, which is not valid.

Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
  • The type of an indexed array is the underlying type, not a reference to the underlying type. There are no reference types here. The expression `x[0] = 5;` assigns an `int` *rvalue* to an `int` *lvalue*. – Stephen M. Webb Nov 20 '19 at 20:36
  • 2
    @StephenM.Webb how would you explain `x[0] = 5;` then? – 463035818_is_not_an_ai Nov 20 '19 at 20:37
  • 2
    @StephenM.Webb dereferencing a pointer, or indexing an array, gives you a reference to the element at that position. If it didn't you couldn't assign to it. – NathanOliver Nov 20 '19 at 20:41
  • @StephenM.Webb Hmm. [cppreference](https://en.cppreference.com/w/cpp/language/operator_member_access#Built-in_subscript_operator) is not really clear on the returned type of this operator and I don't have standard to consult, but I don't see how it could possibly work without reference types. – Yksisarvinen Nov 20 '19 at 20:42
  • Dereferencing a pointer or indexing an array gives you an *lvalue* not a reference type. – Stephen M. Webb Nov 20 '19 at 20:48
  • Don't forget folks, this is C code (despite the "C++" tag). C does not have reference types so any explanation that requires their existence is incorrect. – Stephen M. Webb Nov 20 '19 at 20:51
  • 2
    @StephenM.Webb The Q is tagged as C++ so it is C++ code, even if it would compile in a C compiler. References do exist in C++ and so that is what you get. We go by the language tag on the question, not what the code looks like. – NathanOliver Nov 20 '19 at 20:53
  • 2
    @StephenM.Webb Also, how is it C code. The code has `new` in it and that is **not** C code. – NathanOliver Nov 20 '19 at 20:53
  • I believe what Stephen meant is that "array subscripts can also compile as C code, and C doesn't have references", which is a valid point. In C there must be some magic applied instead of nice type,and presumably most compilers implement it the same way in C++, if the standard doesn't clearly state that it must return a reference type. – Yksisarvinen Nov 20 '19 at 20:57
  • @NathanOliver-ReinstateMonica I could replace the new expression with a malloc call (a remove the useless include directive and using statement) and I'd have pure C code that would compile identically with either a C or a C++ compiler. Going by ISO/IEC 14882:2014 (the C++14 standard) 5.2.1/1(1) [expr.sub] "the result is an lvalue if that operand is an lvalue and an xvalue otherwise" and 5.3.1/1 [expr.unary.op] "the result is an lvalue referring to the object or function to which the expression points". No ambiguity, no reference types. – Stephen M. Webb Nov 20 '19 at 21:06
  • @StephenM.Webb *lvalue referring* means reference. – NathanOliver Nov 20 '19 at 21:07
  • 1
    I think this issue deserves a separate question (if one does not already exist). The discussion seems too long for comments? – Yksisarvinen Nov 20 '19 at 21:10
  • For further reference, ISO/IEC 9899:2011 (the C11 standard) 6.5.3.2 /4 regarding the indirection operator `*`: "If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’." – Stephen M. Webb Nov 20 '19 at 21:11
  • @NathanOliver-ReinstateMonica reference types are defined in ISO/IEC 14882:2014 3.9.2/1.4 [basic.compund] and lvalues are defined in 3.10/1.1 [basic.lval] -- they're not the same thing. – Stephen M. Webb Nov 20 '19 at 21:16
3

x is a pointer to an int. When you x[5] = 3; you actually get *(x + 5) = 3;, which advances the pointer and then dereferences it to get to the int it points to.

With y you have the same thing, but y isn't a pointer to an int, it is a array of pointers to int. That means *(y + 5) gives you an int*& since the element type of the array is int*. You can't assign an int to an int*, hence the error.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
2

Your declaration doesn't do what you think it does. This line:

int* y[100];

does not create an array of ints, but of int*s.

If you want an array of ints, just don't use the *:

int y[100];

This will create an array of 100 ints.

undur_gongor
  • 15,657
  • 5
  • 63
  • 75
2

As pointed out by @Andrew Henle, int* y[100]; is an array of pointers to int but x is a pointer to int.

A helpful technique to parse any C declaration is to use the so called Clockwise/Spiral rule.

Answers to this question are also helpful.

brj
  • 375
  • 2
  • 11