Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Multidimensional Array printing address, not value

41 views
Skip to first unread message

arnuld

unread,
Jan 22, 2018, 8:25:04 AM1/22/18
to
AIM: to print elements of a multidimensional array.
PROBLEM: it prints addresses

I known from C.7.2 of Stroustrup 3/e that there are no multidimensional
arrays on hardware level. These dimensions exist in compiler-source only.
Question is a[i] generally prints the value at \i\. Then why not here ?


#include <iostream>
#include <string>

using std::cout;

int main()
{
int arr[4][4];

for(int i = 0; i != 4; ++i)
{
for(int j = 0; j != 4; ++j)
{
arr[i][j] = i+j;
cout << "arr[" << i << "][" << j << "] = arr[" << arr[i] << "["
<< arr[j] << "]\n";
//cout << arr[i][j] << " ";
}
}



return 0;
}
=========== OUTPUT =================
[arnuld@arch64 programs]$ g++ -std=c++17 -pedantic -Wall -Wextra
arrays.cpp
[arnuld@arch64 programs]$ ./a.out
arr[0][0] = arr[0x7ffda9f1e9e0[0x7ffda9f1e9e0]
arr[0][1] = arr[0x7ffda9f1e9e0[0x7ffda9f1e9f0]
arr[0][2] = arr[0x7ffda9f1e9e0[0x7ffda9f1ea00]
arr[0][3] = arr[0x7ffda9f1e9e0[0x7ffda9f1ea10]
arr[1][0] = arr[0x7ffda9f1e9f0[0x7ffda9f1e9e0]
arr[1][1] = arr[0x7ffda9f1e9f0[0x7ffda9f1e9f0]
arr[1][2] = arr[0x7ffda9f1e9f0[0x7ffda9f1ea00]
arr[1][3] = arr[0x7ffda9f1e9f0[0x7ffda9f1ea10]
arr[2][0] = arr[0x7ffda9f1ea00[0x7ffda9f1e9e0]
arr[2][1] = arr[0x7ffda9f1ea00[0x7ffda9f1e9f0]
arr[2][2] = arr[0x7ffda9f1ea00[0x7ffda9f1ea00]
arr[2][3] = arr[0x7ffda9f1ea00[0x7ffda9f1ea10]
arr[3][0] = arr[0x7ffda9f1ea10[0x7ffda9f1e9e0]
arr[3][1] = arr[0x7ffda9f1ea10[0x7ffda9f1e9f0]
arr[3][2] = arr[0x7ffda9f1ea10[0x7ffda9f1ea00]
arr[3][3] = arr[0x7ffda9f1ea10[0x7ffda9f1ea10]
[arnuld@arch64 programs]$




--
-- arnuld
http://lispmachine.wordpress.com/

Bo Persson

unread,
Jan 22, 2018, 8:42:25 AM1/22/18
to
The output expressions have the wrong type. a[i] and a[j] are one
dimentional arrays of type int[4].

When passed to the output operator they decay to int* and that address
is displayed. Not the value stored at the address.


Bo Persson


James R. Kuyper

unread,
Jan 22, 2018, 9:20:08 AM1/22/18
to
On 01/22/2018 08:24 AM, arnuld wrote:
> AIM: to print elements of a multidimensional array.
> PROBLEM: it prints addresses
>
> I known from C.7.2 of Stroustrup 3/e that there are no multidimensional
> arrays on hardware level. These dimensions exist in compiler-source only.
> Question is a[i] generally prints the value at \i\. Then why not here ?

Because the value at a[i] is an int[4] array. C++ doesn't work directly
with array values; except in certain special cases, "An lvalue or rvalue
of type “array of N T” or “array of unknown bound of T” can be converted
to a prvalue of type “pointer to T”. The temporary materialization
conversion (7.4) is applied. The result is a pointer to the first
element of the array." (7.2)

The main exceptions to this conversion are the &, typeid (8.2.8p3), and
sizeof (8.3.3p4) operators, direct bindings to references (11.6.3p5),
and when used in discarded-value expressions(8p12). Discarded-value
expressions are expressions that have been converted to void (8.2.9p6),
are the left operand of comma operator (8.19p1), or the entire
expression in an expression statement(9.2).

Barry Schwarz

unread,
Jan 22, 2018, 12:10:17 PM1/22/18
to
On 22 Jan 2018 13:24:55 GMT, arnuld <sun...@invalid.address> wrote:

>AIM: to print elements of a multidimensional array.
>PROBLEM: it prints addresses
>
>I known from C.7.2 of Stroustrup 3/e that there are no multidimensional
>arrays on hardware level. These dimensions exist in compiler-source only.
>Question is a[i] generally prints the value at \i\. Then why not here ?

This faulty assumption is at the root of your confusion. When an
expression is evaluated as the operand of an operator, the result is a
value that has a type. Both value and type can be different for
different operators.

Consider the case
char c[4] = {5,9,18,3};
char *p = c;
size_t t = sizeof c;
char (*q)[4] = &c;

c has type array of four char. p has type pointer to char. t has
type size_t which is an alias for some unsigned integer type. q has
type pointer to array of four char.

For purposes of discussion, assume c occupies the four bytes of memory
starting at 0x1000.

c is the right operand of the binary operator =. In evaluating the
expression, the compiler uses the general rule that an expression with
type of array of T is converted to an expression of type pointer to T
with the value address of the first array element. Thus p is assigned
the value 0x1000 with type char*.

c is the operand of the unary operator sizeof. In evaluating the
expression, the compiler uses the exception to the general rule and
does not perform the conversion. Thus t is assigned the value 4 with
type size_t.

c is the operand of the unary operator &. This also is an exception
to the general rule. No conversion is performed and q is assigned
address of the array, value 0x1000 but this time with type (char*)[4].

Note that p and q are not equal. They both point to the same spot in
memory but they need not be the same size or even have the same
internal bit representation.

In your code, arr has type array of four array of four int. Therefore,
arr[0] is the first array (of four int) in that array of four arrays.
arr[1] is the second such array. arr[2][0] is the first int in the
third array of four int. arr[3][2] is the third int in the fourth
array of four int.

When used in an expression of the form
cout << x ....
the << operator is massively overloaded for the various types its
operands can have.
When you code arr[i][j], the compiler will select the overload
version that corresponds to int and you see the value you are
expecting.
When you code arr[i] or arr[j], those expressions have type array
of int and are not exceptions to the general rule. Thus, the
expression is converted and the compiler selects the overload version
that corresponds to int*

Except for char*, the overloaded versions of the << operator that deal
with pointers result in the stream containing the address that was
evaluated (similar to %p in printf) and the contents at that address
are ignored. (The peculiar case of char* is used to insert strings,
as C uses that term, and is similar to %s in printf and the contents
at the address are sent to the stream.)
Remove del for email

Christian Gollwitzer

unread,
Jan 23, 2018, 1:45:17 AM1/23/18
to
Am 22.01.18 um 14:24 schrieb arnuld:
> #include <iostream>
> #include <string>
>
> using std::cout;
>
> int main()
> {
> int arr[4][4];
>
> for(int i = 0; i != 4; ++i)
> {
> for(int j = 0; j != 4; ++j)
> {
> arr[i][j] = i+j;
> cout << "arr[" << i << "][" << j << "] = arr[" << arr[i] << "["
> << arr[j] << "]\n";
> //cout << arr[i][j] << " ";

Replace this line by:

cout << "arr[" << i << "][" << j << "] = " << arr[i] << "["
<< j << "] = " <<arr[i][j] << std::endl;

to see how the compiler resolves the expression a[i][j]

> }
> }
>
>
>
> return 0;
> }

Christian

arnuld

unread,
Jan 24, 2018, 1:51:31 AM1/24/18
to
> On Mon, 22 Jan 2018 09:09:53 -0800, Barry Schwarz wrote:

> This faulty assumption is at the root of your confusion. When an
> expression is evaluated as the operand of an operator, the result is a
> value that has a type. Both value and type can be different for
> different operators.
>
> Consider the case
> char c[4] = {5,9,18,3};
> char *p = c;
> size_t t = sizeof c;
> char (*q)[4] = &c;
> [..SNIP..]
> [..SNIP..]
> Except for char*, the overloaded versions of the << operator that deal
> with pointers result in the stream containing the address that was
> evaluated (similar to %p in printf) and the contents at that address are
> ignored. (The peculiar case of char* is used to insert strings, as C
> uses that term, and is similar to %s in printf and the contents at the
> address are sent to the stream.)

Wow... the best explanation I have ever come across Thanks Barry
0 new messages