Bill Cunningham said:
Ben Bacarisse said:
[Aside: I have used the technique where a tree pointer must always be
"valid" so that every recursive type has its own empty pointer:
struct tree { struct tree *left, *right; int num; };
static struct tree empty_tree = { &empty_tree, &empty_tree };
struct tree *tree_null = &empty_tree;
but I though that would over-complicate things here.]
Ben were you the one that gave me the original code I've been working
with.
Yes. You asked in comp.programming and then posted again here (that's
fine, by the way, I'm just explaining the situation).
When I run into trouble is with main. I get much from the tree and
tree functions set up but your main confuses me.
I can see it might. It was very terse.
int main(int argc, char *argv[])
{
struct tree *tp = NULL;
while (--argc > 0) {
int v = atoi(*++argv);
if (strchr(*argv, '?'))
printf("%d%s found\n", v, tree_has(tp, v) ? "" : " not");
else {
tp = tree_insert(tp, atoi(*argv));
printf("T = ");
tree_print(tp);
putchar('\n');
}
}
return 0;
}
This compiles no problem and you countdowns of argc I've never seen before.
The use of a poiunter in atoi knocks me off a bit. This code reaks of
experience.
Kind of you to say so but to me, if it reeks of anything, it is the
classroom. Too many years getting short examples that fit on one OHP
slide. Terse, dense examples are good to talk over but a proper
programmer would never be so compact in real code.
The idea was to provide a simple way to test "tree_insert" and
"tree_has" from the same program so I test if the argument has a '?'
in it. If so (strchr returns non-NULL) I print a string that depends
on the result of tree_has. If not, the numerical value of the argument
is added to the tree and the new tree is printed. I notice that I
should have used v again:
tp = tree_insert(tp, v);
rather than convert the string twice.
The pattern:
while (--argc > 0) {
++argv;
/* use *argv now, or maybe use or store *++argv */
}
is an old one. I was not sure where I saw it first but I see (having
just had a look) that it is in K&R1 so I'd lay odds on it being from
there.
int v = atoi(*++argv);
is horribly terse but the loop pattern is so well know that I bet most
readers don't miss a beat. ++argv yields a pointer to the next
argument (argv includes the program name which we don't want so
pre-increment is the right thing to do here). * of that is that the
argument itself (a pointer to the start of a string) and atoi of that
is a reasonable way to get a int from a string in test code like
this.
I spent years drawing diagrams like this one to get the hang of
pointers and pointers to pointers. This one shows the situation at
the first call to atoi after running the command "./t 3 1 2 2?"
+-----+ +-----+-----+-----+-----+
argv | --|--------------------->| '.' | '/' | 't' | 0 |
+-----+ +-----+ +-----+-----+ +-----+-----+-----+-----+
| --|----->| x--|----->| '3' | 0 |
+-----+ +-----+ +-----+-----+ +-----+-----+
| --|--------------------->| '1' | 0 |
+-----+ +-----+ +-----+-----+ +-----+-----+
| 4 | | --|----->| '2' | 0 |
+-----+ +-----+ +-----+-----+ +-----+-----+-----+
argc | --|--------------------->| '2' | '?' | 0 |
+-----+ +-----+-----+-----+
| 0 |
+-----+
argc has been decremented and argv incremented once. The box with the
x in it is *argv and the one with the '3' in it is **argv. The tall
column of pointers is the anonymous argument array to whose first
element (thanks, Keith!) argv initially points.
[If you don't use a fixed-width font, the above will just look like a
mess.]