Struct pointer vs. struct array pointer

A

aleksa

Say I'm using a standard windows RECT structure...

RECT *prect;

// I can write
prect->left = 0;

// but I can also write
prect[-1].left = 0;
prect[0].left = 0;
prect[1].left = 0;

and the compiler won't complain...
So, what did I define in the first line, a pointer to ONE structure or
a pointer to an ARRAY of structures?

How can I define a pointer to an array?
I don't know in advance how many RECTs there will be in the array.

I'm asking because I can't make WinDbg (nor MSVC debuffer) to show
me the whole array of RECTs.

Thanks
 
M

Malcolm McLean

Say I'm using a standard windows RECT structure...



RECT *prect;


prect->left = 0;
As the code stands, prect is set to whatever random data was in the memory space assigned to it. So the second line sets a random memory location to zero. Usually the result will be a segmentation fault, but not always.

To fix this problem

RECT rect;
prect = ▭

but of course this us useless. Why not just write rect.left = 0 instead?
How can I define a pointer to an array?

I don't know in advance how many RECTs there will be in the array.
It bcoomes useful here

RECT rectarray[15];

rectarray, is to all intents and purposes, a constant pointer to a block of 15 RECTs.

So what if you don't know how many you'll need at compile time?

RECT *rectp = malloc( Nwanted * sizeof(RECT));

for(i=0;i<Nwanted;i++)
rectp.left = 0;

This creates Nwanted RECTs, and sets the left member of them all to zero.
Nwanted can be an input value.
 
S

Sebastian Gesemann

Say I'm using a standard windows RECT structure...

RECT *prect;

I hope that you initialize this pointer to actually point to some RECT
object.
// I can write
prect->left = 0;

// but I can also write
prect[-1].left = 0;
prect[0].left  = 0;
prect[1].left  = 0;

and the compiler won't complain...
So, what did I define in the first line, a pointer to ONE structure or
a pointer to an ARRAY of structures?

You defined prect to be a pointer to _a_ RECT object. However, nothing
stops you from initializing it to point to the first (or any, really)
element of a RECT array.

The syntax

prect[index]

is simply defined to be a short-cut for

*(prect+index)

So, you're just doing pointer arithmetics followed by dereferencing.
If your pointer were to point to the first element of an array, you
could access this first element by

*prect

or alternativly by

prect[0]

Accessing the other array elements, however, is much more convenient
with the latter syntax:

prect[42]

instead of

*(prect+42)

Since the elements of an array are stored contiguously, this kind of
pointer arithmetic is exactly what you need to access the other array
elements.
How can I define a pointer to an array?

You can still use a variable of type RECT* to point to the first
element of an array and access the other elements via the subscript
operator. With respect to its type, it's still just a pointer to a
single RECT. Depending on who you talk to "pointer to an array" could
mean just that, a pointer that points to the first element of an
array. To other people "pointer to array" means that the pointee type
is an array type:

int (*p)[5] = ...;

which reads: p is a pointer to an array of 5 ints. So, there is some
potential for confusion there ...

Check out http://c-faq.com/aryptr/index.html for more details on this
subject. There are a couple of things that you should know including
array-to-pointer decay and the type transformations that are applied
on function parameter types.
I don't know in advance how many RECTs there will be in the array.

Sounds like you're in need for some dynamic buffer implementation that
keeps track of its size and capacity and is able to grow if the
capacity limit is reached. Unfortunately this kind of data structure
is not part of the C standard library. Since I'm a C++ programmer who
can simply #include <vector> I can't give you any good advice on how
to proceed in pure C here. Rolling your own data structures is kind of
a PITA. Maybe you'll find a useful library for that. (GLib?)
I'm asking because I can't make WinDbg (nor MSVC debuffer) to show
me the whole array of RECTs.

That's because the type information of such a pointer doesn't really
tell the debugger whether it points to a single object or a subobject
of an array and how large this array is. You have to do this manually
somehow. A decent debugger should let you evaluate custom expressions
like yourpointer[3] so that it tells you what the 4th element of the
array looks like, for example.
 
J

James Kuyper

On 02/20/2013 04:59 AM, Malcolm McLean wrote:
....
RECT rectarray[15];

rectarray, is to all intents and purposes, a constant pointer to a block of 15 RECTs.

Except, of course, for the purposes of being an operand of the sizeof or
unary & operators. It's not a pointer, it's an array. C makes it easy to
confuse arrays and pointers; you do aleksa a disservice by actively
promoting that confusion.
 
A

aleksa

int (*p)[5] = ...;

Since my only concern here was how to view entire structure array
(or at least some of it) using WinDbg, maybe this is the best:

RECT (*prect2)[100];

now I can view the first 100 entries, which is more than enough.

Now, how do I assigne prect2 to point to the same memory as prect?

prect2 = prect;
prect2 = &prect[0];

both work and both give me the same error
"...differs in levels of indirection from..."
 
B

Ben Bacarisse

aleksa said:
int (*p)[5] = ...;

Since my only concern here was how to view entire structure array
(or at least some of it) using WinDbg, maybe this is the best:

RECT (*prect2)[100];

now I can view the first 100 entries, which is more than enough.

If the purpose is simply to view things in a debugger it seems excessive
to have to alter the source. Can't you use an expression in the
debugger? I.e. where you now say something like "print prect2" could
you not say "print *((*)[100])prect"?
Now, how do I assigne prect2 to point to the same memory as prect?

prect2 = prect;
prect2 = &prect[0];

both work and both give me the same error
"...differs in levels of indirection from..."

prect2 = (void *)prect;
 
J

James Kuyper

int (*p)[5] = ...;

Since my only concern here was how to view entire structure array
(or at least some of it) using WinDbg, maybe this is the best:

RECT (*prect2)[100];

now I can view the first 100 entries, which is more than enough.

Now, how do I assigne prect2 to point to the same memory as prect?

prect2 = prect;
prect2 = &prect[0];

both work and both give me the same error
"...differs in levels of indirection from..."

prect2 = (int (*)[100])prect;

Type punning like this is not actually guaranteed to work, but it is
likely to. However, Ben's suggestion has the same effect without
requiring adding a variable to your program.
 
B

Ben Bacarisse

Ben Bacarisse said:
aleksa said:
int (*p)[5] = ...;

Since my only concern here was how to view entire structure array
(or at least some of it) using WinDbg, maybe this is the best:

RECT (*prect2)[100];

now I can view the first 100 entries, which is more than enough.

If the purpose is simply to view things in a debugger it seems excessive
to have to alter the source. Can't you use an expression in the
debugger? I.e. where you now say something like "print prect2" could
you not say "print *((*)[100])prect"?

I missed the base type out: print *(int (*)[100])prect

<snip>
 
K

Keith Thompson

Malcolm McLean said:
Say I'm using a standard windows RECT structure...
RECT *prect;

prect->left = 0;
As the code stands, prect is set to whatever random data was in the
memory space assigned to it. So the second line sets a random memory
location to zero. Usually the result will be a segmentation fault, but
not always.

To fix this problem

RECT rect;
prect = &rect;

but of course this us useless. Why not just write rect.left = 0 instead?
How can I define a pointer to an array?

I don't know in advance how many RECTs there will be in the array.
It bcoomes useful here

RECT rectarray[15];

rectarray, is to all intents and purposes, a constant pointer to a
block of 15 RECTs.

No, it bloody well is not. Do you think `sizeof rectarray` yields the
size of a pointer?

rectarray is an *array*. An expression of array type, in most contexts,
is implicitly converted to a pointer to the array object's first
element. The exceptions are when it's the operand of sizeof, _Alignof
(new in C99), unary &, and when it's a string literal in an initializer
used to initialize an array object.

Malcolm and aleksa, you should both read section 6 of the comp.lang.c
FAQ, http://www.c-faq.com/.
So what if you don't know how many you'll need at compile time?

RECT *rectp = malloc( Nwanted * sizeof(RECT));

Better:

RECT *rectp = malloc(Nwanted * sizeof *rectp);

(and of course you should check that malloc() returned a non-null
pointer).
for(i=0;i<Nwanted;i++)
rectp.left = 0;

This creates Nwanted RECTs, and sets the left member of them all to zero.
Nwanted can be an input value.
 
K

Keith Thompson

Sebastian Gesemann said:
You can still use a variable of type RECT* to point to the first
element of an array and access the other elements via the subscript
operator. With respect to its type, it's still just a pointer to a
single RECT. Depending on who you talk to

No, it doesn't really depend on who you talk to.
"pointer to an array" could
mean just that, a pointer that points to the first element of an
array.

Those people are mistaken.
To other people "pointer to array" means that the pointee type
is an array type:

int (*p)[5] = ...;

which reads: p is a pointer to an array of 5 ints.

And those people are correct.
So, there is some
potential for confusion there ...

Which is avoided by understanding the difference between a pointer
to an element of an array and a pointer to an entire array.

Pointers to arrays are actually not as useful as you might expect. Most
array manipulation is done via a pointer to an element of the array --
which means you need to keep track of the length of the array
separately.

[...]
 
K

Keith Thompson

Keith Thompson said:
rectarray is an *array*. An expression of array type, in most contexts,
is implicitly converted to a pointer to the array object's first
element. The exceptions are when it's the operand of sizeof, _Alignof
(new in C99), unary &, and when it's a string literal in an initializer
used to initialize an array object.

Correction: _Alignof is new in C11, not C99.
 
S

Shao Miller

Say I'm using a standard windows RECT structure...

RECT *prect;

As already pointed out, this should be initialized to point to a 'RECT'.
// I can write
prect->left = 0;

Which achieves the same thing as the following lines:

(prect + 0)->left = 0;
(*prect).left = 0;
prect[0].left = 0;
// but I can also write
prect[-1].left = 0;

Which achieves the same thing as the following lines:

(prect - 1)->left = 0;
(*(prect - 1)).left = 0;
prect[0].left = 0;
prect[1].left = 0;

and the compiler won't complain...
So, what did I define in the first line, a pointer to ONE structure or
a pointer to an ARRAY of structures?

You declared a pointer to one 'RECT'. It can point to any 'RECT',
including an element of an array of 'RECT's. 'prect + 1' is also a
pointer to a 'RECT'. Whether or not a pointer actually points to a
'RECT' is a matter of value, but its purpose is a matter of type.
How can I define a pointer to an array?
I don't know in advance how many RECTs there will be in the array.

I'm asking because I can't make WinDbg (nor MSVC debuffer) to show
me the whole array of RECTs.

In the watch window, cast a pointer to the first 'RECT' as a pointer to
an array of 'RECT's.

(RECT (*)[100]) prect
 
A

aleksa

In the watch window, cast a pointer to the first 'RECT' as a pointer to
an array of 'RECT's.
(RECT (*)[100]) prect

I've just tried it, it doesn't work. (using WinDbg 6.12)
After I press enter, the line is NOT entered in the watch window.
 
S

Shao Miller

In the watch window, cast a pointer to the first 'RECT' as a pointer to
an array of 'RECT's.
(RECT (*)[100]) prect

I've just tried it, it doesn't work. (using WinDbg 6.12)
After I press enter, the line is NOT entered in the watch window.

Did you break during the function in which 'prect' was available before
adding the watch? If so, I apologize and will find the WinDbg method.
To be honest, I usually cast the actual address:

(RECT (*)[100]) 0x8042EFBE
 
A

aleksa

Did you break during the function in which 'prect' was available before
adding the watch? If so, I apologize and will find the WinDbg method.
To be honest, I usually cast the actual address:
(RECT (*)[100]) 0x8042EFBE

I've tried direct address, still nothing happens.
Which version are you using?
Or are you using something else?
 
S

Shao Miller

Did you break during the function in which 'prect' was available before
adding the watch? If so, I apologize and will find the WinDbg method.
To be honest, I usually cast the actual address:
(RECT (*)[100]) 0x8042EFBE

I've tried direct address, still nothing happens.
Which version are you using?
Or are you using something else?

It appears that you can make a typedef and a dummy object, which is
quite unfortunate.

typedef RECT RECT_100[100];
RECT_100 * dummy;

Then your watch can have:

(RECT_100 *) prect

Blah.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top