Pointer Question

A

Arun Prasath

Hi all,

I have the following question regd pointer typecasting. Is the
following type of pointer typecasting valid?


#define ALLOC(type,num) ((type *)malloc(sizeof(type)*num))

/*begin code*/

struct node{
:
} node;

typedef node *nodeptr;
node **nodeptrptr;

nodeptrptr = (nodeptr *)ALLOC(node,NUM_OF_NODES)

/*end code*/

Is the above code valid? If so, can anyone explain how it works? How
can a pointer to a memory chunk be typecast to a pointer to a pointer
to a memchunk?

Thanks,
Arun
 
P

Peace

Hi all,

I have the following question regd pointer typecasting. Is the
following type of pointer typecasting valid?


#define ALLOC(type,num) ((type *)malloc(sizeof(type)*num))

/*begin code*/

struct node{
:
} node;

typedef node *nodeptr;
node **nodeptrptr;

nodeptrptr = (nodeptr *)ALLOC(node,NUM_OF_NODES)

/*end code*/

Is the above code valid? If so, can anyone explain how it works? How
can a pointer to a memory chunk be typecast to a pointer to a pointer
to a memchunk?
You can get this code to compile. But it is not going to work. How are
you planning to use this nodeptrptr?

The typecast would convert this pointer into a pointer to a pointer
type, but how would you dereference this? First dereference would give
you the value stored at the location which was allocated using
ALLOC.The second dereference would treat this data as an address and
try to get the value at this address which wouldn't be valid.If your
application is going to ensure that this value is going to be a valid
address, then this would work but looks like a very dangerous way of
doing this.
 
A

Al Bowers

Arun said:
Hi all,

I have the following question regd pointer typecasting. Is the
following type of pointer typecasting valid?

It will not compile as written.
#define ALLOC(type,num) ((type *)malloc(sizeof(type)*num))

/*begin code*/

struct node{
:
} node;

You will need to make a vaiid struct.
typedef node *nodeptr;

typedef struct node nodeptr;
node **nodeptrptr;

struct node **nodeptrptr;
nodeptrptr = (nodeptr *)ALLOC(node,NUM_OF_NODES)

nodeprtptr is type node **. There is a mismatch.
I believe you want something like:

nodeptr p = ALLOC(struct node,NUM_OF_NODES)
/*end code*/

Is the above code valid? If so, can anyone explain how it works? How
can a pointer to a memory chunk be typecast to a pointer to a pointer
to a memchunk?

You want to use a struct pointer to a struct pointer like this?

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define NUM_OF_NODES 3
#define ALLOC(type,num) malloc(sizeof(type)*num)

struct node{
char name[32];
};

typedef struct node *nodeptr;

int main(void)
{
nodeptr p = ALLOC(struct node,NUM_OF_NODES);
struct node **nodeptrptr = ALLOC(*nodeptrptr,NUM_OF_NODES);
unsigned i;

if(!p || !nodeptrptr) exit(EXIT_FAILURE);
for(i = 0;i < NUM_OF_NODES;i++)
{
sprintf(p.name,"%u. Hello",i+1);
nodeptrptr = &p;
printf("p[%u].name = \"%s\"\n",i,p.name);
printf("nodeptrptr[%u]->name = \"%s\"\n\n",i,nodeptrptr->name);
}
free(p);
free(nodeptrptr);
return 0;
}
 
B

Barry Schwarz

Hi all,

I have the following question regd pointer typecasting. Is the
following type of pointer typecasting valid?


#define ALLOC(type,num) ((type *)malloc(sizeof(type)*num))

The cast on malloc's return is unnecessary and ill advised. It can
never help but it can cause the compiler to suppress a diagnostic you
really want to see.
/*begin code*/

struct node{
:
} node;

typedef node *nodeptr;
node **nodeptrptr;

nodeptrptr = (nodeptr *)ALLOC(node,NUM_OF_NODES)

This is an excellent example of why you don't want to do this. You
are allocating enough space for a quantity of structures. However,
The pointer which will receive the address cannot point to a
structure. It must point to a pointer to structure. If the size of
the structure is smaller than the size of a pointer (unlikely but
possible), it will not allocate enough space for all the pointers you
want. More than likely, it will allocate way more space that you
need.

The oft repeated recommendation for malloc is
some_pointer = malloc(quantity * sizeof *some_pointer);
which will always allocate the correct amount of space for the
quantity of objects the pointer points to (or return NULL).
/*end code*/

Is the above code valid? If so, can anyone explain how it works? How
can a pointer to a memory chunk be typecast to a pointer to a pointer
to a memchunk?
If T is a typedef for an object type that occupies some quantity of
memory, then T* is the type for pointer to T and T** is the type for
pointer to pointer to T. You definition of nodeptrptr works fine.


<<Remove the del for email>>
 
P

Peter Shaggy Haywood

Groovy hepcat Arun Prasath was jivin' on 23 Nov 2003 19:59:18 -0800 in
comp.lang.c.
Pointer Question's a cool scene! Dig it!
I have the following question regd pointer typecasting. Is the
following type of pointer typecasting valid?

#define ALLOC(type,num) ((type *)malloc(sizeof(type)*num))

No. Casting the return value of malloc() is never valid. It is
legal, but never useful, and can actually hide a serious bug.
Kindly read the newsgroup for the usual month or two and read the
FAQ before posting again. Had you done so, you would not have needed
to ask.
/*begin code*/

struct node{
:
} node;

This creates an object named node. It does not create a type named
node. It creates a type named struct node, however.
typedef node *nodeptr;

And since there is no type named node, this declaration is invalid.
node **nodeptrptr;

So is this one.
nodeptrptr = (nodeptr *)ALLOC(node,NUM_OF_NODES)

/*end code*/

Is the above code valid? If so, can anyone explain how it works? How

Nope. Noone can explain how it works, because it may not work (and
that's even if you fix the broken declarations). And if it does, then
it does so merely by accident. Calling malloc() without a valid
declaration (provided by including stdlib.h, which you neglected to do
here) causes undefined behaviour.
can a pointer to a memory chunk be typecast to a pointer to a pointer
to a memchunk?

No. Well, semantically it can. But logically it is incorrect and
useless to do so.

--

Dig the even newer still, yet more improved, sig!

http://alphalink.com.au/~phaywood/
"Ain't I'm a dog?" - Ronny Self, Ain't I'm a Dog, written by G. Sherry & W. Walker.
I know it's not "technically correct" English; but since when was rock & roll "technically correct"?
 
E

Eric Sosman

Peter said:
Groovy hepcat Arun Prasath was jivin' on 23 Nov 2003 19:59:18 -0800 in
comp.lang.c.


No. Well, semantically it can. But logically it is incorrect and
useless to do so.

Actually, it seems like a perfectly valid way to handle a
linked list, or any linked data structure. The usual formulation
looks like

struct chunk {
struct chunk *next;
char payload[42];
} *p;
p = malloc(sizeof *p); // assume success
p->next = malloc(sizeof *p->next); // assume success
p->next->next = NULL;

However, the final line could also have been written as

*(struct next**)p = NULL;

.... showing that "a pointer to a memory chunk [can] be typecast
to a pointer to a pointer to a memchunk" and be useful.

Now, why would anyone use the obfuscated rewrite instead
of the crystal-clear original? It would be foolish not to take
advantage of the mnemonic value of the `next' identifier -- but
to do so, the `struct chunk' declaration must be in scope. What
if you're writing a library function that deals in "opaque"
struct types, whose declarations are not available?

For example, my little bag of tricks includes a function to
merge-sort linked lists of structs of arbitrary type. The
function definition begins

void *listsort(void *head, size_t offset,
int (*compare)(const void *, const void *))

.... where `head' points to the first struct of the original list,
`offset' is the byte offset of the forward link in each struct,
and `compare' is the usual comparison function a la qsort().
How does this function navigate the list's links, and how does
it modify them to reflect the result of the sort? By exactly
the kind of casting described above:

void *next = *((struct x**)((char*)head + offset);

Of course, I wrap this up in some macros to save my sanity,
but that's just syntactic sugar. The cast is still there:
`(char*)head + offset' is a "pointer to a memory chunk," this
is then "typecast to a pointer to a pointer to a memchunk"
(of incomplete type, no less), and the result turns out to be
not only useful, but essential.
 
C

CBFalconer

Eric said:
.... snip ...

p->next->next = NULL;

However, the final line could also have been written as

*(struct next**)p = NULL;

... showing that "a pointer to a memory chunk [can] be typecast
to a pointer to a pointer to a memchunk" and be useful.

Now, why would anyone use the obfuscated rewrite instead
of the crystal-clear original? It would be foolish not to take
advantage of the mnemonic value of the `next' identifier -- but
to do so, the `struct chunk' declaration must be in scope. What
if you're writing a library function that deals in "opaque"
struct types, whose declarations are not available?

For example, my little bag of tricks includes a function to
merge-sort linked lists of structs of arbitrary type. The
function definition begins

void *listsort(void *head, size_t offset,
int (*compare)(const void *, const void *))

... where `head' points to the first struct of the original list,
`offset' is the byte offset of the forward link in each struct,
and `compare' is the usual comparison function a la qsort().
How does this function navigate the list's links, and how does
it modify them to reflect the result of the sort? By exactly
the kind of casting described above:

void *next = *((struct x**)((char*)head + offset);

My attitude would be to simply insist that the next field be the
first field in the structure, ensuring offset of 0, and avoiding
many gyrations. Of course the code is not as general as yours,
but does that really matter?

In point of fact I like to build lispish car/cdr structures, with
the cdr pointing to the data. struct node {struct node *next;
void *datum};
 
K

Kevin Bracey

[Posted and mailed]

Groovy hepcat Arun Prasath was jivin' on 23 Nov 2003 19:59:18 -0800 in
comp.lang.c.
Pointer Question's a cool scene! Dig it!


No. Casting the return value of malloc() is never valid. It is
legal, but never useful, and can actually hide a serious bug.

Yawn, reflex rude response without engaging brain. If that macro is defined
in a header file that #includes <stdlib.h>, your serious bug can't occur. And
the cast inside the macro will guarantee type-safety when the macro is used.
I don't see any real problem with it at all in this instance.

The macro produces something functionally equivalent to

thing *make_array_of_things(size_t n)
{
return malloc(n * sizeof(thing));
}

and surely it's better that that returns a thing * than a void *.

We don't know whether or not the OP intended to include <stdlib.h> because
he didn't post a full program. I don't see any reason to leap to flame him.
Except that this is comp.lang.c, and it's force of habit.

I'd recommend putting brackets around the num in the replacement though.
 
P

Peter Shaggy Haywood

Groovy hepcat Kevin Bracey was jivin' on Thu, 27 Nov 2003 12:08:47 GMT
in comp.lang.c.
Re: Pointer Question's a cool scene! Dig it!
[Posted and mailed]

In message <[email protected]>
Groovy hepcat Arun Prasath was jivin' on 23 Nov 2003 19:59:18 -0800 in
comp.lang.c.
Pointer Question's a cool scene! Dig it!


No. Casting the return value of malloc() is never valid. It is
legal, but never useful, and can actually hide a serious bug.

Yawn, reflex rude response without engaging brain. If that macro is defined
in a header file that #includes <stdlib.h>, your serious bug can't occur. And

And where is it indicated that the OP had this in a header that also
included stdlib.h? He asked a fairly general question about a
construct, and I gave him a fairly general answer. Had he indicated
that he was including stdlib.h I wouldn't have mentioned it.
the cast inside the macro will guarantee type-safety when the macro is used.
I don't see any real problem with it at all in this instance.

The macro produces something functionally equivalent to

thing *make_array_of_things(size_t n)
{
return malloc(n * sizeof(thing));
}

and surely it's better that that returns a thing * than a void *.

We don't know whether or not the OP intended to include <stdlib.h> because
he didn't post a full program. I don't see any reason to leap to flame him.

I didn't flame him. Why are you so sensitive? I merely pointed out a
problem with the code. It was intended to help. What's your problem?
Except that this is comp.lang.c, and it's force of habit.

I'd recommend putting brackets around the num in the replacement though.

Me too.

--

Dig the even newer still, yet more improved, sig!

http://alphalink.com.au/~phaywood/
"Ain't I'm a dog?" - Ronny Self, Ain't I'm a Dog, written by G. Sherry & W. Walker.
I know it's not "technically correct" English; but since when was rock & roll "technically correct"?
 
E

Eric Sosman

CBFalconer said:
Eric said:
For example, my little bag of tricks includes a function to
merge-sort linked lists of structs of arbitrary type. [...]
How does this function navigate the list's links [...]?

void *next = *((struct x**)((char*)head + offset);

My attitude would be to simply insist that the next field be the
first field in the structure, ensuring offset of 0, and avoiding
many gyrations. Of course the code is not as general as yours,
but does that really matter?

Design preferences, I guess. Insisting on a zero offset
saves you an addition, and can also eliminate a cast (at the
cost, I guess, of a dummy struct declaration somewhere). On
the other hand, coping with the offset explicitly makes it
easy to manage multilinked structures:

typedef struct node_s {
double coefficient;
int row, col;
struct node_s *nextr, *nextc;
} SparseMatrixNode;

.... and I can sort the `nextr' and `nextc' chains independently.
On the gripping hand, though, I confess it's pretty rare that
I find myself actually using this capability.
 

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
474,303
Messages
2,571,557
Members
48,359
Latest member
Raqib_121635
Top