Sie sind auf Seite 1von 3

sign up

Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free.

log in

tour

help

stack overflow careers

Take the 2-minute tour

Void pointers to struct pointers in C


I am learning C, mainly by K&R, but now I have found an Object Oriented C pdf tutorial and am fascinated. I'm going through it, but my
C skills/knowledge may not be up to the task. This is the tutorial: http://www.planetpdf.com/codecuts/pdfs/ooc.pdf
My question comes from looking at many different functions in the first couple of chapters of the pdf. Below is one of them. (page 14 of
pdf)
void delete(void * self){
const struct Class ** cp = self;
if (self&&*cp&&(*cp)->dtor)
self = (*cp)->dtor(self);
free(self);
}

dtor is a destructor function pointer. But knowledge of this isn't really necessary for my questions.
My first question is, why is **cp constant? Is it necessary or just being thorough so the code writer doesn't do anything damaging
by accident?
Secondly, why is cp a pointer-to-a-pointer (double asterisk?). The struct class was defined on page 12 of the pdf. I don't
understand why it can't be a single pointer, since we are casting the self pointer to a Class pointer, it seems.
Thirdly, how is a void pointer being changed to a Class pointer (or pointer-to-a-Class-pointer)? I think this question most shows my
lack of understanding of C. What I imagine in my head is a void pointer taking up a set amount of memory, but it must be less than
Class pointer, because aClass has a lot of "stuff" in it. I know a void pointer can be "cast" to another type of pointer, but I don't
understand how, since there may not be enough memory to perform this.
Thanks in advance
c

pointers

struct

asked May 3 '12 at 17:54


user485498

@Joe Absolutely nothing wrong with that. Good C programming skills are so valuable and hard to find these
days of rapid scripties. jman May 3 '12 at 17:57
@Joe - I assume it means ANSI C89, which the newer K&R book discussed. the code in the example isn't
K&R C IIRC. Flexo May 3 '12 at 18:00
I am reading K&R ANSI (I think from 1989, as you stated.)The code example comes form the OOC pdf
user485498 May 3 '12 at 18:02

3 Answers

Interesting pdf.
My first question is, why is **cp constant? Is it necessary or just being thorough so the code
writer doesn't do anything damaging by accident?
It's necessary so the writer doesn't do anything by accident, yes, and to communicate
something about the nature of the pointer and its use to the reader of the code.
Secondly, why is cp a pointer-to-a-pointer (double asterisk?). The struct class was defined
on page 12 of the pdf. I don't understand why it can't be a single pointer, since we are
casting the self pointer to a Class pointer, it seems.
Take a look at the definition of new() (pg 13) where the pointer
pointer that's passed as self to delete()):
void * new (const void * _class, ...)

is created (the same

{
const struct Class * class = _class;
void * p = calloc(1, class > size);
* (const struct Class **) p = class;

So, 'p' is allocated space, then dereferenced and assigned a pointer value (the address in
class; this is like dereferencing and assigning to an int pointer, but instead of an int, we're
assigning an address). This means the first thing in p is a pointer to its class definition.
However, p was allocated space for more than just that (it will also hold the object's instance
data). Now consider delete() again:
const struct Class ** cp = self;
if (self&&*cp&&(*cp)->dtor)

When cp is dereferenced, since it was a pointer to a pointer, it's now a pointer. What does a
pointer contain? An address. What address? The pointer to the class definition that's at the
beginning of the block pointed to by p.
This is sort of clever, because p's not really a pointer to a pointer -- it has a larger chunk of
memory allocated which contains the specific object data. However, at the very beginning of
that block is an address (the address of the class definition), so if p is dereferenced into a
pointer (via casting or cp), you have access to that definition. So, the class definition exists
only in one place, but each instance of that class contains a reference to the definition. Make
sense? It would be clearer if p were typed as a struct like this:
struct object {
struct class *class;
[...]
};

Then you could just use something like p->class->dtor() instead of the existing code in
delete(). However, this would mess up and complicate the larger picture.
Thirdly, how is a void pointer being changed to a Class pointer (or pointer-to-a-Classpointer)? I think this question most shows my lack of understanding of C. What I imagine in
my head is a void pointer taking up a set amount of memory, but it must be less than Class
pointer, because aClass has a lot of "stuff" in it.
A pointer is like an int -- it has a small, set size for holding a value. That value is a memory
address. When you dereference a pointer (via * or ->) what you are accessing is the
memory at that address. But since memory addresses are all the same length (eg, 8 bytes on
a 64-bit system) pointers themselves are all the same size regardless of type. This is how the
magic of the object pointer 'p' worked. To re-iterate: the first thing in the block of memory p
points to is an address, which allows it to function as a pointer to a pointer, and when that is
dereferenced, you get the block of memory containing the class definition, which is separate
from the instance data in p.
edited May 3 '12 at 18:52

answered May 3 '12 at 18:33


delicateLatticeworkFever
6,845

10

36

1. In this case, that's just a precaution. The function shouldn't be modifying the class (in fact,
nothing should probably), so casting to const struct Class * makes sure that the class
is more difficult to inadvertently change.
2. I'm not super-familiar with the Object-Oriented C library being used here, but I suspect this
is a nasty trick. The first pointer in self is probably a reference to the class, so
dereferencing self will give a pointer to the class. In effect, self can always be treated
as a struct Class **.
A diagram may help here:
+--------+
self -> | *class | -> [Class]
| .... |
| .... |
+--------+

3. Remember that all pointers are just addresses.* The type of a pointer has no bearing on
the size of the pointer; they're all 32 or 64 bits wide, depending on your system, so you
can convert from one type to another at any time. The compiler will warn you if you try to
convert between types of pointer without a cast, but void * pointers can always be
converted to anything without a cast, as they're used throughout C to indicate a "generic"

pointer.
*: There are some odd platforms where this isn't true, and different types of pointers are in fact
sometimes different sizes. If you're using one of them, though, you'd know about it. In all
probability, you aren't.
answered May 3 '12 at 18:22
duskwuff
86.3k

11

87

128

1.

const is used to cause a compilation error if the code attempts to change anything within
the object pointed to. This is a safety feature when the programmer intends only to read
the object and does not intend to change it.

2.

** is used because that must be what was passed to the function. It would be a grave
programming error to re-declare it as something it is not.

3. A pointer is simply an address. On almost all modern CPUs, all addresses are the same
size (32 bit or 64 bit). Changing a pointer from one type to another doesn't actually change
the value. It says to regard what is at that address as a different layout of data.
answered May 3 '12 at 18:19
wallyk
37.2k

39

85

Das könnte Ihnen auch gefallen