wkaufman@oracle.oracle.com (William P. Kaufman) (04/07/90)
In article <78932@tut.cis.ohio-state.edu> <waylonis@cis.ohio-state.edu> writes: >typedef struct menu_struct >{ > int num_items; > char **item; /* this may be wrong, but I want a arbitrary > number of items of arbitrary length */ >} menu_td; > >menu_td menu[5]; /* want 5 menus */ > > menu[0].item[0] = "Item0"; Don't tell me: the compiler accepts it, but it pukes at run-time. OK, the trick I've found to dealing with obscure structures is to strip down what you want, and figure out its type. menu is an array of menu_td, so menu[0] is valid, and it's a menu_td. menu[0].item then is valid, and its a (char **), so that assignment _looks_ fine. But, since it's a _pointer_ and not an _array_, menu[0].item points to random space: it needs to be allocated! menu[0].item = (char **)malloc( (size_of_item_array) * (sizeof(char *)) ); Can't stress strongly enough--if a) you need a list of stuff (this is true for any type) b) either the number of stuff is constant, or it's range is known and is small and c) you don't need off-the-cuff assignment of the stuff pointe typedef struct menu_struct { int num_items; char *item[MAXITEM]; } menu_td; If you've got a good idea of how many items you'll have (say, within a tenth of the actual number), and you don't have any cases where you might want to assign a pre-assigned array of strings to item, this might be better. Hey, you see how many posts we get on this one subject alone? Practice safe programming! Even if it might cause you to waste a couple of megs of memory,...memory's cheap! But, I'm not. -- Bill Kaufman. {...}!hplabs!oracle.com!wkaufman .sig under construction
chris@mimsy.umd.edu (Chris Torek) (04/08/90)
In article <78932@tut.cis.ohio-state.edu> dan_waylonis@gryphon.cis.ohio-state.edu writes: >I am having a problem with loading a structure with a string: No, actually, you are having a different problem. Anyway: >typedef struct menu_struct { > int num_items; > char **item; /* this may be wrong, but I want a arbitrary > number of items of arbitrary length */ >} menu_td; The type for `item' is the best one for `zero or more pointers to char', each of which points to zero or more characters. If `item' is set to the address of the first of a sequence of pointers, each of which points to the first of a sequence of characters that are ended by a '\0', then `item[i]' (for any valid, i.e., in-range, integral i) can be called a `string of arbitrary length'. >menu_td menu[5]; /* want 5 menus */ > > menu[0].item[0] = "Item0"; > >But this last line doesn't work... This is a type mismatch. menu[0].item[0] has type `pointer to char'; its value is that of the first of the pointers to which menu[0].item has been set to point. Since menu[0].item has not been set to point anywhere, this value is either garbage (if menu[] is an automatic varible) or a nil of type `char **' (if menu[] is a global or static variable). In either case, it does not point to at least one pointer. So, the first problem is to set menu[i] (for 0 <= i <= 4) so that it has a valid `num_items' field and a valid `items' field: int i; for (i = 0; i < 4; i++) { menu[i].num_items = 0; menu[i].items = NULL; } Now each menu has zero items, and a nil pointer of type `char **' (no matter which of the two proper standard definitions of `NULL' are used). (This loop is unnecessary if menu[] is global or static. It is also unnecessary if you can prove that menu[i] will not be used before it is set to some valid value.) Next, suppose that menu[0] has a fixed size, 4, and should have 4 `items': menu[0].num_items = 4; menu[0].items must now be set to point to the first of at least four contiguous objects of type `pointer to char'. One easy way to do this is: { static char *menu0[4] = { "foo", "bar", "baz", "raz" }; menu[0].items = &menu0[0]; } Now menu[0].items points to the first element of the four-element array `menu0'. Each element of that array has type `pointer to char', and each points to a (read-only) `C string' (i.e., array of one or more characters, ended by '\0') allocated somehow by the compiler. If, instead, the `strings' are to be read from an external file, the process is more complicated; I will not go into this here. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
chris@mimsy.umd.edu (Chris Torek) (04/09/90)
In article <23571@mimsy.umd.edu> I wrote: >... char **item; /* this may be wrong, but I want a arbitrary >... ...item[0] = "Item0"; >This is a type mismatch. Oops. My brain was on fire. Sorry about that. The types do match; the problem (as given by the rest of my article) is that the `item' pointer has no valid value. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris