Brendon Cheung
Brendon Cheung

Reputation: 1035

Lvalue and Rvalue with C++ arrays

I have done some experimentation on array and learning about L-value and R-values,

From my understanding:

L-values are object that has an identifiable memory location, R-values are defined by exclusion, anything that is not a L-value, is a R-value, by exclusion.

Here is my experiment:

int array [] = {8, 7, 6, 5, 4};            
std::cout << array << std::endl;           //0x61fedc
std::cout << &array << std::endl;          //0x61fedc
std::cout << *(&array) << std::endl;       //0x61fedc
std::cout << *array << std::endl;          //8

Line 1 and 2 should come with no surprises, when you evaluate an array, it will return the address of the first element

What is confusing is the results from line 3. *(&array) is saying to me "what is the de-referenced value of the first memory address of the variable array, I was expecting 8, however i got back the first memory address, why is that?

Lastly, line 4 evaluates to 8, which was expected. However, since the dereferencing operator works on the array variable, why can't we conclude that array is a pointer (points to the first element memory address)? I know this can't be truth but they behaves the same?

Thank you

Upvotes: 4

Views: 1172

Answers (2)

Ted Lyngmo
Ted Lyngmo

Reputation: 117168

I find an example clarifying. Here I have some foo overloads accepting the versions you've used in your code.

#include <iostream>
#include <string>

template<size_t N>
std::string foo(const int(&)[N]) {
    return std::string(" int(&)[") + std::to_string(N) + "]\n";
}

template<size_t N>
std::string foo(const int(*)[N]) {
    return std::string(" int(*)[") + std::to_string(N) + "]\n";
}

std::string foo(const int*) {
    return " int*\n";
}

std::string foo(int) {
    return " int\n";
}

int main() {
    int array [] = {8, 7, 6, 5, 4};
    std::cout << array     << foo(array);
    std::cout << &array    << foo(&array);
    std::cout << *(&array) << foo(*(&array));
    std::cout << *array    << foo(*array);
}

Possible output:

0x7ffeaf43a610 int(&)[5]
0x7ffeaf43a610 int(*)[5]
0x7ffeaf43a610 int(&)[5]
8 int

As you can see, with this combination of overloads, none of the versions decay into an int*.

Upvotes: 2

EML
EML

Reputation: 10261

Your question already has an answer here. Basically, sometimes an array to pointer conversion takes place, sometimes it doesn't.

Your definition of an lvalue is incorrect. An lvalue must be capable of being assigned to; it is valid on the left hand side of assignment. A read-only location has an address, for example, but is not an lvalue.

Upvotes: 0

Related Questions