473,770 Members | 2,120 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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 counterintuitiv e, though; do you know
the truth?

Thanks a lot in advance,
Bernd Gaertner.

#include<iostre am>

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 4384
On Nov 12, 1:58 pm, Bernd Gaertner <gaert...@inf.e thz.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 counterintuitiv e, though; do you know
the truth?
Neither are legal, although both are likely to work on most
implementations .
#include<iostre am>

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 objektorientier ter Datenverarbeitu ng
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<iostr eam>

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<iost ream>

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
2190
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 array. Why does bp point to some address that is not &d? Please clarify. Thanks,
22
12749
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 exactly this, and similarly generic functions seem to have useful applications. In a few posts I read, it was suggested to avoid void pointer arithmetic by casting to a char pointer, and performing arithmetic on that (in multiples of...
6
2295
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
2211
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 reading The C Programming Language Second Edition.. When i hit on pointer arithmetic example, i have no idea what's happening, hopefully some of you could alleviate my confusion, so here goes:
27
8975
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 advance. Erik
7
528
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
3063
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 read some of the items from the bottom up of the buffer, and some from the top down, moving the bottom items back to the new re-allocated bottom on every file read. Then when I've read all four files, I sort the top and bottom items separately...
41
3686
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 pointer and reference are and how they relate to each other.
3
1736
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++=' '; So please suggest as to what i have to do? Am i doing wrong by converting char* to String* in managed VC.net. Thanks, Dipesh.
19
3902
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
9454
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10260
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10101
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
8933
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, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7456
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6712
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 then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5354
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
4007
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
2850
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.