Hi,
I have a problem with arrays within a struct definitions. Let's say I
want to define a tree structure with tree nodes and each node can have
several child nodes, like this:
typedef struct _node {
char *name;
struct _node *parent;
struct _node *children
Missing a semicolon here. (Demonstrating that you have not shown
us actual code, but some kind of inaccurate paraphrase. My further
comments are about the code you've shown; if they do not apply to the
actual code you're having trouble with, that's your fault and not mine.)
By the way: Don't use the identifier _node at file scope (outside
a function), because it's a reserved name that the implementation may
be using for its own purposes. If those purposes clash with yours,
it's your fault for misappropriating a reserved name -- think of it as
identity theft. Advice: Don't use _ at the start of an identifier
(this advice is stronger than strictly necessary, but easy to follow).
} node;
Now when I create a tree like this:
node root = {"root node\0"};
node n1 = {"n1\0"};
node n2 = {"n1\0"};
node n3 = {"n1\0"}:
Is there some special reason you need *two* '\0' bytes at the
end of each string? The C compiler will append one '\0' on its
own (except in one odd case that doesn't apply here), which is
why sizeof("Hello") is six, not five.
Also, you may find it confusing that all child nodes have
the same name, like the five sons of George Foreman, all named
"George."
node children[] = {n1, n2, n3};
This will only work inside a function (that is, not at file
scope), and even then it won't do quite what you probably want.
You've already got four structs: root,n1,n2,n3. This creates
three more, children[0],children[1],children[2], and *copies*
their content from n1,n2,n3. So now you've got seven nodes:
one parent and two copies of each child.
If you want the children to be in an array, you've got to
put them there to start with. Get rid of n1,n2,n3 and write
node children[] = { {"n1"}, {"n2"}, {"n3"} };
root.children = children;
There are a few problems here (or "near here"). One is that
you haven't finished initializing things: From your struct layout
it looks like each child is supposed to point to its parent -- but
all your children have NULL as the parent pointer.
A bigger problem is that you've given yourself no way to know
how many children a node has. Are there three? Two? Forty-two?
None at all? There's nothing in the data to let you know (well,
the "none at all" case is distinguishable, but ...). There are
many ways to do this; two of the commonest are:
- The parent node has an element that counts its children,
so you'd write something like
root.children = children;
root.kidcount = sizeof children / sizeof children[0];
- The array of children is followed by a "sentinel," a child
that's distinguishable from the others as "I'm not really
a child," much like the '\0' at the end of a string. In
your example this might be a node with an empty name, so
node children[] = { {"n1"}, {"n2"}, {"n3"}, {""} };
... and when traversing the children of a node you'd know
to stop when you found one with "" as its name.
and browse through it like this:
int i;
for (i = 0; i< 20; i++) {
printf("node #%i: %s\n", root->children.name);
}
it has far more entries than I initially added. I thought there should
actually occur a segfault for any entry greater than 3. Why is this?
Accessing outside the bounds of an array is undefined behavior.
Note that word "undefined:" it means there are no promises at all
about what will happen. In particular, there is no promise that
your program will generate a trap or fault of any kind -- it might,
of course, or it might do something even weirder, or it might even
seem to "work." There are no guarantees, good or bad.
Also no matter how many children I add, sizeof ( e.g. sizeof(root--
of the struct rather than the array. Any Thoughts?
I'm not sure what you mean by `sizeof(root--children)', because
as far as I can see it shouldn't compile. The number 3 is also
puzzling; I don't see anything in your code that is likely to have
a sizeof equal to 3 (although surprises are possible). But again:
We know you've not shown us your actual code, so we're all just
guessing at what you really mean.
However: None of your nodes contains any array; all of your
nodes have exactly the same size. Each node contains three pointers
(a char* and two struct _node*), and that's that. These pointers
aim at data that is not inside the node, and does not contribute
to the sizeof the node.