473,411 Members | 1,937 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,411 software developers and data experts.

pointer arithmetic and multi-dimensional arrays

Dear experts,

according to my interpretation of the Standard, loop 1 in the
following program is legal, while loop 2 is not (see explanation
below). This looks a bit counterintuitive, though; do you know
the truth?

Thanks a lot in advance,
Bernd Gaertner.

#include<iostream>

int main()
{
int a[2][3] = { {0, 1, 2}, {3, 4, 5} };
int* first = a[0]; // pointer to a[0][0]

// loop 1
for (int* p = first; p < first+6; ++p)
std::cout << *p; // 012345

// loop 2
for (int* p = first; p < first+6; p+=2)
std::cout << *p; // 024

return 0;
}

Explanation: [decl.array] 7-9 implies that the memory layout of
"int a[3][2]" is as for "int a[6]" - the six ints are consecutive
in memory. This means that during any iteration of loop 1, both p
and ++p are pointers to elements (or past-the-end pointers) of the
*same* three-element array, namely either a[0] or a[1]. In this
case, [expr.add] 5 guarantees well-defined behavior. In loop 2,
if p == first+2 (pointer to last element of a[0]), p+=2 points to
the second element of a[1], so p and p+=2 do not refer to the same
array. In this case, [expr.add] 5 stipulates undefined behavior.
Nov 12 '07 #1
4 4362
On Nov 12, 1:58 pm, Bernd Gaertner <gaert...@inf.ethz.chwrote:
according to my interpretation of the Standard, loop 1 in the
following program is legal, while loop 2 is not (see explanation
below). This looks a bit counterintuitive, though; do you know
the truth?
Neither are legal, although both are likely to work on most
implementations.
#include<iostream>

int main()
{
int a[2][3] = { {0, 1, 2}, {3, 4, 5} };
int* first = a[0]; // pointer to a[0][0]
More precisely: a pointer to the first element in a[0]. More
precisely, a pointer to an int which is the first element of an
array of 3 ints. Legal values for this pointer a thus first,
first+1, first+2 and first+3; the last may not be dereferenced.

In practice, the only time this will fail is with a bounds
checking implementation using fat pointers. (CenterLine once
sold such a compiler; I don't know what the current status is,
but ICS is still selling a compiler under the CenterLine mark.)
// loop 1
for (int* p = first; p < first+6; ++p)
std::cout << *p; // 012345
// loop 2
for (int* p = first; p < first+6; p+=2)
std::cout << *p; // 024
return 0;
}
Explanation: [decl.array] 7-9 implies that the memory layout of
"int a[3][2]" is as for "int a[6]" - the six ints are consecutive
in memory.
Yes, but it's not too clear what you can do with that. The
standard has been very carefully worded to allow compiler bounds
checking (even if no one, or almost no one, does it). When you
assign a[0] to first, the bounds are a[0][0]...a[0][3]. A
compiler is allowed to maintain this information with the
pointer (i.e. a fat pointer), and check it each time you modify
the pointer.
This means that during any iteration of loop 1, both p
and ++p are pointers to elements (or past-the-end pointers) of the
*same* three-element array, namely either a[0] or a[1]. In this
case, [expr.add] 5 guarantees well-defined behavior. In loop 2,
if p == first+2 (pointer to last element of a[0]), p+=2 points to
the second element of a[1], so p and p+=2 do not refer to the same
array. In this case, [expr.add] 5 stipulates undefined behavior.
That's a different problem. Obviously, a bounds checking
implementation would fail here; supposedly, at least, there have
also been cases where it would fail in special cases without
bounds checking. (I don't think it would ever fail without
bounds checking for an on stack array of small elements like
int. It might fail if the array were dynamically allocated,
however, or if the elements were significantly larger---things
that could cause the pointer to point to memory that didn't
exist or that wasn't mapped.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Nov 13 '07 #2
Thanks a lot, for your answer, Alf! There are some things I still don't
understand, though (and yes, it's homework-related, but not my homework
but that of my students).

Alf P. Steinbach wrote:
>#include<iostream>

int main()
{
int a[2][3] = { {0, 1, 2}, {3, 4, 5} };
int* first = a[0]; // pointer to a[0][0]

// loop 1
for (int* p = first; p < first+6; ++p)
std::cout << *p; // 012345

// loop 2
for (int* p = first; p < first+6; p+=2)
std::cout << *p; // 024

return 0;
}
You have no guarantee that a pointer to the first array element can be
treated as a pointer to the array. On a segmented architecture the
pointers might theoretically (although not in practice) be completely
different beast, and the two inner arrays might reside in different
segments, "you can't get there from here".
This seems to be in contradiction to [dcl.array] 1 where it is stated
that "An object of array type contains a contiguously allocated nonempty
subset of N subobjects of type T". And a twodimensional array is simply
an array where T is another array type.
>In loop 2,
if p == first+2 (pointer to last element of a[0]), p+=2 points to
the second element of a[1], so p and p+=2 do not refer to the same
array. In this case, [expr.add] 5 stipulates undefined behavior.

The reasoning here seems to not be meaningful in any way, but the
conclusion is just about right.
The reasoning was based on the assumed fact that the two subarrays are
contiguoulsy allocated in memory.
On the suspicion that this is HOMEWORK, I'll leave it as an exercise to
figure out why the second loop has formally Undefined Behavior in
addition to the UB considerations that apply to the first loop.
I figured one thing out that also applies to loop 1 (stupid me): the
behavior of the operation "first+6" is already undefined since first and
the result first+6 definitely do not point to elements (or past the end)
of the same array. But what if we loop as follows?

// loop 1
int* p = first;
for (int i=0; i<6; ++i)
std::cout << *p++; // 012345
Nov 13 '07 #3
Bernd Gaertner wrote:
Thanks a lot, for your answer, Alf! There are some things I still don't
understand, though (and yes, it's homework-related, but not my homework
but that of my students).

Alf P. Steinbach wrote:
>>#include<iostream>

int main()
{
int a[2][3] = { {0, 1, 2}, {3, 4, 5} };
int* first = a[0]; // pointer to a[0][0]

// loop 1
for (int* p = first; p < first+6; ++p)
std::cout << *p; // 012345

// loop 2
for (int* p = first; p < first+6; p+=2)
std::cout << *p; // 024

return 0;
}
>You have no guarantee that a pointer to the first array element can be
treated as a pointer to the array. On a segmented architecture the
pointers might theoretically (although not in practice) be completely
different beast, and the two inner arrays might reside in different
segments, "you can't get there from here".

This seems to be in contradiction to [dcl.array] 1 where it is stated
that "An object of array type contains a contiguously allocated nonempty
subset of N subobjects of type T". And a twodimensional array is simply
an array where T is another array type.
That only concerns the layout of the arrays in memory. It does not concern
what you can do with pointer arithmetic. The standard does not preclude an
implementation to perform bounds checking. In particular, an implementation
is allowed to use decorated pointers that keep track of the range of
validity for pointer arithmetic through extra data not used in
dereferencing. Although this may not correspond to the intuitive notion of
a pointer, it is a perfectly valid implementation. The compiler would
deduce such ranges of validity from type information. In the above cases,
range checking would find an access violation once you increment p past the
bound of the 1D-array used to initialize it.
[snip]

Best

Kai-Uwe Bux
Nov 13 '07 #4
Thanks for all your in-depth answers! I understand the issue much better
now, and in retrospect it was somewhat naive to expect defined behavior
for the loops in my original posting.

Best regards,
Bernd.
Nov 13 '07 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: ceo | last post by:
Hi, Following is a program that doesn't give the expected output, not sure what's wrong here. I'm adding the size of derived class to the base class pointer to access the next element in the...
22
by: Alex Fraser | last post by:
From searching Google Groups, I understand that void pointer arithmetic is a constraint violation, which is understandable. However, generic functions like qsort() and bsearch() must in essence do...
6
by: Francois Grieu | last post by:
Are these programs correct ? #include <stdio.h> unsigned char a = {1,2}; int main(void) { unsigned char j; for(j=1; j<=2; ++j) printf("%u\n", *( a+j-1 )); return 0; }
3
by: randomtalk | last post by:
hello everyone! Well, recently i've been trying to pick up c and see what is pointer all about (been programming in lisp/python for the better part of my last two years).. mmm.. I'm currently...
27
by: Erik de Castro Lopo | last post by:
Hi all, The GNU C compiler allows a void pointer to be incremented and the behaviour is equivalent to incrementing a char pointer. Is this legal C99 or is this a GNU C extention? Thanks in...
7
by: barikat | last post by:
int a; int *Ptr1, *Ptr2; Ptr1 = a; Ptr1++; Ptr2 = a; printf("Ptr1 : %p\n", Ptr1); printf("Ptr2 : %p\n\n", Ptr2);
26
by: Bill Reid | last post by:
Bear with me, as I am not a "professional" programmer, but I was working on part of program that reads parts of four text files into a buffer which I re-allocate the size as I read each file. I...
41
by: Summercool | last post by:
Can we confirm the following? also someone said, Java also has "reference" like in C++, which is an "implicit pointer": Pointer and Reference --------------------- I am starting to see what...
3
by: =?Utf-8?B?RGlwZXNoX1NoYXJtYQ==?= | last post by:
Hi all, I am porting my code in VC++ to VC.net i.e managed. I have seen somewhere that i need to convert my char* to String*, but String * doesnt perform pointer arithmetic like String* p; *p++='...
19
by: =?iso-8859-1?b?VG9t4XMg0yBoyWlsaWRoZQ==?= | last post by:
Coming originally from C++, I used to do the likes of the following, using a pointer in a conditional: void Func(int *p) { if (p) { *p++ = 7; *p++ = 8;
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.