Understanding allocated memory addresses in array elements in C (gcc in Windows 10)
I'm trying to get a grip on pointers and arrays in C. Now, I'm stuck on trying to figure out how my C compiler allocates memory for the elements in a two dimensional array. Here's my example code:
#include <stdio.h>
int main(void)
{
int ar[2][2] = { {1, 2}, {3, 4} };
printf("sizeof(int) = %un-----n", sizeof(int));
printf("ar = %pn", ar);
printf("ar + 1 = %pn", ar + 1);
printf("&ar = %pn", &ar);
printf("&ar + 1 = %pnn", &ar + 1);
printf("sizeof(ar) = %un-----n", sizeof(ar));
printf("ar[0] = %pn", ar[0]);
printf("ar[0] + 1 = %pn", ar[0] + 1);
printf("&ar[0] = %pn", &ar[0]);
printf("&ar[0] + 1 = %pnn", &ar[0] + 1);
printf("sizeof(ar[0]) = %un-----n", sizeof(ar[0]));
printf("ar[1] = %pn", ar[1]);
printf("ar[1] + 1 = %pn", ar[1] + 1);
printf("&ar[1] = %pn", &ar[1]);
printf("&ar[1] + 1 = %pnn", &ar[1] + 1);
printf("sizeof(ar[1]) = %un-----n", sizeof(ar[1]));
printf("&ar[0][0] = %pn", &ar[0][0]);
printf("&ar[0][0] + 1 = %pn", &ar[0][0] + 1);
printf("&ar[1][0] = %pn", &ar[1][0]);
printf("&ar[1][0] + 1 = %pnn", &ar[1][0] + 1);
printf("sizeof(ar[0][0]) = %un-----n", sizeof(ar[0][0]));
return 0;
}
The output I get on my system is:
sizeof(int) = 4
-----
ar = 0061FF20
ar + 1 = 0061FF28
&ar = 0061FF20
&ar + 1 = 0061FF30
sizeof(ar) = 16
-----
ar[0] = 0061FF20
ar[0] + 1 = 0061FF24
&ar[0] = 0061FF20
&ar[0] + 1 = 0061FF28
sizeof(ar[0]) = 8
-----
ar[1] = 0061FF28
ar[1] + 1 = 0061FF2C
&ar[1] = 0061FF28
&ar[1] + 1 = 0061FF30
sizeof(ar[1]) = 8
-----
&ar[0][0] = 0061FF20
&ar[0][0] + 1 = 0061FF24
&ar[1][0] = 0061FF28
&ar[1][0] + 1 = 0061FF2C
sizeof(ar[0][0]) = 4
-----
I understand why ar
is 16 bytes in size; it should be able to hold 4 int
s, which on my system is 4x4 = 16 bytes. This, I guess, is also why the difference in bytes between &ar + 1
and &ar
is (hex) 30 - 20 = 16.
What I don't understand is why the difference between ar + 1
and ar
is only 8 bytes. This would mean that the array can only hold 2 int
s á 4 bytes.
I have the same problem understanding ar[0]
and ar[1]
as you can see in my code.
Shouldn't ar + 1
and &ar + 1
produce the same result?
c arrays memory pointer-arithmetic
add a comment |
I'm trying to get a grip on pointers and arrays in C. Now, I'm stuck on trying to figure out how my C compiler allocates memory for the elements in a two dimensional array. Here's my example code:
#include <stdio.h>
int main(void)
{
int ar[2][2] = { {1, 2}, {3, 4} };
printf("sizeof(int) = %un-----n", sizeof(int));
printf("ar = %pn", ar);
printf("ar + 1 = %pn", ar + 1);
printf("&ar = %pn", &ar);
printf("&ar + 1 = %pnn", &ar + 1);
printf("sizeof(ar) = %un-----n", sizeof(ar));
printf("ar[0] = %pn", ar[0]);
printf("ar[0] + 1 = %pn", ar[0] + 1);
printf("&ar[0] = %pn", &ar[0]);
printf("&ar[0] + 1 = %pnn", &ar[0] + 1);
printf("sizeof(ar[0]) = %un-----n", sizeof(ar[0]));
printf("ar[1] = %pn", ar[1]);
printf("ar[1] + 1 = %pn", ar[1] + 1);
printf("&ar[1] = %pn", &ar[1]);
printf("&ar[1] + 1 = %pnn", &ar[1] + 1);
printf("sizeof(ar[1]) = %un-----n", sizeof(ar[1]));
printf("&ar[0][0] = %pn", &ar[0][0]);
printf("&ar[0][0] + 1 = %pn", &ar[0][0] + 1);
printf("&ar[1][0] = %pn", &ar[1][0]);
printf("&ar[1][0] + 1 = %pnn", &ar[1][0] + 1);
printf("sizeof(ar[0][0]) = %un-----n", sizeof(ar[0][0]));
return 0;
}
The output I get on my system is:
sizeof(int) = 4
-----
ar = 0061FF20
ar + 1 = 0061FF28
&ar = 0061FF20
&ar + 1 = 0061FF30
sizeof(ar) = 16
-----
ar[0] = 0061FF20
ar[0] + 1 = 0061FF24
&ar[0] = 0061FF20
&ar[0] + 1 = 0061FF28
sizeof(ar[0]) = 8
-----
ar[1] = 0061FF28
ar[1] + 1 = 0061FF2C
&ar[1] = 0061FF28
&ar[1] + 1 = 0061FF30
sizeof(ar[1]) = 8
-----
&ar[0][0] = 0061FF20
&ar[0][0] + 1 = 0061FF24
&ar[1][0] = 0061FF28
&ar[1][0] + 1 = 0061FF2C
sizeof(ar[0][0]) = 4
-----
I understand why ar
is 16 bytes in size; it should be able to hold 4 int
s, which on my system is 4x4 = 16 bytes. This, I guess, is also why the difference in bytes between &ar + 1
and &ar
is (hex) 30 - 20 = 16.
What I don't understand is why the difference between ar + 1
and ar
is only 8 bytes. This would mean that the array can only hold 2 int
s á 4 bytes.
I have the same problem understanding ar[0]
and ar[1]
as you can see in my code.
Shouldn't ar + 1
and &ar + 1
produce the same result?
c arrays memory pointer-arithmetic
You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]
– SPlatten
Nov 26 '18 at 10:44
Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?
– Jens M.
Nov 26 '18 at 11:12
add a comment |
I'm trying to get a grip on pointers and arrays in C. Now, I'm stuck on trying to figure out how my C compiler allocates memory for the elements in a two dimensional array. Here's my example code:
#include <stdio.h>
int main(void)
{
int ar[2][2] = { {1, 2}, {3, 4} };
printf("sizeof(int) = %un-----n", sizeof(int));
printf("ar = %pn", ar);
printf("ar + 1 = %pn", ar + 1);
printf("&ar = %pn", &ar);
printf("&ar + 1 = %pnn", &ar + 1);
printf("sizeof(ar) = %un-----n", sizeof(ar));
printf("ar[0] = %pn", ar[0]);
printf("ar[0] + 1 = %pn", ar[0] + 1);
printf("&ar[0] = %pn", &ar[0]);
printf("&ar[0] + 1 = %pnn", &ar[0] + 1);
printf("sizeof(ar[0]) = %un-----n", sizeof(ar[0]));
printf("ar[1] = %pn", ar[1]);
printf("ar[1] + 1 = %pn", ar[1] + 1);
printf("&ar[1] = %pn", &ar[1]);
printf("&ar[1] + 1 = %pnn", &ar[1] + 1);
printf("sizeof(ar[1]) = %un-----n", sizeof(ar[1]));
printf("&ar[0][0] = %pn", &ar[0][0]);
printf("&ar[0][0] + 1 = %pn", &ar[0][0] + 1);
printf("&ar[1][0] = %pn", &ar[1][0]);
printf("&ar[1][0] + 1 = %pnn", &ar[1][0] + 1);
printf("sizeof(ar[0][0]) = %un-----n", sizeof(ar[0][0]));
return 0;
}
The output I get on my system is:
sizeof(int) = 4
-----
ar = 0061FF20
ar + 1 = 0061FF28
&ar = 0061FF20
&ar + 1 = 0061FF30
sizeof(ar) = 16
-----
ar[0] = 0061FF20
ar[0] + 1 = 0061FF24
&ar[0] = 0061FF20
&ar[0] + 1 = 0061FF28
sizeof(ar[0]) = 8
-----
ar[1] = 0061FF28
ar[1] + 1 = 0061FF2C
&ar[1] = 0061FF28
&ar[1] + 1 = 0061FF30
sizeof(ar[1]) = 8
-----
&ar[0][0] = 0061FF20
&ar[0][0] + 1 = 0061FF24
&ar[1][0] = 0061FF28
&ar[1][0] + 1 = 0061FF2C
sizeof(ar[0][0]) = 4
-----
I understand why ar
is 16 bytes in size; it should be able to hold 4 int
s, which on my system is 4x4 = 16 bytes. This, I guess, is also why the difference in bytes between &ar + 1
and &ar
is (hex) 30 - 20 = 16.
What I don't understand is why the difference between ar + 1
and ar
is only 8 bytes. This would mean that the array can only hold 2 int
s á 4 bytes.
I have the same problem understanding ar[0]
and ar[1]
as you can see in my code.
Shouldn't ar + 1
and &ar + 1
produce the same result?
c arrays memory pointer-arithmetic
I'm trying to get a grip on pointers and arrays in C. Now, I'm stuck on trying to figure out how my C compiler allocates memory for the elements in a two dimensional array. Here's my example code:
#include <stdio.h>
int main(void)
{
int ar[2][2] = { {1, 2}, {3, 4} };
printf("sizeof(int) = %un-----n", sizeof(int));
printf("ar = %pn", ar);
printf("ar + 1 = %pn", ar + 1);
printf("&ar = %pn", &ar);
printf("&ar + 1 = %pnn", &ar + 1);
printf("sizeof(ar) = %un-----n", sizeof(ar));
printf("ar[0] = %pn", ar[0]);
printf("ar[0] + 1 = %pn", ar[0] + 1);
printf("&ar[0] = %pn", &ar[0]);
printf("&ar[0] + 1 = %pnn", &ar[0] + 1);
printf("sizeof(ar[0]) = %un-----n", sizeof(ar[0]));
printf("ar[1] = %pn", ar[1]);
printf("ar[1] + 1 = %pn", ar[1] + 1);
printf("&ar[1] = %pn", &ar[1]);
printf("&ar[1] + 1 = %pnn", &ar[1] + 1);
printf("sizeof(ar[1]) = %un-----n", sizeof(ar[1]));
printf("&ar[0][0] = %pn", &ar[0][0]);
printf("&ar[0][0] + 1 = %pn", &ar[0][0] + 1);
printf("&ar[1][0] = %pn", &ar[1][0]);
printf("&ar[1][0] + 1 = %pnn", &ar[1][0] + 1);
printf("sizeof(ar[0][0]) = %un-----n", sizeof(ar[0][0]));
return 0;
}
The output I get on my system is:
sizeof(int) = 4
-----
ar = 0061FF20
ar + 1 = 0061FF28
&ar = 0061FF20
&ar + 1 = 0061FF30
sizeof(ar) = 16
-----
ar[0] = 0061FF20
ar[0] + 1 = 0061FF24
&ar[0] = 0061FF20
&ar[0] + 1 = 0061FF28
sizeof(ar[0]) = 8
-----
ar[1] = 0061FF28
ar[1] + 1 = 0061FF2C
&ar[1] = 0061FF28
&ar[1] + 1 = 0061FF30
sizeof(ar[1]) = 8
-----
&ar[0][0] = 0061FF20
&ar[0][0] + 1 = 0061FF24
&ar[1][0] = 0061FF28
&ar[1][0] + 1 = 0061FF2C
sizeof(ar[0][0]) = 4
-----
I understand why ar
is 16 bytes in size; it should be able to hold 4 int
s, which on my system is 4x4 = 16 bytes. This, I guess, is also why the difference in bytes between &ar + 1
and &ar
is (hex) 30 - 20 = 16.
What I don't understand is why the difference between ar + 1
and ar
is only 8 bytes. This would mean that the array can only hold 2 int
s á 4 bytes.
I have the same problem understanding ar[0]
and ar[1]
as you can see in my code.
Shouldn't ar + 1
and &ar + 1
produce the same result?
c arrays memory pointer-arithmetic
c arrays memory pointer-arithmetic
edited Nov 26 '18 at 10:47
Sourav Ghosh
111k15132191
111k15132191
asked Nov 26 '18 at 10:30
Jens M.Jens M.
132
132
You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]
– SPlatten
Nov 26 '18 at 10:44
Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?
– Jens M.
Nov 26 '18 at 11:12
add a comment |
You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]
– SPlatten
Nov 26 '18 at 10:44
Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?
– Jens M.
Nov 26 '18 at 11:12
You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]
– SPlatten
Nov 26 '18 at 10:44
You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]
– SPlatten
Nov 26 '18 at 10:44
Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?
– Jens M.
Nov 26 '18 at 11:12
Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?
– Jens M.
Nov 26 '18 at 11:12
add a comment |
3 Answers
3
active
oldest
votes
In your case, ar
is an array. Hence, first of all, remember
ar
is type ofint [2][2]
, which is an array of array ofint
s
&ar
is of typeint (*)[2][2]
, i.e., pointer to an array of array of 2int
s.
That said, array type, in cases, decay to the pointer to the first element of the array.Note
So, in case of an expression like
ar + 1
is just the same as
(&(ar[0])) + 1;
which basically points to ar[1]
.
What I don't understand is why the difference between
ar + 1
andar
is only 8 bytes
So, the "difference" here, is by the size occupied by the elements of ar[0]
, which is , 2 ints
, which is, in your platform, 8 bytes. Result checks out.
On the other hand, for an expression like
&ar + 1;
it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. So, the difference is, for 2 arrays of 2 int
s each, hence (2*2*4) = 16 bytes.
Note:
Quoting C11
, chapter §6.3.2.1
Except when it is the operand of the
sizeof
operator, the_Alignof
operator, or the
unary&
operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [....]
add a comment |
ar
, when used in an expression, "decays" to a pointer to the first element. In this case, arr + 1
gives arithmetic on a pointer of type int (*)[2]
. Which points to an int [2]
with size 8 bytes.
This rule of "array decay" is specified in C17 6.3.2.1 §3:
Except when it is the operand of the sizeof operator, or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue
So when you type &ar
, you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2]
as expected. And therefore &ar + 1
gives 16 bytes.
add a comment |
So:
sizeof(int) == 4
The following:
int ar[2][2];
is a 2D array.
We know that, a[b]
is equal to *(a + b)
. And &*
is converted to nothing.
So:
&ar[1]
is equal to
(ar + 1)
here ar
"decays" or "shall be adjusted" (read as: magically converts) into a pointer. A pointer to an array of two int elements, ie. int (*)[2]
. So it's not an int *
nor int[2][2]
pointer but int (*)[2]
. We know that
sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)
So
(ar + 1)
is equal to (to the value):
(uintptr_t)ar + sizeof(*ar) * 1 ==
(uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
(uintptr_t)ar + sizeof(int[2]) * 1) ==
(uintptr_t)ar + sizeof(int) * 2 * 1)
ie. it increments the ar
pointer value by 2 * sizeof(int)
.
What I don't understand is why the difference between ar + 1 and ar is only 8 bytes.
ar + 1
is equal to
(uintptr_t)ar + sizeof(*ar) + 1
As ar
is int[2][2]
, then *ar
is int[2]
, so sizeof(*ar) = sizeof(int) * 2
.
So ar + 1
is equal to
(uintptr_t)ar + sizeof(int) * 2 * 1
So (ar + 1) - ar
is equal to
((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
sizeof(int[2]) ==
sizeof(int) * 2
Shouldn't ar + 1 and &ar + 1 produce the same result?
In case of arrays like int array[2];
The array
pointer value is equal to &array
pointer value. It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. Through array
has a type of int[2][2]
, but &array
has the type of int(*)[2][2]
, ie. it is a pointer to 2d array.
Because the type changes, the pointer arithmetics changes. Teh typeof(ar)
decays to typeof(int(*)[2])
so the ar + 1
is equal to
`(uintptr_t)ar + sizeof(int[2]) * 1`.
But because the typeof(&ar) == typeof(int(*)[2][2])
the &ar + 1
is equal to
`(uintrpt_t)ar + sizeof(int[2][2]) * 1`.
hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2])
is equal to sizeof(int) * 2 * 2
.
I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. So typeof(ar[0])
is an array of two int elements.
Your code has UB, as the %p
modifer should be used only with void*
pointers. It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1);
cast your pointers.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53479169%2funderstanding-allocated-memory-addresses-in-array-elements-in-c-gcc-in-windows%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
In your case, ar
is an array. Hence, first of all, remember
ar
is type ofint [2][2]
, which is an array of array ofint
s
&ar
is of typeint (*)[2][2]
, i.e., pointer to an array of array of 2int
s.
That said, array type, in cases, decay to the pointer to the first element of the array.Note
So, in case of an expression like
ar + 1
is just the same as
(&(ar[0])) + 1;
which basically points to ar[1]
.
What I don't understand is why the difference between
ar + 1
andar
is only 8 bytes
So, the "difference" here, is by the size occupied by the elements of ar[0]
, which is , 2 ints
, which is, in your platform, 8 bytes. Result checks out.
On the other hand, for an expression like
&ar + 1;
it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. So, the difference is, for 2 arrays of 2 int
s each, hence (2*2*4) = 16 bytes.
Note:
Quoting C11
, chapter §6.3.2.1
Except when it is the operand of the
sizeof
operator, the_Alignof
operator, or the
unary&
operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [....]
add a comment |
In your case, ar
is an array. Hence, first of all, remember
ar
is type ofint [2][2]
, which is an array of array ofint
s
&ar
is of typeint (*)[2][2]
, i.e., pointer to an array of array of 2int
s.
That said, array type, in cases, decay to the pointer to the first element of the array.Note
So, in case of an expression like
ar + 1
is just the same as
(&(ar[0])) + 1;
which basically points to ar[1]
.
What I don't understand is why the difference between
ar + 1
andar
is only 8 bytes
So, the "difference" here, is by the size occupied by the elements of ar[0]
, which is , 2 ints
, which is, in your platform, 8 bytes. Result checks out.
On the other hand, for an expression like
&ar + 1;
it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. So, the difference is, for 2 arrays of 2 int
s each, hence (2*2*4) = 16 bytes.
Note:
Quoting C11
, chapter §6.3.2.1
Except when it is the operand of the
sizeof
operator, the_Alignof
operator, or the
unary&
operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [....]
add a comment |
In your case, ar
is an array. Hence, first of all, remember
ar
is type ofint [2][2]
, which is an array of array ofint
s
&ar
is of typeint (*)[2][2]
, i.e., pointer to an array of array of 2int
s.
That said, array type, in cases, decay to the pointer to the first element of the array.Note
So, in case of an expression like
ar + 1
is just the same as
(&(ar[0])) + 1;
which basically points to ar[1]
.
What I don't understand is why the difference between
ar + 1
andar
is only 8 bytes
So, the "difference" here, is by the size occupied by the elements of ar[0]
, which is , 2 ints
, which is, in your platform, 8 bytes. Result checks out.
On the other hand, for an expression like
&ar + 1;
it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. So, the difference is, for 2 arrays of 2 int
s each, hence (2*2*4) = 16 bytes.
Note:
Quoting C11
, chapter §6.3.2.1
Except when it is the operand of the
sizeof
operator, the_Alignof
operator, or the
unary&
operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [....]
In your case, ar
is an array. Hence, first of all, remember
ar
is type ofint [2][2]
, which is an array of array ofint
s
&ar
is of typeint (*)[2][2]
, i.e., pointer to an array of array of 2int
s.
That said, array type, in cases, decay to the pointer to the first element of the array.Note
So, in case of an expression like
ar + 1
is just the same as
(&(ar[0])) + 1;
which basically points to ar[1]
.
What I don't understand is why the difference between
ar + 1
andar
is only 8 bytes
So, the "difference" here, is by the size occupied by the elements of ar[0]
, which is , 2 ints
, which is, in your platform, 8 bytes. Result checks out.
On the other hand, for an expression like
&ar + 1;
it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. So, the difference is, for 2 arrays of 2 int
s each, hence (2*2*4) = 16 bytes.
Note:
Quoting C11
, chapter §6.3.2.1
Except when it is the operand of the
sizeof
operator, the_Alignof
operator, or the
unary&
operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [....]
edited Nov 26 '18 at 10:44
answered Nov 26 '18 at 10:37
Sourav GhoshSourav Ghosh
111k15132191
111k15132191
add a comment |
add a comment |
ar
, when used in an expression, "decays" to a pointer to the first element. In this case, arr + 1
gives arithmetic on a pointer of type int (*)[2]
. Which points to an int [2]
with size 8 bytes.
This rule of "array decay" is specified in C17 6.3.2.1 §3:
Except when it is the operand of the sizeof operator, or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue
So when you type &ar
, you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2]
as expected. And therefore &ar + 1
gives 16 bytes.
add a comment |
ar
, when used in an expression, "decays" to a pointer to the first element. In this case, arr + 1
gives arithmetic on a pointer of type int (*)[2]
. Which points to an int [2]
with size 8 bytes.
This rule of "array decay" is specified in C17 6.3.2.1 §3:
Except when it is the operand of the sizeof operator, or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue
So when you type &ar
, you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2]
as expected. And therefore &ar + 1
gives 16 bytes.
add a comment |
ar
, when used in an expression, "decays" to a pointer to the first element. In this case, arr + 1
gives arithmetic on a pointer of type int (*)[2]
. Which points to an int [2]
with size 8 bytes.
This rule of "array decay" is specified in C17 6.3.2.1 §3:
Except when it is the operand of the sizeof operator, or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue
So when you type &ar
, you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2]
as expected. And therefore &ar + 1
gives 16 bytes.
ar
, when used in an expression, "decays" to a pointer to the first element. In this case, arr + 1
gives arithmetic on a pointer of type int (*)[2]
. Which points to an int [2]
with size 8 bytes.
This rule of "array decay" is specified in C17 6.3.2.1 §3:
Except when it is the operand of the sizeof operator, or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue
So when you type &ar
, you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2]
as expected. And therefore &ar + 1
gives 16 bytes.
answered Nov 26 '18 at 10:40
LundinLundin
112k17163271
112k17163271
add a comment |
add a comment |
So:
sizeof(int) == 4
The following:
int ar[2][2];
is a 2D array.
We know that, a[b]
is equal to *(a + b)
. And &*
is converted to nothing.
So:
&ar[1]
is equal to
(ar + 1)
here ar
"decays" or "shall be adjusted" (read as: magically converts) into a pointer. A pointer to an array of two int elements, ie. int (*)[2]
. So it's not an int *
nor int[2][2]
pointer but int (*)[2]
. We know that
sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)
So
(ar + 1)
is equal to (to the value):
(uintptr_t)ar + sizeof(*ar) * 1 ==
(uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
(uintptr_t)ar + sizeof(int[2]) * 1) ==
(uintptr_t)ar + sizeof(int) * 2 * 1)
ie. it increments the ar
pointer value by 2 * sizeof(int)
.
What I don't understand is why the difference between ar + 1 and ar is only 8 bytes.
ar + 1
is equal to
(uintptr_t)ar + sizeof(*ar) + 1
As ar
is int[2][2]
, then *ar
is int[2]
, so sizeof(*ar) = sizeof(int) * 2
.
So ar + 1
is equal to
(uintptr_t)ar + sizeof(int) * 2 * 1
So (ar + 1) - ar
is equal to
((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
sizeof(int[2]) ==
sizeof(int) * 2
Shouldn't ar + 1 and &ar + 1 produce the same result?
In case of arrays like int array[2];
The array
pointer value is equal to &array
pointer value. It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. Through array
has a type of int[2][2]
, but &array
has the type of int(*)[2][2]
, ie. it is a pointer to 2d array.
Because the type changes, the pointer arithmetics changes. Teh typeof(ar)
decays to typeof(int(*)[2])
so the ar + 1
is equal to
`(uintptr_t)ar + sizeof(int[2]) * 1`.
But because the typeof(&ar) == typeof(int(*)[2][2])
the &ar + 1
is equal to
`(uintrpt_t)ar + sizeof(int[2][2]) * 1`.
hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2])
is equal to sizeof(int) * 2 * 2
.
I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. So typeof(ar[0])
is an array of two int elements.
Your code has UB, as the %p
modifer should be used only with void*
pointers. It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1);
cast your pointers.
add a comment |
So:
sizeof(int) == 4
The following:
int ar[2][2];
is a 2D array.
We know that, a[b]
is equal to *(a + b)
. And &*
is converted to nothing.
So:
&ar[1]
is equal to
(ar + 1)
here ar
"decays" or "shall be adjusted" (read as: magically converts) into a pointer. A pointer to an array of two int elements, ie. int (*)[2]
. So it's not an int *
nor int[2][2]
pointer but int (*)[2]
. We know that
sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)
So
(ar + 1)
is equal to (to the value):
(uintptr_t)ar + sizeof(*ar) * 1 ==
(uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
(uintptr_t)ar + sizeof(int[2]) * 1) ==
(uintptr_t)ar + sizeof(int) * 2 * 1)
ie. it increments the ar
pointer value by 2 * sizeof(int)
.
What I don't understand is why the difference between ar + 1 and ar is only 8 bytes.
ar + 1
is equal to
(uintptr_t)ar + sizeof(*ar) + 1
As ar
is int[2][2]
, then *ar
is int[2]
, so sizeof(*ar) = sizeof(int) * 2
.
So ar + 1
is equal to
(uintptr_t)ar + sizeof(int) * 2 * 1
So (ar + 1) - ar
is equal to
((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
sizeof(int[2]) ==
sizeof(int) * 2
Shouldn't ar + 1 and &ar + 1 produce the same result?
In case of arrays like int array[2];
The array
pointer value is equal to &array
pointer value. It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. Through array
has a type of int[2][2]
, but &array
has the type of int(*)[2][2]
, ie. it is a pointer to 2d array.
Because the type changes, the pointer arithmetics changes. Teh typeof(ar)
decays to typeof(int(*)[2])
so the ar + 1
is equal to
`(uintptr_t)ar + sizeof(int[2]) * 1`.
But because the typeof(&ar) == typeof(int(*)[2][2])
the &ar + 1
is equal to
`(uintrpt_t)ar + sizeof(int[2][2]) * 1`.
hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2])
is equal to sizeof(int) * 2 * 2
.
I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. So typeof(ar[0])
is an array of two int elements.
Your code has UB, as the %p
modifer should be used only with void*
pointers. It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1);
cast your pointers.
add a comment |
So:
sizeof(int) == 4
The following:
int ar[2][2];
is a 2D array.
We know that, a[b]
is equal to *(a + b)
. And &*
is converted to nothing.
So:
&ar[1]
is equal to
(ar + 1)
here ar
"decays" or "shall be adjusted" (read as: magically converts) into a pointer. A pointer to an array of two int elements, ie. int (*)[2]
. So it's not an int *
nor int[2][2]
pointer but int (*)[2]
. We know that
sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)
So
(ar + 1)
is equal to (to the value):
(uintptr_t)ar + sizeof(*ar) * 1 ==
(uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
(uintptr_t)ar + sizeof(int[2]) * 1) ==
(uintptr_t)ar + sizeof(int) * 2 * 1)
ie. it increments the ar
pointer value by 2 * sizeof(int)
.
What I don't understand is why the difference between ar + 1 and ar is only 8 bytes.
ar + 1
is equal to
(uintptr_t)ar + sizeof(*ar) + 1
As ar
is int[2][2]
, then *ar
is int[2]
, so sizeof(*ar) = sizeof(int) * 2
.
So ar + 1
is equal to
(uintptr_t)ar + sizeof(int) * 2 * 1
So (ar + 1) - ar
is equal to
((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
sizeof(int[2]) ==
sizeof(int) * 2
Shouldn't ar + 1 and &ar + 1 produce the same result?
In case of arrays like int array[2];
The array
pointer value is equal to &array
pointer value. It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. Through array
has a type of int[2][2]
, but &array
has the type of int(*)[2][2]
, ie. it is a pointer to 2d array.
Because the type changes, the pointer arithmetics changes. Teh typeof(ar)
decays to typeof(int(*)[2])
so the ar + 1
is equal to
`(uintptr_t)ar + sizeof(int[2]) * 1`.
But because the typeof(&ar) == typeof(int(*)[2][2])
the &ar + 1
is equal to
`(uintrpt_t)ar + sizeof(int[2][2]) * 1`.
hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2])
is equal to sizeof(int) * 2 * 2
.
I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. So typeof(ar[0])
is an array of two int elements.
Your code has UB, as the %p
modifer should be used only with void*
pointers. It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1);
cast your pointers.
So:
sizeof(int) == 4
The following:
int ar[2][2];
is a 2D array.
We know that, a[b]
is equal to *(a + b)
. And &*
is converted to nothing.
So:
&ar[1]
is equal to
(ar + 1)
here ar
"decays" or "shall be adjusted" (read as: magically converts) into a pointer. A pointer to an array of two int elements, ie. int (*)[2]
. So it's not an int *
nor int[2][2]
pointer but int (*)[2]
. We know that
sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)
So
(ar + 1)
is equal to (to the value):
(uintptr_t)ar + sizeof(*ar) * 1 ==
(uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
(uintptr_t)ar + sizeof(int[2]) * 1) ==
(uintptr_t)ar + sizeof(int) * 2 * 1)
ie. it increments the ar
pointer value by 2 * sizeof(int)
.
What I don't understand is why the difference between ar + 1 and ar is only 8 bytes.
ar + 1
is equal to
(uintptr_t)ar + sizeof(*ar) + 1
As ar
is int[2][2]
, then *ar
is int[2]
, so sizeof(*ar) = sizeof(int) * 2
.
So ar + 1
is equal to
(uintptr_t)ar + sizeof(int) * 2 * 1
So (ar + 1) - ar
is equal to
((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
sizeof(int[2]) ==
sizeof(int) * 2
Shouldn't ar + 1 and &ar + 1 produce the same result?
In case of arrays like int array[2];
The array
pointer value is equal to &array
pointer value. It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. Through array
has a type of int[2][2]
, but &array
has the type of int(*)[2][2]
, ie. it is a pointer to 2d array.
Because the type changes, the pointer arithmetics changes. Teh typeof(ar)
decays to typeof(int(*)[2])
so the ar + 1
is equal to
`(uintptr_t)ar + sizeof(int[2]) * 1`.
But because the typeof(&ar) == typeof(int(*)[2][2])
the &ar + 1
is equal to
`(uintrpt_t)ar + sizeof(int[2][2]) * 1`.
hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2])
is equal to sizeof(int) * 2 * 2
.
I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. So typeof(ar[0])
is an array of two int elements.
Your code has UB, as the %p
modifer should be used only with void*
pointers. It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1);
cast your pointers.
edited Nov 26 '18 at 10:59
answered Nov 26 '18 at 10:51
Kamil CukKamil Cuk
12.7k1529
12.7k1529
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53479169%2funderstanding-allocated-memory-addresses-in-array-elements-in-c-gcc-in-windows%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]
– SPlatten
Nov 26 '18 at 10:44
Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?
– Jens M.
Nov 26 '18 at 11:12