473,513 Members | 2,669 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Deferencing void pointer

I can't believe I've been trying to work this out for hours now, and I
can't believe I couldn't find someone asking for a similar solution in
the newsgroups. No wonder I hate C so much, and every time I get the
textbooks out end up throwing them against the wall in rage. Thats
been going on for 10 years now.

Anyway, I have:

typedef struct _record {
int age;
} record;

typedef struct _LinkedList {
void *data;
struct _LinkedList *next;
} LinkedList;

I can add items to my linked list, traverse the list etc. However I
CANNOT get the data OUT of the list.

curr_ptr = head;
while ( curr_ptr != NULL ) {
printf ("traverse: this=%p data=%d\n",
curr_ptr, curr_ptr->data->age);
}

This results in the error:
warning: deferencing 'void *' pointer
request for member 'age' in something not a structure or union.

I know I have to cast it or something.... but I just can't figure it
out!
Arrgh!

Doug
Nov 13 '05 #1
52 5596
Douglas Garstang wrote:
I can't believe I've been trying to work this out for hours now, and I
can't believe I couldn't find someone asking for a similar solution in
the newsgroups. No wonder I hate C so much, and every time I get the
textbooks out end up throwing them against the wall in rage. Thats
been going on for 10 years now.
<shrug> You sound like you need better textbooks.

Anyway, I have:

typedef struct _record {
int age;
} record;

typedef struct _LinkedList {
void *data;
struct _LinkedList *next;
} LinkedList;
(A side-point: I used to do this too, but then I discovered that names that
begin with leading underscores are reserved for the implementation. So I
started putting the underscores on the end_ instead_, which_ works_ just_
as_ well_ and_ has_ the_ virtue_ of_ correctness_.)

I can add items to my linked list, traverse the list etc. However I
CANNOT get the data OUT of the list.

curr_ptr = head;
while ( curr_ptr != NULL ) {
printf ("traverse: this=%p data=%d\n",
curr_ptr, curr_ptr->data->age);
}

This results in the error:
warning: deferencing 'void *' pointer
request for member 'age' in something not a structure or union.

I know I have to cast it or something.... but I just can't figure it
out!
No, you don't need to cast (except to print the actual pointer value). I
presume that in this case your data pointer points to a structure of type
record. If so, then...

curr_ptr = head;
{
while(curr_ptr != NULL)
{
record *p = curr_ptr->data;
printf ("traverse: this=%p data=%d\n",
(void *)curr_ptr, p->age);

curr_ptr = curr_ptr->next;
}
}
Arrgh!


Feeling better now? :-)

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #2
On Sat, 15 Nov 2003 21:44:00 -0800, Douglas Garstang wrote:
typedef struct _record {
int age;
} record;

typedef struct _LinkedList {
void *data;
struct _LinkedList *next;
} LinkedList;

I can add items to my linked list, traverse the list etc. However I
CANNOT get the data OUT of the list.

curr_ptr = head;
while ( curr_ptr != NULL ) {
printf ("traverse: this=%p data=%d\n",
curr_ptr, curr_ptr->data->age);
}

This results in the error:
warning: deferencing 'void *' pointer
request for member 'age' in something not a structure or union.


Richard gave you a good answer, so I won't write any code for you.
However, I thought I might try to get to the root of your problem.

It seems to me that you are (at least in this case) confusing what
you know about the data structure and what the compiler knows about
the data structure.

Look at your struct LinkedList declaration: You have declared data
as a pointer to void. This tells the compiler that every member
called data of every struct LinkedList is a generic pointer. It
can point to anything at all. *You* know that your code is using
data to point at struct record objects, but the compiler doesn't
know that. All it knows is that data could be pointing at anything
at all.

Therefore, when you try to retrieve a record by dereferencing
curr_ptr->data, the compiler has no choice but to complain. It does
not have the knowledge that, in this situation, curr_ptr->data is
pointing at a struct record. So it says (paraphrased):

"You are asking me to retrieve the value of the member 'age' from
the struct that curr_ptr->data is pointing to, but I can't do that,
because as far as I know, curr_ptr->data isn't pointing to a struct
at all!"

So, in order to access members of the struct record that you know
curr_ptr->data is pointing to, you have to give that information to
the compiler. You have to specify that, in this case, curr_ptr->data
is pointing to a struct record. Richard showed you the cleanest way
to do that, use a temporary variable:

record *p = curr_ptr->data;
printf("data: data=%d\n", p->age);

I recommend you use temporary variables in situations like this as
Richard suggested. I will show you how it would be possible to cast
curr_ptr->data so you can see that it's really just a matter of
telling the compiler what kind of thing curr_ptr->data is pointing
to:

printf("data: data=%d\n", ((record *)curr_ptr->data)->age);

In this case, the cast informs the compiler that curr_ptr-data is
pointing to a record. The compiler is then able to convert
curr_ptr->data into a pointer to record, and then access the age
member of the record being pointed to.

-Sheldon

Nov 13 '05 #3
Richard Heathfield <do******@address.co.uk.invalid> wrote in message news:<bp**********@hercules.btinternet.com>...
Douglas Garstang wrote:
I can't believe I've been trying to work this out for hours now, and I
can't believe I couldn't find someone asking for a similar solution in
the newsgroups. No wonder I hate C so much, and every time I get the
textbooks out end up throwing them against the wall in rage. Thats
been going on for 10 years now.


<shrug> You sound like you need better textbooks.

Anyway, I have:

typedef struct _record {
int age;
} record;

typedef struct _LinkedList {
void *data;
struct _LinkedList *next;
} LinkedList;


(A side-point: I used to do this too, but then I discovered that names that
begin with leading underscores are reserved for the implementation. So I
started putting the underscores on the end_ instead_, which_ works_ just_
as_ well_ and_ has_ the_ virtue_ of_ correctness_.)

I can add items to my linked list, traverse the list etc. However I
CANNOT get the data OUT of the list.

curr_ptr = head;
while ( curr_ptr != NULL ) {
printf ("traverse: this=%p data=%d\n",
curr_ptr, curr_ptr->data->age);
}

This results in the error:
warning: deferencing 'void *' pointer
request for member 'age' in something not a structure or union.

I know I have to cast it or something.... but I just can't figure it
out!


No, you don't need to cast (except to print the actual pointer value). I
presume that in this case your data pointer points to a structure of type
record. If so, then...

curr_ptr = head;
{
while(curr_ptr != NULL)
{
record *p = curr_ptr->data;
printf ("traverse: this=%p data=%d\n",
(void *)curr_ptr, p->age);

curr_ptr = curr_ptr->next;
}
}
Arrgh!


Feeling better now? :-)


Thanks Richard, well I felt better for literally 5 minutes. Now I've
reached my next stumbling block. I'm trying to make the list functions
generic. I did have something like this in my append function:

int list_append ( LinkedList **list, void *data ) {

LinkedList *new_item;

if ( (new_item == (LinkedList *)malloc(sizeof(LinkedList))) ==
NULL ) {
return -1;
}
new_item->data = data
....

(btw, I don't know why the pointer to a pointer (ie **list) lets me
return the list pointer in the function arguments without having to
use a return statement... I just know it works because I've seen
others do it! Arrrgh!)

However, I found that because I was only keeping a pointer to the data
in each node, every time I added a new node with a different value,
all the nodes got updated.

So, I changed my code to:
int list_append ( LinkedList **list, void *data, int data_size ) {

LinkedList *new_item;
void *data_blk;

if ( (new_item == (LinkedList *)malloc(sizeof(LinkedList))) ==
NULL ) {
return -1;
}
if ( (data_blk == (void *)malloc(data_size)) == NULL ) {
return -1;
}
memcpy ( data_blk, data, sizeof(data))
new_item->data = data_blk;
....

Once again, the use of memcpy is not something I just KNEW would work.
I remembered I'd used it a few years ago when I spent hours
researching it. NOTHING in C comes naturally to me...)

This doesn't seem like a perfect solution. The function has no way to
know the size of the data because its working with voids. The only way
I can see to make it work is to pass the size of the data to the
function. Is there a better way?

Btw, I have a HUGE pile of textbooks. They can't all be bad.

Doug.
Nov 13 '05 #4
On Sun, 16 Nov 2003 15:49:24 -0800, Douglas Garstang wrote:
Thanks Richard, well I felt better for literally 5 minutes. Now I've
reached my next stumbling block. I'm trying to make the list functions
generic. I did have something like this in my append function:

int list_append ( LinkedList **list, void *data ) {

LinkedList *new_item;

if ( (new_item == (LinkedList *)malloc(sizeof(LinkedList))) ==
NULL ) {
return -1;
}
new_item->data = data
...

(btw, I don't know why the pointer to a pointer (ie **list) lets me
return the list pointer in the function arguments without having to
use a return statement... I just know it works because I've seen
others do it! Arrrgh!)


Ok, so I'll try to explain it. Assume you already have a linked list with
one or more elements. Assume further that the variable you use to keep
track of your linked list was declared like this:

int main (void)
{
LinkedList * my_list;
...
list_append(&my_list, stuff);
...
}

In memory, this will look like this:

Object of type LinkedList
+---------+ +---------+---------+
my_list:| ---|----->|data :next ---|-----> (next node)
+---------+ +-------|-+---------+
Object of type pointer |
to LinkedList V
+---------+
|some data|
+---------+

The variable my_list has an address in memory. You can access it like
this:

&a

This address is just a way of locating my_list in memory. The address
itself has a type in C. That type is pointer to (whatever it's the
address of). In this case that would be pointer to (pointer to LinkedList)
We can store that address in a variable, as long as the variable also
has type pointer to pointer to LinkedList, like this:

LinkedList ** address_of_my_list = &my_list;

An argument to a function is very much like a variable in the function,
that has already been initialized with a value from outside the function.
So when you define your function list_append:

int list_append ( LinkedList **list, void *data )

You are specifying that it will have an argument of type pointer to
pointer to LinkedList and, just as above, you can initialize that argument
with the address of your my_list variable when you call the function:

list_append(&my_list, some_data);

Now when list_append() is called like this, the layout of the data
structures in memory will be like this:

Object of type pointer to
pointer to LinkedList
+---------+
list:| | (this is the argument to list_append)
+-------|-+
|
|
V Object of type LinkedList
+---------+ +---------+---------+
my_list:| ---|----->|data :next ---|-----> (next node)
+---------+ +-------|-+---------+
Object of type pointer |
to LinkedList V
+---------+
|some data|
+---------+

Notice that this looks almost exactly the same as before. That's because
all that happened is that a pointer to the variable my_list was stored
in the argument named list.

Now list_append() presumably will add the new data to the front of the
list. Probably like this:

1 LinkedList * new_item;
2 new_item = malloc(sizeof *new_item); /* allocate a new LinkedList */
if (new_item != NULL)
{
3 new_item->data = data;
4 new_item->next = *list;
5 *list = new_item;
}

Now lets consider what each numbered line does:

(1) LinkedList * new_item;

This line defines a new object of type pointer to LinkedList called
new_item. The value of this variable is undefined. It doesn't point
to anything in the program yet.

+---------+
new_item:| ---|-----> ?
+---------+

(2) new_item = malloc(sizeof *new_item);

This line allocates a new object big enough to be a LinkedList struct
and stores its address in new_item. (i.e. new_item is set to point at
the new LinkedList node). The members of the LinkedList node (data and
next) have undefined values. They are pointers, but don't point at any
known object yet.

+---------+ +---------+---------+
new_item:| ---|----->|data :next ---|-----> ?
+---------+ +-------|-+---------+
|
V
?
(3) new_item->data = data;

This line makes the data member of the LinkedList node point to the
data that was passed as an argument to list_append():

+---------+ +---------+---------+
new_item:| ---|----->|data :next ---|-----> ?
+---------+ +-------|-+---------+
|
V
+---------+
(the argument called 'data') |new data |
+---------+

(4) new_item->next = *list;

This is where things start to get interesting, and it may be helpful
to break this line down further. From the last big diagram up before
the code, we know that list looks like this in memory:

+---------+
list:| | (this is the argument to list_append)
+-------|-+
|
V
+---------+ +----
my_list:| ---|----->| ...
+---------+ +----

now *list simply means "the thing that list is pointing to". You can
see that list is pointing to the object named my_list, which was
declared OUTSIDE the list_append() function. The line of code we
are considering is (once again):

(4) new_item->next = *list;

So now you should be able to see that this means "copy the value of
the thing list is pointing to into the 'next' member of the LinkedList
node". Since the thing list is pointing to is the variable my_list,
new_item->next will point to whatever my_list is pointing to:

+---------+ +---------+---------+
new_item:| ---|----->|data :next ---|-----+
+---------+ +-------|-+---------+ |
| |
V |
+---------+ |
|new data | |
+---------+ |
|
+---------+ |
list:| | +---------------------+
+-------|-+ |
| |
| |
V V
+---------+ +---------+---------+
my_list:| ---|----->|data :next ---|-----> (next node)
+---------+ +-------|-+---------+
|
V
+---------+
|some data|
+---------+

(5) *list = new_item;

Finally, this line copies the value of new_item into the thing that
list is pointing to. (i.e., it makes my_list point to the same thing
that new_item is pointing to):

+---------+ +---------+---------+
new_item:| ---|----->|data :next ---|-----+
+---------+ +-------|-+---------+ |
^ | |
| V |
| +---------+ |
| |new data | |
| +---------+ |
+-----+ |
+---------+ | |
list:| | | +---------------------+
+-------|-+ | |
| | |
| | |
V | V
+---------+ | +---------+---------+
my_list:| ---|---+ |data :next ---|-----> (next node)
+---------+ +-------|-+---------+
|
V
+---------+
|some data|
+---------+

Now this probably looks like a mess, but you can see that we have
now changed the value of my_list, which was declared in main().
Once the function list_append() is finished and returns, the
value in my_list will still be the updated value. The variable
new_item and the argument list will disappear when list_append()
returns, since they are local to the function list_append(). So
after list_append() returns, the objects in memory will look like
this:

+---------+ +---------+---------+
my_list:| ---|----->|data :next ---|-----+
+---------+ +-------|-+---------+ |
| |
V |
+---------+ |
|new data | |
+---------+ |
|
+---------------------+
|
|
V
+---------+---------+
|data :next ---|-----> (next node)
+-------|-+---------+
|
V
+---------+
|some data|
+---------+
Nov 13 '05 #5
Sheldon Simms <sh**********@yahoo.com> wrote in message news:<pa****************************@yahoo.com>...
On Sun, 16 Nov 2003 15:49:24 -0800, Douglas Garstang wrote:
Thanks Richard, well I felt better for literally 5 minutes. Now I've
reached my next stumbling block. I'm trying to make the list functions
generic. I did have something like this in my append function:

int list_append ( LinkedList **list, void *data ) {

LinkedList *new_item;

if ( (new_item == (LinkedList *)malloc(sizeof(LinkedList))) ==
NULL ) {
return -1;
}
new_item->data = data
...

(btw, I don't know why the pointer to a pointer (ie **list) lets me
return the list pointer in the function arguments without having to
use a return statement... I just know it works because I've seen
others do it! Arrrgh!)


Ok, so I'll try to explain it. Assume you already have a linked list with
one or more elements. Assume further that the variable you use to keep
track of your linked list was declared like this:

int main (void)
{
LinkedList * my_list;
...
list_append(&my_list, stuff);
...
}

In memory, this will look like this:

Object of type LinkedList
+---------+ +---------+---------+
my_list:| ---|----->|data :next ---|-----> (next node)
+---------+ +-------|-+---------+
Object of type pointer |
to LinkedList V
+---------+
|some data|
+---------+

The variable my_list has an address in memory. You can access it like
this:

&a

This address is just a way of locating my_list in memory. The address
itself has a type in C. That type is pointer to (whatever it's the
address of). In this case that would be pointer to (pointer to LinkedList)
We can store that address in a variable, as long as the variable also
has type pointer to pointer to LinkedList, like this:

LinkedList ** address_of_my_list = &my_list;

An argument to a function is very much like a variable in the function,
that has already been initialized with a value from outside the function.
So when you define your function list_append:

int list_append ( LinkedList **list, void *data )

You are specifying that it will have an argument of type pointer to
pointer to LinkedList and, just as above, you can initialize that argument
with the address of your my_list variable when you call the function:

list_append(&my_list, some_data);

Now when list_append() is called like this, the layout of the data
structures in memory will be like this:

Object of type pointer to
pointer to LinkedList
+---------+
list:| | (this is the argument to list_append)
+-------|-+
|
|
V Object of type LinkedList
+---------+ +---------+---------+
my_list:| ---|----->|data :next ---|-----> (next node)
+---------+ +-------|-+---------+
Object of type pointer |
to LinkedList V
+---------+
|some data|
+---------+

Notice that this looks almost exactly the same as before. That's because
all that happened is that a pointer to the variable my_list was stored
in the argument named list.

Now list_append() presumably will add the new data to the front of the
list. Probably like this:

1 LinkedList * new_item;
2 new_item = malloc(sizeof *new_item); /* allocate a new LinkedList */
if (new_item != NULL)
{
3 new_item->data = data;
4 new_item->next = *list;
5 *list = new_item;
}

Now lets consider what each numbered line does:

(1) LinkedList * new_item;

This line defines a new object of type pointer to LinkedList called
new_item. The value of this variable is undefined. It doesn't point
to anything in the program yet.

+---------+
new_item:| ---|-----> ?
+---------+

(2) new_item = malloc(sizeof *new_item);

This line allocates a new object big enough to be a LinkedList struct
and stores its address in new_item. (i.e. new_item is set to point at
the new LinkedList node). The members of the LinkedList node (data and
next) have undefined values. They are pointers, but don't point at any
known object yet.

+---------+ +---------+---------+
new_item:| ---|----->|data :next ---|-----> ?
+---------+ +-------|-+---------+
|
V
?
(3) new_item->data = data;

This line makes the data member of the LinkedList node point to the
data that was passed as an argument to list_append():

+---------+ +---------+---------+
new_item:| ---|----->|data :next ---|-----> ?
+---------+ +-------|-+---------+
|
V
+---------+
(the argument called 'data') |new data |
+---------+

(4) new_item->next = *list;

This is where things start to get interesting, and it may be helpful
to break this line down further. From the last big diagram up before
the code, we know that list looks like this in memory:

+---------+
list:| | (this is the argument to list_append)
+-------|-+
|
V
+---------+ +----
my_list:| ---|----->| ...
+---------+ +----

now *list simply means "the thing that list is pointing to". You can
see that list is pointing to the object named my_list, which was
declared OUTSIDE the list_append() function. The line of code we
are considering is (once again):

(4) new_item->next = *list;

So now you should be able to see that this means "copy the value of
the thing list is pointing to into the 'next' member of the LinkedList
node". Since the thing list is pointing to is the variable my_list,
new_item->next will point to whatever my_list is pointing to:

+---------+ +---------+---------+
new_item:| ---|----->|data :next ---|-----+
+---------+ +-------|-+---------+ |
| |
V |
+---------+ |
|new data | |
+---------+ |
|
+---------+ |
list:| | +---------------------+
+-------|-+ |
| |
| |
V V
+---------+ +---------+---------+
my_list:| ---|----->|data :next ---|-----> (next node)
+---------+ +-------|-+---------+
|
V
+---------+
|some data|
+---------+

(5) *list = new_item;

Finally, this line copies the value of new_item into the thing that
list is pointing to. (i.e., it makes my_list point to the same thing
that new_item is pointing to):

+---------+ +---------+---------+
new_item:| ---|----->|data :next ---|-----+
+---------+ +-------|-+---------+ |
^ | |
| V |
| +---------+ |
| |new data | |
| +---------+ |
+-----+ |
+---------+ | |
list:| | | +---------------------+
+-------|-+ | |
| | |
| | |
V | V
+---------+ | +---------+---------+
my_list:| ---|---+ |data :next ---|-----> (next node)
+---------+ +-------|-+---------+
|
V
+---------+
|some data|
+---------+

Now this probably looks like a mess, but you can see that we have
now changed the value of my_list, which was declared in main().
Once the function list_append() is finished and returns, the
value in my_list will still be the updated value. The variable
new_item and the argument list will disappear when list_append()
returns, since they are local to the function list_append(). So
after list_append() returns, the objects in memory will look like
this:

+---------+ +---------+---------+
my_list:| ---|----->|data :next ---|-----+
+---------+ +-------|-+---------+ |
| |
V |
+---------+ |
|new data | |
+---------+ |
|
+---------------------+
|
|
V
+---------+---------+
|data :next ---|-----> (next node)
+-------|-+---------+
|
V
+---------+
|some data|
+---------+


Sheldon,
Thanks for the really detailed response. Unfortunately after reading
your post several times, I still just don't get it. I can't even
visualise pointers to anything in my head, let alone pointers to
pointers. I've got something pretty good working right now...
simulating perl's (now there's something I can work with) push, pop,
shift and unshift functions... and its only taken 10 years to do it!

I have to wonder if there's any point in trying any more. Even if I
manage to get something working, I still don't understand all the
fundamentals and probably never will. You'd think for a guy who
started programming at the age of 10 with his vic-20, went to Uni, and
scripts on a daily basis, I'd have SOME idea by now.
Nov 13 '05 #6
Douglas Garstang wrote:
Thanks Richard, well I felt better for literally 5 minutes. Now I've
reached my next stumbling block. I'm trying to make the list functions
generic. I did have something like this in my append function:

int list_append ( LinkedList **list, void *data ) {

LinkedList *new_item;
I just use new, rather than new_item (mainly for the apoplexy it causes in
C++ programmers).

if ( (new_item == (LinkedList *)malloc(sizeof(LinkedList))) ==
NULL ) {
Better: if( (new_item == malloc(sizeof *new_item)) == NULL) {

which, as well as being quicker to type, needs less maintenance and is
easier to read.
return -1;
}
new_item->data = data
...

(btw, I don't know why the pointer to a pointer (ie **list) lets me
return the list pointer in the function arguments without having to
use a return statement... I just know it works because I've seen
others do it! Arrrgh!)
"return the list pointer" is really the wrong way to say it. Think of
"return value" as "thing that comes out of the left-hand end of a function"
rather than something the compiler vomits back up to the caller via a
parameter.

Okay, why does it work? Well, C is always pass-by-value, as you know
already. Parameters are /copies/ of the arguments provided, not the
original objects. So changing a parameter's value has no effect in the
caller. BUT consider this. I have a piece of paper here which tells me
where I can find my ATM card and PIN. I give you a copy of the piece of
paper. Now, if you want, you can write all over that piece of paper. Will
it affect my original piece? No, of course not. Will it affect my bank
account in any way? No, of course not. BUT if you take that copy and use it
to track down my ATM and PIN, you can use them to do all sorts of mischief.

The piece of paper is a pointer. Changing its value is equivalent to
scribbling on the paper. A waste of time. But /using/ its value to locate
another object in memory? That's very different, because an accurate /copy/
of an accurate /description/ of a location is just as good as the
/original/ description of the location.

People get mildly confused when what they need to change is a pointer. But
nothing is different here. If you want a function to change the value of a
foo, you must pass in the address of that foo. Just because foo might
already be a pointer type, doesn't mean that anything's changed. If you
want to update a pointer, you must pass that pointer's address (i.e. a
pointer to the pointer!) to the function, just like you'd have to pass
anything else's address.
However, I found that because I was only keeping a pointer to the data
in each node, every time I added a new node with a different value,
all the nodes got updated.
Right.
So, I changed my code to:
int list_append ( LinkedList **list, void *data, int data_size ) {
Better: size_t data_size (or just size_t size)

LinkedList *new_item;
void *data_blk;

if ( (new_item == (LinkedList *)malloc(sizeof(LinkedList))) ==
NULL ) {
if( (new_item == malloc(sizeof *new_item)) == NULL) {
return -1;
}
if ( (data_blk == (void *)malloc(data_size)) == NULL ) {
Casting malloc is already silly, but casting from void * to void * to assign
to a void * pointer is actually quite funny. :-)

if((data_blk = malloc(data_size)) == NULL) {
return -1;
}
memcpy ( data_blk, data, sizeof(data))
new_item->data = data_blk;
...

Once again, the use of memcpy is not something I just KNEW would work.
Well, now you know.
I remembered I'd used it a few years ago when I spent hours
researching it. NOTHING in C comes naturally to me...)
It will, it will.
This doesn't seem like a perfect solution. The function has no way to
know the size of the data because its working with voids. The only way
I can see to make it work is to pass the size of the data to the
function. Is there a better way?
Well, not if you want to keep the generic nature of the code.

You might benefit from taking a look at the linked list code at
http://users.powernet.co.uk/eton/unl.../ch11/ch11.zip - if only to
reassure you that you are basically on the right track.

Btw, I have a HUGE pile of textbooks. They can't all be bad.


Yeesh. You'd be amazed. (No, you're probably right. There's probably at
least one good C book in the pile. Maybe.)

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #7
Douglas Garstang wrote:

<snip>
Sheldon,
Thanks for the really detailed response.
We'd already read it. Please only include /necessary/ text when responding,
for the sake of those of us who have modems rather than cable or satellite
connections. Thanks.
Unfortunately after reading
your post several times, I still just don't get it. I can't even
visualise pointers to anything in my head, let alone pointers to
pointers.


Okay. That's fixable. And you're gonna love this...

If you want to understand pointers, write a computer. Or rather, write an
emulator for the non-existent computer of your choice.

Start off simple. A 1-bit computer with 2 1-bit "bytes" of memory, a 1-bit
instruction register (it holds the address in memory of the next
instruction to be executed), and one 1-bit register. Decide on an
instruction set for it (it'll have just two different instructions), and
then write it. /Then/ write programs for it. (These are easy: 00, 01, 10,
11. All done.)

This can be done in around 300 lines of C code. Less if you're a terse
coder, but mine is 300 lines (excluding a few printfs and comments), and it
even includes a rudimentary disassembler.

Then write a 2-bit computer. That'll have four 2-bit "bytes" of memory, a
2-bit instruction register, and perhaps you can be daring and give it two
2-bit registers. The instruction set can have a massive FOUR instructions.

My version takes about 350 lines. And the 3-bit version is about 400 lines.
It's not difficult, believe me. And by the time you get up to 8 bits, you
/will/ understand pointers.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #8
On 2003-11-17, Douglas Garstang <do**@pobox.com> wrote:

... Unfortunately after reading your post several times, I still just
don't get it. I can't even visualise pointers to anything in my head,
let alone pointers to pointers.


A pointer is simply an indirect reference to an entity (in C parlance,
and object).

Here is an analogy. C objects are voice mailboxes. These objects are
named according to the people to whom the mailboxes belong. A pointer
to a C object would correspond to the phone number you would dial to
access the voice mailbox of the person you wanted leave a message for.

Dialing a number is analagous to dereferencing a pointer. Leaving
a message in a voice mailbox is analagous to assigning a value to a
dereferenced pointer. Listening to a voice mailbox message is analagous
to reading the value of a deferenced pointer.

A pointer to a pointer is analgous to a phone number to a voice mailbox
which can only hold a message that is another phone number.

-- James
Nov 13 '05 #9
James Hu <jx*@despammed.com> wrote:
On 2003-11-17, Douglas Garstang <do**@pobox.com> wrote:

... Unfortunately after reading your post several times, I still just
don't get it. I can't even visualise pointers to anything in my head,
let alone pointers to pointers.


A pointer is simply an indirect reference to an entity (in C parlance,
and object).

Here is an analogy. C objects are voice mailboxes. These objects are
named according to the people to whom the mailboxes belong. A pointer
to a C object would correspond to the phone number you would dial to
access the voice mailbox of the person you wanted leave a message for.

Dialing a number is analagous to dereferencing a pointer. Leaving
a message in a voice mailbox is analagous to assigning a value to a
dereferenced pointer. Listening to a voice mailbox message is analagous
to reading the value of a deferenced pointer.

A pointer to a pointer is analgous to a phone number to a voice mailbox
which can only hold a message that is another phone number.


Ahem... a _pointer_ _to_ _a_ _pointer_ is the phone number of directory
assistance. (Which needs care in accessing, because as soon as
you give it the address to dereference, it is possible that the
results are a trap represention, which comes not from the pleasant
sounding human voice of the operator you were talking to, but from
a mechanized voice in a machine located in some remote corner of
the collective network memory of the telephone network.)

A _pointer_ _to_ _a_ _pointer_ _to_ _a_ _pointer_ is the number of that guy
down the block, who works for the phone company and knows the
right number to call to ask where to call to get a number to
call to get whatever number it is that you want.

A _pointer_ _to_ _a_ _pointer_ _to_ _a_ _pointer_ _to_ _a_ _pointer_ may have a
different size though, because that is the little black book the
guy down the block has been keeping in his pocket for the past
20-30 years, where he looks up all these numbers to get numbers
to get numbers to get a number.

I mean, how could anybody be confused??? ;-)

--
Floyd L. Davidson <http://web.newsguy.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska) fl***@barrow.com
Nov 13 '05 #10
Richard Heathfield wrote:
.... snip ...
Better: if( (new_item == malloc(sizeof *new_item)) == NULL) {

which, as well as being quicker to type, needs less maintenance and is
easier to read.


Harumph. Are you sure? :-)

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 13 '05 #11
On 2003-11-17, Floyd Davidson <fl***@barrow.com> wrote:
James Hu <jx*@despammed.com> wrote:
On 2003-11-17, Douglas Garstang <do**@pobox.com> wrote:

... Unfortunately after reading your post several times, I still just
don't get it. I can't even visualise pointers to anything in my head,
let alone pointers to pointers.


...
A pointer to a pointer is analagous to a phone number to a voice
mailbox which can only hold a message that is another phone number.


Ahem... a _pointer_ _to_ _a_ _pointer_ is the phone number of directory
assistance.
...


No, that is a pointer to an oracle, for which there is no C analog, so
it is off-topic in comp.lang.c. Please try rec.humor.oracle.

-- James
Nov 13 '05 #12
CBFalconer wrote:
Richard Heathfield wrote:

... snip ...

Better: if( (new_item == malloc(sizeof *new_item)) == NULL) {

which, as well as being quicker to type, needs less maintenance and is
easier to read.


Harumph. Are you sure? :-)


Modulo the first == (which should be = instead), yes, I'm sure. (Oops.)

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #13
In <bp**********@hercules.btinternet.com> Richard Heathfield <do******@address.co.uk.invalid> writes:
CBFalconer wrote:
Richard Heathfield wrote:

... snip ...

Better: if( (new_item == malloc(sizeof *new_item)) == NULL) {

which, as well as being quicker to type, needs less maintenance and is
easier to read.


Harumph. Are you sure? :-)


Modulo the first == (which should be = instead), yes, I'm sure. (Oops.)


See, it's much better to always triple check than to rely on silly gadgets
that work only when you're lucky!

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #14
Richard Heathfield <do******@address.co.uk.invalid> spoke thus:
I just use new, rather than new_item (mainly for the apoplexy it causes in
C++ programmers).


Well, whatever flaws may result from doing so are well worth causing
apoplexy in C++ programmers, eh? ;)

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Nov 13 '05 #15
Dan Pop wrote:
In <bp**********@hercules.btinternet.com> Richard Heathfield
<do******@address.co.uk.invalid> writes:
Modulo the first == (which should be = instead), yes, I'm sure. (Oops.)


See, it's much better to always triple check than to rely on silly gadgets
that work only when you're lucky!


I don't /rely/ on what you call silly gadgets. I use the const==var order as
an additional check, because I know I make mistakes of this kind, no matter
how carefully I check. I know you do, too, because you have done so in an
article posted to this group, so please don't get all high and mighty on
me.

In any event, const==var can never catch a mistakenly typed == where = was
meant; its purpose is to catch (where possible) the /opposite/ mistake.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #16
Christopher Benson-Manica wrote:
Richard Heathfield <do******@address.co.uk.invalid> spoke thus:
I just use new, rather than new_item (mainly for the apoplexy it causes
in C++ programmers).


Well, whatever flaws may result from doing so are well worth causing
apoplexy in C++ programmers, eh? ;)


Er, flaws? I haven't spotted any yet. Do feel free to share them. :-)

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #17
Richard Heathfield <do******@address.co.uk.invalid> wrote in message news:<bp**********@titan.btinternet.com>...
Douglas Garstang wrote:
Thanks Richard, well I felt better for literally 5 minutes. Now I've
reached my next stumbling block. I'm trying to make the list functions
generic. I did have something like this in my append function:

int list_append ( LinkedList **list, void *data ) {

LinkedList *new_item;


I just use new, rather than new_item (mainly for the apoplexy it causes in
C++ programmers).


Bzzzt. Not around here you don't! and I'm not even a C++ programmer.
It's generally necessary to port C code to C++.

karl m
Nov 13 '05 #18
On Tue, 18 Nov 2003 16:35:22 -0800, karl malbrain wrote:
Richard Heathfield <do******@address.co.uk.invalid> wrote in message news:<bp**********@titan.btinternet.com>...
Douglas Garstang wrote:
> Thanks Richard, well I felt better for literally 5 minutes. Now I've
> reached my next stumbling block. I'm trying to make the list functions
> generic. I did have something like this in my append function:
>
> int list_append ( LinkedList **list, void *data ) {
>
> LinkedList *new_item;


I just use new, rather than new_item (mainly for the apoplexy it causes in
C++ programmers).


Bzzzt. Not around here you don't! and I'm not even a C++ programmer.
It's generally necessary to port C code to C++.


Why? Did the C compiler stop working?

Nov 13 '05 #19
karl malbrain wrote:
Richard Heathfield <do******@address.co.uk.invalid> wrote in message
news:<bp**********@titan.btinternet.com>...
Douglas Garstang wrote:
>
> LinkedList *new_item;
I just use new, rather than new_item (mainly for the apoplexy it causes
in C++ programmers).


Bzzzt. Not around here you don't!


I see no reason why not.
and I'm not even a C++ programmer.
Irrelevant.
It's generally necessary to port C code to C++.


That has not been my experience. If it ain't broke, don't fix it.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #20
In <bp**********@titan.btinternet.com> Richard Heathfield <do******@address.co.uk.invalid> writes:
Dan Pop wrote:
In <bp**********@hercules.btinternet.com> Richard Heathfield
<do******@address.co.uk.invalid> writes:
Modulo the first == (which should be = instead), yes, I'm sure. (Oops.)
See, it's much better to always triple check than to rely on silly gadgets
that work only when you're lucky!


I don't /rely/ on what you call silly gadgets. I use the const==var order as
an additional check, because I know I make mistakes of this kind, no matter
how carefully I check. I know you do, too, because you have done so in an
article posted to this group, so please don't get all high and mighty on
me.


I did it in a context where it was a syntax error, so there was no risk
of silently getting the wrong result. Big difference. When I know that
the compiler can't help, I do the triple checking. When merely providing
an initialiser, I'm less careful.
In any event, const==var can never catch a mistakenly typed == where = was
meant; its purpose is to catch (where possible) the /opposite/ mistake.


While the purpose of triple checking is to catch *any* mistake related to
the (mis)usage of the assignment/equality operators. Thus rendering the
silly const==var trick futile.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #21
In <7f*************************@posting.google.com> ka****@acm.org (karl malbrain) writes:
It's generally necessary to port C code to C++.


It NEVER happened to me... C++ has an official interface for
interoperating with C code, which completely removes the need to port C
code to C++.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #22
Dan Pop wrote:
In <bp**********@titan.btinternet.com> Richard Heathfield
.... snip ...
In any event, const==var can never catch a mistakenly typed ==
where = was meant; its purpose is to catch (where possible)
the /opposite/ mistake.


While the purpose of triple checking is to catch *any* mistake
related to the (mis)usage of the assignment/equality operators.
Thus rendering the silly const==var trick futile.


Most of us mere mortals have, in the past, contrived to re-read
our own code many more than three times, without catching such
errors. There appears to be a fault in our infallibility
mechanism. Thus we find a net gain in using the zero effort
"trick" up front.

My favorite foolish foulup is to add an extraneous semi to a macro
definition. At least that one tends to trigger misleading
compiler complaints rather than silent acceptance.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 13 '05 #23
In <3F**************@yahoo.com> CBFalconer <cb********@yahoo.com> writes:
Dan Pop wrote:
In <bp**********@titan.btinternet.com> Richard Heathfield
... snip ...
> In any event, const==var can never catch a mistakenly typed ==
> where = was meant; its purpose is to catch (where possible)
> the /opposite/ mistake.


While the purpose of triple checking is to catch *any* mistake
related to the (mis)usage of the assignment/equality operators.
Thus rendering the silly const==var trick futile.


Most of us mere mortals have, in the past, contrived to re-read
our own code many more than three times, without catching such
errors. There appears to be a fault in our infallibility
mechanism.


If you triple check at the time you write it, it is practically impossible
to end up with the wrong operator: "hey, I wrote ==, is it really what I
want?".
Thus we find a net gain in using the zero effort "trick" up front.
Your fondness of zero effort "tricks" probably explains the high rate of
bugs in the code you post... It takes real effort to write correct C
code!
My favorite foolish foulup is to add an extraneous semi to a macro
definition.


Another place where I triple check, because I don't even want to consider
the consequences of a mistake.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #24
Dan Pop wrote:
In <bp**********@titan.btinternet.com> Richard Heathfield
<do******@address.co.uk.invalid> writes:
I don't /rely/ on what you call silly gadgets. I use the const==var order
as an additional check, because I know I make mistakes of this kind, no
matter how carefully I check. I know you do, too, because you have done so
in an article posted to this group, so please don't get all high and
mighty on me.
I did it in a context where it was a syntax error, so there was no risk
of silently getting the wrong result. Big difference.


No, no real difference. It just shows that we're all fallible - even you.
You have your ways of avoiding errors, and I have mine. Yours don't always
work, and neither do mine. We all make out the best we can.
When I know that
the compiler can't help, I do the triple checking. When merely providing
an initialiser, I'm less careful.


I try to be careful /all/ the time. I don't always succeed. I use all the
useful techniques I know of to assist me in reducing the number of errors
in my code, of which the const==var technique is just one. That you do not
happen to value it does not make it valueless to /me/.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #25
Da*****@cern.ch (Dan Pop) wrote in message news:<bp**********@sunnews.cern.ch>...
In <7f*************************@posting.google.com> ka****@acm.org (karl malbrain) writes:
It's generally necessary to port C code to C++.


It NEVER happened to me... C++ has an official interface for
interoperating with C code, which completely removes the need to port C
code to C++.


Nonsense. Lot's of porting falls completely outside any "official
interface." karl m
Nov 13 '05 #26
In <bp**********@titan.btinternet.com> Richard Heathfield <do******@address.co.uk.invalid> writes:
Dan Pop wrote:
In <bp**********@titan.btinternet.com> Richard Heathfield
<do******@address.co.uk.invalid> writes:
I don't /rely/ on what you call silly gadgets. I use the const==var order
as an additional check, because I know I make mistakes of this kind, no
matter how carefully I check. I know you do, too, because you have done so
in an article posted to this group, so please don't get all high and
mighty on me.
I did it in a context where it was a syntax error, so there was no risk
of silently getting the wrong result. Big difference.


No, no real difference.


Even a blind can see the difference between a mistake that requires a
diagnostic one that doesn't.
It just shows that we're all fallible - even you.
Of course I'm fallible and I have provided ample proof of that, over the
years. It's just that I am perfectly able to avoid certain insidious bugs
by paying extra attention at the points where I have a chance to actually
generate them, without resorting to any silly tricks.
I try to be careful /all/ the time. I don't always succeed. I use all the
useful techniques I know of to assist me in reducing the number of errors
in my code, of which the const==var technique is just one. That you do not
happen to value it does not make it valueless to /me/.


Which goes on to show that there is something wrong with your programming
methodology. However, if you're happy with it, keep doing things your
way... Just don't encourage other people to follow your example.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #27
In <7f*************************@posting.google.com> ka****@acm.org (karl malbrain) writes:
Da*****@cern.ch (Dan Pop) wrote in message news:<bp**********@sunnews.cern.ch>...
In <7f*************************@posting.google.com> ka****@acm.org (karl malbrain) writes:
>It's generally necessary to port C code to C++.


It NEVER happened to me... C++ has an official interface for
interoperating with C code, which completely removes the need to port C
code to C++.


Nonsense. Lot's of porting falls completely outside any "official
interface." karl m


???

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #28
Dan Pop <Da*****@cern.ch> wrote:
In <7f*************************@posting.google.com> ka****@acm.org (karl malbrain) writes:
Da*****@cern.ch (Dan Pop) wrote in message news:<bp**********@sunnews.cern.ch>...
In <7f*************************@posting.google.com> ka****@acm.org (karl malbrain) writes:

>It's generally necessary to port C code to C++.

It NEVER happened to me... C++ has an official interface for
interoperating with C code, which completely removes the need to port C
code to C++.


Nonsense. Lot's of porting falls completely outside any "official
interface." karl m

???


Methinks that he thinks that "official interface" implies
"standard library" :-)

Alex
Nov 13 '05 #29
Dan Pop wrote:
In <bp**********@titan.btinternet.com> Richard Heathfield
<do******@address.co.uk.invalid> writes:
Dan Pop wrote:
In <bp**********@titan.btinternet.com> Richard Heathfield
<do******@address.co.uk.invalid> writes:

I don't /rely/ on what you call silly gadgets. I use the const==var
order as an additional check, because I know I make mistakes of this
kind, no matter how carefully I check. I know you do, too, because you
have done so in an article posted to this group, so please don't get all
high and mighty on me.

I did it in a context where it was a syntax error, so there was no risk
of silently getting the wrong result. Big difference.
No, no real difference.


Even a blind can see the difference between a mistake that requires a
diagnostic one that doesn't.


Oh, of course I can. That's why I use the const == var construct.
It just shows that we're all fallible - even you.


Of course I'm fallible and I have provided ample proof of that, over the
years. It's just that I am perfectly able to avoid certain insidious bugs
by paying extra attention at the points where I have a chance to actually
generate them, without resorting to any silly tricks.


And I am perfectly able to avoid certain insidious bugs by using a technique
that requires a diagnostic if I type = instead of ==, instead of being
silly enough to rely solely on my remembering to triple-check each time.
One man's silly is another man's sensible. To use words like "silly" in
this context is silly. (There ya go - two sig block quotes for the price of
one.) (Or is that three?)
I try to be careful /all/ the time. I don't always succeed. I use all the
useful techniques I know of to assist me in reducing the number of errors
in my code, of which the const==var technique is just one. That you do not
happen to value it does not make it valueless to /me/.


Which goes on to show that there is something wrong with your programming
methodology.


I disagree.
However, if you're happy with it, keep doing things your
way...
I plan to do just that.
Just don't encourage other people to follow your example.


Oh, but I /do/. You see, it's a sensible technique for fallible people. That
you disagree does not affect my opinion in the slightest, despite the high
regard I have for your knowledge of the C language.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #30
Da*****@cern.ch (Dan Pop) wrote in message news:<bp**********@sunnews.cern.ch>...
In <7f*************************@posting.google.com> ka****@acm.org (karl malbrain) writes:
Da*****@cern.ch (Dan Pop) wrote in message news:<bp**********@sunnews.cern.ch>...
In <7f*************************@posting.google.com> ka****@acm.org (karl malbrain) writes:

>It's generally necessary to port C code to C++.

It NEVER happened to me... C++ has an official interface for
interoperating with C code, which completely removes the need to port C
code to C++.
Nonsense. Lot's of porting falls completely outside any "official
interface." karl m


???


Porting code fragments from one function to another, and from C to C++
falls outside the C++ "official interface" for interacting with C.
karl m
Dan

Nov 13 '05 #31
In <bp**********@sparta.btinternet.com> Richard Heathfield <do******@address.co.uk.invalid> writes:
Dan Pop wrote:
Just don't encourage other people to follow your example.


Oh, but I /do/. You see, it's a sensible technique for fallible people.


Nope, it isn't. All people are fallible, and the only technique that
catches any = vs == error that a compiler cannot or doesn't have to catch
is engaging your brain. If you don't engage the brain, the technique
doesn't buy you anything (it just make your code look silly, from a
logical point of view), if you do, you don't need it in the first place.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #32
In <7f**************************@posting.google.com > ka****@acm.org (karl malbrain) writes:
Da*****@cern.ch (Dan Pop) wrote in message news:<bp**********@sunnews.cern.ch>...
In <7f*************************@posting.google.com> ka****@acm.org (karl malbrain) writes:
>Da*****@cern.ch (Dan Pop) wrote in message news:<bp**********@sunnews.cern.ch>...
>> In <7f*************************@posting.google.com> ka****@acm.org (karl malbrain) writes:
>>
>> >It's generally necessary to port C code to C++.
>>
>> It NEVER happened to me... C++ has an official interface for
>> interoperating with C code, which completely removes the need to port C
>> code to C++.
>
>Nonsense. Lot's of porting falls completely outside any "official
>interface." karl m


???


Porting code fragments from one function to another, and from C to C++
falls outside the C++ "official interface" for interacting with C.


No problem, that's why it's called *porting* code fragments and not
*reusing* code fragments.

It's no different from porting code fragments from C to *any* other
programming language. There is *nothing* special about C++.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #33
On Fri, 21 Nov 2003 10:46:35 +0000, Dan Pop wrote:
In <bp**********@sparta.btinternet.com> Richard Heathfield <do******@address.co.uk.invalid> writes:
Dan Pop wrote:
Just don't encourage other people to follow your example.


Oh, but I /do/. You see, it's a sensible technique for fallible people.


Nope, it isn't. All people are fallible, and the only technique that
catches any = vs == error that a compiler cannot or doesn't have to catch
is engaging your brain. If you don't engage the brain, the technique
doesn't buy you anything (it just make your code look silly, from a
logical point of view), if you do, you don't need it in the first place.


Logical?
How is (0 == X) any less logical than (X == 0)?
Nov 13 '05 #34
Sheldon Simms <sh**********@yahoo.com> wrote:
On Fri, 21 Nov 2003 10:46:35 +0000, Dan Pop wrote:
In <bp**********@sparta.btinternet.com> Richard Heathfield <do******@address.co.uk.invalid> writes:
Dan Pop wrote:

Just don't encourage other people to follow your example.

Oh, but I /do/. You see, it's a sensible technique for fallible people.


Nope, it isn't. All people are fallible, and the only technique that
catches any = vs == error that a compiler cannot or doesn't have to catch
is engaging your brain. If you don't engage the brain, the technique
doesn't buy you anything (it just make your code look silly, from a
logical point of view), if you do, you don't need it in the first place.

Logical?
How is (0 == X) any less logical than (X == 0)?


How many times have you said aloud "if 0 is equal to X then ..."?

Alex
Nov 13 '05 #35
In <pa***************************@yahoo.com> Sheldon Simms <sh**********@yahoo.com> writes:
On Fri, 21 Nov 2003 10:46:35 +0000, Dan Pop wrote:
In <bp**********@sparta.btinternet.com> Richard Heathfield <do******@address.co.uk.invalid> writes:
Dan Pop wrote:

Just don't encourage other people to follow your example.

Oh, but I /do/. You see, it's a sensible technique for fallible people.


Nope, it isn't. All people are fallible, and the only technique that
catches any = vs == error that a compiler cannot or doesn't have to catch
is engaging your brain. If you don't engage the brain, the technique
doesn't buy you anything (it just make your code look silly, from a
logical point of view), if you do, you don't need it in the first place.


Logical?
How is (0 == X) any less logical than (X == 0)?


I was not talking about formal logic, merely about code that reflects the
programmer's intention (aka readable code).

You want to test whether X is equal to zero, not whether zero is equal to
X. X == 0 *directly* reflects this intention, while 0 == X doesn't.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #36
Dan Pop wrote:
Sheldon Simms <sh**********@yahoo.com> writes:

.... snip ...

Logical?
How is (0 == X) any less logical than (X == 0)?


I was not talking about formal logic, merely about code that
reflects the programmer's intention (aka readable code).

You want to test whether X is equal to zero, not whether zero
is equal to X. X == 0 *directly* reflects this intention, while
0 == X doesn't.


No, I want to test whether the entity represented by 0 is
interchangeable with the entity represented by X in terms of some
pre-specified set of attributes. Some consider this symettry,
others consider it special relativity, while others consider it
pouring oil upon the flames. :-)

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 13 '05 #37
Alex wrote:
Sheldon Simms <sh**********@yahoo.com> wrote:
.... snip ...
Logical?
How is (0 == X) any less logical than (X == 0)?


How many times have you said aloud "if 0 is equal to X then ..."?


In languages other than C, how many times have you said:

if (0 <= x <= 3) then ....

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 13 '05 #38
CBFalconer <cb********@yahoo.com> wrote:
Alex wrote:
Sheldon Simms <sh**********@yahoo.com> wrote:
... snip ...
> Logical?
> How is (0 == X) any less logical than (X == 0)?


How many times have you said aloud "if 0 is equal to X then ..."?

In languages other than C, how many times have you said: if (0 <= x <= 3) then ....


This is an entirely different issue. Your example is traditional
mathematical notation. If this was a feature of C, I /would/ use
it.

A more relevant subsection of your example would be

if (0 <= x)

which, to me, is unreadable.

Alex
Nov 13 '05 #39
Dan Pop wrote:
In <bp**********@sparta.btinternet.com> Richard Heathfield
<do******@address.co.uk.invalid> writes:
Dan Pop wrote:
Just don't encourage other people to follow your example.
Oh, but I /do/. You see, it's a sensible technique for fallible people.


Nope, it isn't. All people are fallible, and the only technique that
catches any = vs == error that a compiler cannot or doesn't have to catch
is engaging your brain.


Why restrict yourself to techniques that a compiler cannot or doesn't have
to catch? It seems a very silly restriction.
If you don't engage the brain, the technique
doesn't buy you anything (it just make your code look silly, from a
logical point of view),
Logically, a==b and b==a are equivalent. (Duh.)
if you do, you don't need it in the first place.


You seem to see brain engagement as a Boolean phenomenon. I don't believe
it's as simple as that; people /do/ make mistakes even when their brains
/are/ engaged.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #40
On 21 Nov 2003 20:20:29 GMT, in comp.lang.c , Alex
<al*******@hotmail.com> wrote:
CBFalconer <cb********@yahoo.com> wrote:
Alex wrote:
Sheldon Simms <sh**********@yahoo.com> wrote:

> How is (0 == X) any less logical than (X == 0)?

How many times have you said aloud "if 0 is equal to X then ..."?
In languages other than C, how many times have you said:
if (0 <= x <= 3) then ....


This is an entirely different issue.


Not really, You attempted to show that English usage should govern how
C is written. Chuck showed why thats a false idea.
Your example is traditional mathematical notation.
so is if (x ==0) . Your point seems null.
If this was a feature of C, I /would/ use
t'would be nice wouldn't it?
A more relevant subsection of your example would be

if (0 <= x)

which, to me, is unreadable.
Its not uncommon to see this sort of expression in maths.


Alex


--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>
Nov 13 '05 #41
Mark McIntyre <ma**********@spamcop.net> wrote:
On 21 Nov 2003 20:20:29 GMT, in comp.lang.c , Alex
<al*******@hotmail.com> wrote:
CBFalconer <cb********@yahoo.com> wrote:
Alex wrote:
Sheldon Simms <sh**********@yahoo.com> wrote:

> How is (0 == X) any less logical than (X == 0)?

How many times have you said aloud "if 0 is equal to X then ..."?

In languages other than C, how many times have you said:
if (0 <= x <= 3) then ....


This is an entirely different issue. Not really, You attempted to show that English usage should govern how
C is written. Chuck showed why thats a false idea.
To /me/, (x==0) is more natural than (0==x), while being
just as efficient of a construct. In the case of a range
expression, there is no efficient and natural way to
express:

if(x is between 0 and 3, inclusive)

This is the idea behind the simplification of such
expressions in C

if(x >= 0 && x <= 3)

....however, the simplification and repetition of the
variable, does not appeal to /me/.

This is a style issue and is, as such, moot. I was not
attempting to generalize my preference to other constructs,
other than the one presented. It is my preference to use
natural language constructs when they are as convenient to
use as their evil twins. /I/ find that this contributes
to readability.

Your example is traditional mathematical notation. so is if (x ==0) . Your point seems null.
Erm, unless you meant (0==x), this is in fact what I
was arguing.
A more relevant subsection of your example would be

if (0 <= x)

which, to me, is unreadable.

Its not uncommon to see this sort of expression in maths.


My math vocabulary is somewhat limited. However, I am
yet to see an expression of this sort, with a good reason.

Alex
Nov 13 '05 #42
In <bp**********@sparta.btinternet.com> Richard Heathfield <do******@address.co.uk.invalid> writes:
Dan Pop wrote:
In <bp**********@sparta.btinternet.com> Richard Heathfield
<do******@address.co.uk.invalid> writes:
Dan Pop wrote:

Just don't encourage other people to follow your example.

Oh, but I /do/. You see, it's a sensible technique for fallible people.


Nope, it isn't. All people are fallible, and the only technique that
catches any = vs == error that a compiler cannot or doesn't have to catch
is engaging your brain.


Why restrict yourself to techniques that a compiler cannot or doesn't have
to catch? It seems a very silly restriction.


It's a *very* practical one, too. You (subconciously, in my case)
concentrate your mental resources on the things the compiler cannot help
with.
If you don't engage the brain, the technique
doesn't buy you anything (it just make your code look silly, from a
logical point of view),


Logically, a==b and b==a are equivalent. (Duh.)


When was the last time you said "compare 0 to x" in plain English?
As a C beginner, how many times have you written "0 == x"?
if you do, you don't need it in the first place.


You seem to see brain engagement as a Boolean phenomenon. I don't believe
it's as simple as that; people /do/ make mistakes even when their brains
/are/ engaged.


Entirely agreed. It's just that *certain* classes of mistakes can be
trivially avoided if the brain is fully engaged and I claim that the =
vs == mistakes are one such class.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #43
Dan Pop wrote:
If you don't engage the brain, the technique
doesn't buy you anything (it just make your code look silly, from a
logical point of view),
Logically, a==b and b==a are equivalent. (Duh.)


When was the last time you said "compare 0 to x" in plain English?


Never. But we're not discussing English here. We're discussing C. When I see
either 0==x or x==0, I don't think of it as "compare 0 to x" or "compare x
to 0" but rather, "compare these two quantities for equality". It makes no
difference whatsoever which way around you put them.
As a C beginner, how many times have you written "0 == x"?
Many times.
if you do, you don't need it in the first place.


You seem to see brain engagement as a Boolean phenomenon. I don't believe
it's as simple as that; people /do/ make mistakes even when their brains
/are/ engaged.


Entirely agreed. It's just that *certain* classes of mistakes can be
trivially avoided if the brain is fully engaged and I claim that the =
vs == mistakes are one such class.


I accept that you claim that. I happen to disagree.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #44
In <3f******@news2.power.net.uk> Richard Heathfield <in*****@address.co.uk.invalid> writes:
Dan Pop wrote:
If you don't engage the brain, the technique
doesn't buy you anything (it just make your code look silly, from a
logical point of view),

Logically, a==b and b==a are equivalent. (Duh.)


When was the last time you said "compare 0 to x" in plain English?


Never. But we're not discussing English here. We're discussing C.


Nope, we're discussing the way people think. From the C's point of view
it doesn't make any difference how you write it and nobody claimed
otherwise. But C code is not written for the exclusive perusal of the
C compilers. And when people read the code, *many* things that don't
make any difference to the compiler become (more or less) important.
As a C beginner, how many times have you written "0 == x"?


Many times.


How many years have you been a beginner?
if you do, you don't need it in the first place.

You seem to see brain engagement as a Boolean phenomenon. I don't believe
it's as simple as that; people /do/ make mistakes even when their brains
/are/ engaged.


Entirely agreed. It's just that *certain* classes of mistakes can be
trivially avoided if the brain is fully engaged and I claim that the =
vs == mistakes are one such class.


I accept that you claim that. I happen to disagree.


Which means that you can't tell for sure which operator is which when
writing C code. If you could, it would be impossible to use the wrong
operator when performing an equality test. The usual excuse for this
mistake is not paying enough attention, which can be entirely avoided by
engaging the brain.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #45
"Dan Pop" <Da*****@cern.ch> wrote in message
news:bp**********@sunnews.cern.ch...
In <3f******@news2.power.net.uk> Richard Heathfield <in*****@address.co.uk.invalid> writes:
Dan Pop wrote:
> If you don't engage the brain, the technique
> doesn't buy you anything (it just make your code look silly, from a
> logical point of view),

Logically, a==b and b==a are equivalent. (Duh.)

When was the last time you said "compare 0 to x" in plain English?


Never. But we're not discussing English here. We're discussing C.


Nope, we're discussing the way people think. From the C's point of view
it doesn't make any difference how you write it and nobody claimed
otherwise. But C code is not written for the exclusive perusal of the
C compilers. And when people read the code, *many* things that don't
make any difference to the compiler become (more or less) important.
As a C beginner, how many times have you written "0 == x"?


Many times.


How many years have you been a beginner?
> if you do, you don't need it in the first place.

You seem to see brain engagement as a Boolean phenomenon. I don't believe
it's as simple as that; people /do/ make mistakes even when their brains
/are/ engaged.

Entirely agreed. It's just that *certain* classes of mistakes can be
trivially avoided if the brain is fully engaged and I claim that the =
vs == mistakes are one such class.


I accept that you claim that. I happen to disagree.


Which means that you can't tell for sure which operator is which when
writing C code. If you could, it would be impossible to use the wrong
operator when performing an equality test. The usual excuse for this
mistake is not paying enough attention, which can be entirely avoided by
engaging the brain.


That line of reasoning is equivalent to saying, "Don't use a debugger. You
should be able to desk-check your code to determine that it will work without
using a debugger to test it."

I actually had a manager say that.
Nov 13 '05 #46
Dan Pop wrote:
In <3f******@news2.power.net.uk> Richard Heathfield
<in*****@address.co.uk.invalid> writes:
Dan Pop wrote:
> If you don't engage the brain, the technique
> doesn't buy you anything (it just make your code look silly, from a
> logical point of view),

Logically, a==b and b==a are equivalent. (Duh.)

When was the last time you said "compare 0 to x" in plain English?
Never. But we're not discussing English here. We're discussing C.


Nope, we're discussing the way people think.


No, we're discussing C. Psychology is down the hall.
From the C's point of view
it doesn't make any difference how you write it and nobody claimed
otherwise.
Quite so.
But C code is not written for the exclusive perusal of the
C compilers. And when people read the code, *many* things that don't
make any difference to the compiler become (more or less) important.
True enough, and I accept that there is a minor readability hit on
const==var for /some/ people, but I consider the benefit (of avoiding a
subtle error) to outweigh the cost. Obviously, you disagree.
As a C beginner, how many times have you written "0 == x"?


Many times.


How many years have you been a beginner?


Just over 14 years. How about you?
> if you do, you don't need it in the first place.

You seem to see brain engagement as a Boolean phenomenon. I don't
believe it's as simple as that; people /do/ make mistakes even when
their brains /are/ engaged.

Entirely agreed. It's just that *certain* classes of mistakes can be
trivially avoided if the brain is fully engaged and I claim that the =
vs == mistakes are one such class.


I accept that you claim that. I happen to disagree.


Which means that you can't tell for sure which operator is which when
writing C code.


As a matter of fact, I can. Sometimes my fingers and/or keyboard can't,
though.
If you could, it would be impossible to use the wrong
operator when performing an equality test.
Wrong. It's not impossible at all.
The usual excuse for this
mistake is not paying enough attention, which can be entirely avoided by
engaging the brain.


The brain is often too busy to notice minor typos. Why not help the compiler
to pick up as many as it can? It seems perfectly logical to me.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #47
In <A_*******************@newsread2.news.pas.earthlin k.net> "xarax" <xa***@email.com> writes:
"Dan Pop" <Da*****@cern.ch> wrote in message
news:bp**********@sunnews.cern.ch...

Which means that you can't tell for sure which operator is which when
writing C code. If you could, it would be impossible to use the wrong
operator when performing an equality test. The usual excuse for this
mistake is not paying enough attention, which can be entirely avoided by
engaging the brain.
That line of reasoning is equivalent to saying, "Don't use a debugger. You
should be able to desk-check your code to determine that it will work without
using a debugger to test it."


Bullshit! Locally checking the correctness of an operator in the context
of the code you're just writing is not the same thing as globally
checking the correctness of a program. The human mind has its
limitations.

BTW, I don't need a debugger to test the correctness of a program.
There are much better and more efficient ways of doing it.
I actually had a manager say that.


Either he was an idiot or you're quoting him out of context.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #48
"Dan Pop" <Da*****@cern.ch> wrote in message
news:bq**********@sunnews.cern.ch...
In <A_*******************@newsread2.news.pas.earthlin k.net> "xarax" <xa***@email.com> writes:
"Dan Pop" <Da*****@cern.ch> wrote in message
news:bp**********@sunnews.cern.ch...

Which means that you can't tell for sure which operator is which when
writing C code. If you could, it would be impossible to use the wrong
operator when performing an equality test. The usual excuse for this
mistake is not paying enough attention, which can be entirely avoided by
engaging the brain.


That line of reasoning is equivalent to saying, "Don't use a debugger. You
should be able to desk-check your code to determine that it will work without
using a debugger to test it."


Bullshit! Locally checking the correctness of an operator in the context
of the code you're just writing is not the same thing as globally
checking the correctness of a program. The human mind has its
limitations.

BTW, I don't need a debugger to test the correctness of a program.
There are much better and more efficient ways of doing it.
I actually had a manager say that.


Either he was an idiot or you're quoting him out of context.


He was the former.
Nov 13 '05 #49
Dan Pop wrote:
"xarax" <xa***@email.com> writes:

.... snip ...

That line of reasoning is equivalent to saying, "Don't use a
debugger. You should be able to desk-check your code to determine
that it will work without using a debugger to test it."


Bullshit! Locally checking the correctness of an operator in the
context of the code you're just writing is not the same thing as
globally checking the correctness of a program. The human mind has
its limitations.


Counter example:

if (p = malloc(N * sizeof *p)) {
/* carry on with gay abandon */
}
else {
/* cleanup */
exit(EXIT_FAILURE);
}

is perfectly legitimate code, although some may disapprove. We
can also flip it to something slightly more readable with:

if (NULL == (p = malloc(N * sizeof *p))) {
/* cleanup */
exit(EXIT_FAILURE);
}
else {
/* carry on with gay abandon */
}

or we could use (my preference):

if (!(p = malloc(N * sizeof *p))) {
/* cleanup */
exit(EXIT_FAILURE);
}
else {
/* carry on with gay abandon */
}

and I am sure you can come up with further variations.

The point is that I have flipped operators about with some
abandon, but all the fragments are correct code. So, to requote,
"Locally checking the correctness of an operator in the
context of the code you're just writing" has very little to do
with it.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 13 '05 #50

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

Similar topics

15
4128
by: Stig Brautaset | last post by:
Hi group, I'm playing with a little generic linked list/stack library, and have a little problem with the interface of the pop() function. If I used a struct like this it would be simple: ...
6
8180
by: bob_jenkins | last post by:
{ const void *p; (void)memset((void *)p, ' ', (size_t)10); } Should this call to memset() be legal? Memset is of type void *memset(void *, unsigned char, size_t) Also, (void *) is the...
188
17206
by: infobahn | last post by:
printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */
9
5280
by: Juggernaut | last post by:
I am trying to create a p_thread pthread_create(&threads, &attr, Teste, (void *)var); where var is a char variable. But this doesnt't work, I get this message: test.c:58: warning: cast to pointer...
5
3501
by: Stijn van Dongen | last post by:
A question about void*. I have a hash library where the hash create function accepts functions unsigned (*hash)(const void *a) int (*cmp) (const void *a, const void *b) The insert function...
27
8909
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...
49
2740
by: elmar | last post by:
Hi Clers, If I look at my ~200000 lines of C code programmed over the past 15 years, there is one annoying thing in this smart language, which somehow reduces the 'beauty' of the source code...
2
2165
by: Siv | last post by:
what is meant by dereferecing pointer? why does it occur? how to fix it?
28
1792
by: junky_fellow | last post by:
Guys, Consider a function func(void **var) { /* In function I need to typecast the variable var as (int **) I mean to say, I need to access var as (int **) }
0
7257
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,...
1
7098
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
7521
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...
1
5084
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...
0
4745
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...
0
3232
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...
0
1591
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 ...
1
798
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
455
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...

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.