340 likes | 346 Views
Homework. Continuing K&R Chapter 6. Review structs. struct point { int x; int y; }; struct point pt1, pt2; struct point maxpt = {320, 200};. struct point { int x; int y; }pt1,pt2;. Review structs. struct rect { struct point pt1; struct point pt2;
E N D
Homework • Continuing K&R Chapter 6
Review structs struct point { int x; int y; }; struct point pt1, pt2; struct point maxpt = {320, 200}; struct point { int x; int y; }pt1,pt2;
Review structs struct rect { struct point pt1; struct point pt2; }; Note: must have ; following } struct rect box;
Review structs box.pt1.x = 5; box.pt1.y = 10; box.pt2.x = 10; box.pt2.y = 20; area = (box.pt2.x – box.pt1.x) * (box.pt2.y – box.pt1.y);
What can we do with a struct? • Reference members box.pt2.x = box.pt1.x + width; • Assign as a unit pt2 = pt1; • Create a pointer to it struct point *ppt1; ppt1 = &pt1;
What can we do with a struct? • Not legal to compare structs if (pt1 = = pt2) … INVALID • Must be done as: if (pt1.x = = pt2.x && pt1.y = = pt2.y) …
structs and Functions, K&R 6.2 /* ptinrect: if point p in rect r, return 1 else return 0 note: slightly different from K&R example */ int ptinrect (struct point p, struct rect r) { return p.x >= r.pt1.x && p.x <= r.pt2.x && p.y >= r.pt1.y && p.y <= r.pt2.y; }
Arrays of structs, K&R 6.3 • Multiple related arrays char * keyword[NKEYS]; int keycount[NKEYS]; • Can be implemented as an array of structs struct key { char *word; int count; } keytab [NKEYS];
Arrays of structs • Alternative array of structs implementation struct key { char *word; int count; }; struct key keytab[NKEYS];
Arrays of structs • Initialization for an array of structs struct key { char *word; int count; } keytab[ ] = { “auto”, 0, … “while”, 0 }; Another way to write keytab[ ] = { {“auto”, 0}, … {“while”, 0} };
sizeof structs • sizeof is a compile-time unary operator • Can be used to get the number of integer bytes (actually size_t): sizeof object sizeof (type name) • NKEYS can be dynamically derived using sizeof #define NKEYS (sizeof keytab / sizeof (struct key)) #define NKEYS (sizeof keytab / sizeof keytab[0])
Pointers to structs, K&R 6.4 • Declare and initialize a pointer to struct struct point p; struct point *pp = &p; • Refer to members of struct p via pointer pp (*pp).x and (*pp).y See precedence • More commonly done as: pp->x and pp->y See precedence
Pointers to structs struct string { int len; char *cp; } *p; struct string xp; p = &xp; ExpressionSame asValue / Effect ++p->len ++(p->len) increments len *p->cp *(p->cp) value is a char *p->cp++ *((p->cp)++) value is a char increments cp
Example of pointers to struct struct string a = {8 , “yellow”}; struct string b = {9 , “black”}; struct string * ptr_a = &a; p = &b; ptr_a->len = ? ptr_a->cp = ? p->len = ? p->cp = ? 8 pointer to address of ‘y’ and *ptr_a->cp = ‘y’
Pointers to structs /* ptinrect: (pointer version) if point p in rect r, return 1 else return 0 */ int ptinrect (struct point *pp, struct rect *rp) { return pp->x >= rp->pt1.x && pp->x <= rp->pt2.x && pp->y >= rp->pt1.y && pp->y <= rp->pt2.y; }
now is the men for of time all good their to party aid come Self Referential structs, K&R 6.5 • Count the occurrences of all the words in some input • Look at this binary tree structure (Pg. 139) for the sentence “now is the time for all good men to come to the aid of their party” • At any node, the left subtree only has words that are lexicographically less than the word at the node. The right subtree has words that are greater.
Self Referential structs struct tnode { /* the tree node struct */ char *word; /* points to the word at this node */ int count; /* has a count of occurances */ struct tnode *left; /* a word < one at this node */ struct tnode *right; /* a word > one at this node */ }; • OK to have a pointer to a struct of same type in its own definition • NOT OK to have a struct itself in its own definition (OK to have a different struct as a member)!
Tree of struct tnodes tnode *root char *word int count tnode *left tnode *right keyword \0 … char *word int count tnode *left tnode *right … … … char *word int count tnode *left tnode *right … …
Self Referential structs • Each node is a struct tnode with a string value and a count of occurrences • Each node also contains a pointer to a left child and a right child • Each child is another struct tnode
Declarations / Prototypes #include <stdio.h> #include <ctype.h> (see functions in App. B2, pp. 248-249, K&R) #include <string.h> (see functions in App. B3, pp. 249-250, K&R) #define MAXWORD 100 int getword(char *word, int lim); struct tnode *addtree(struct tnode *, char *); void treeprint(struct tnode *);
Main program int main( ) { struct tnode *root; /* ptr to root for binary tree */ char word[MAXWORD]; /* word to get from stdin */ root = NULL; /* initially, no tnodes in tree */ /* OK that root pointer points to NULL initially */ while (getword(word, MAXWORD) != EOF) /* getword from stdin */ if (isalpha(word[0])) /* from ctype.h library */ root = addtree(root, word); /* expect not NULL anymore */ treeprint(root); /* print it out in order */ return 0; }
getword ( ) /* getword: get next word or character from input */ /* a word is either a string of letters and digits beginning with a letter, or a single non-white space character */ int getword(char *word, int lim) { int c, getch(void); void ungetch(int); char *w = word; while (isspace(c = getch())) /* skip spaces; c first non-space */ ; if (c != EOF) *w++=c; /* c might be EOF here (empty word) */ if(!isalpha(c)) { /* c (identifier) starts with alpha */ *w = '\0'; return c; } /* if not, form word with 1 non-white space char*/ for( ; --lim > 0; w++) if (!isalnum(*w = getch())) { /* identify alpha or digits */ ungetch(*w); break; /* need to go back 1 character if the end is reached*/ } *w = '\0'; return word[0]; }
addtree ( ) struct tnode *talloc(void); /* allocate. return ptr to tnode */ char *strdup(char *); /* allocate space, copy word there */ /* addtree: add a node with w, at or below p */ struct tnode *addtree(struct tnode *p, char *w) { int cond; /*for empty tree, root is NULL */ if (p == NULL) { /* nothing at this node yet */ p = talloc(); /* allocate a new node */ p->word = strdup(w); /* allocate space, copy word there */ p->count = 1; /* count is 1 */ p->left = p->right = NULL; /* this works; see precedence */ } else if ((cond = strcmp(w, p->word)) == 0) /* string.h */ p->count++; /* repeated word, increment count */ else if (cond < 0) /* note cond remembers strcmp above */ p->left = addtree(p->left, w); /* less: go left subtree */ else /* more, go to right subtree */ p->right = addtree(p->right, w); return p; }
addtree( ) • Note, that addtree is recursive. If it adds a node, it might need to add root or any left or right child anywhere down the tree • We pass struct tnode *p as first argument, and also pass back the same type - always a pointer to the node at the current recursive nesting level • Any time a new node is created: root, p->left or p->right in node above will be set for the FIRST time based on return value from addtree
addtree ( ) • When main calls addtree, the return sets root value each time even if the root already pointed to tnode • Allows for possible addition of a pointer to a node • Why do we need to return a struct tnode *p when we have struct tnode *p as an argument? • Can't we just set it via argument, return void from addtree, and write (in main)? addtree(root, word); instead of root = addtree(root, word);
addtree ( ) • No, root is already a pointer, struct tnode *p, but it is the pointer p itself that must be modified • To modify root, we would need to declare addtree with a pointer to p as 1st arg: void addtree(struct tnode **p, char *w); • Call it from main recursively by invocation: addtree(&root, word); • Then, addtree could set the value for root directly instead of by return value. Same is true of lower levels when adding a left or right child
talloc ( ) • How to write talloc to allocate a tnode and return a pointer. struct tnode *talloc(void) { return (struct tnode *) malloc (sizeof(struct tnode)); }
strdup ( ) • strdup ( ) creates space for a character string, copies a word into it (up to null terminator) and returns the char pointer char *strdup(char *s) { char * p; p = (char *) malloc (strlen(s)+1); /* +1 for '\0' */ if (p != NULL) /* if malloc didn’t fail */ strcpy(p, s); /* library function in string.h */ return p; }
treeprint ( ) • To print out tree contents in order: void treeprint (struct tnode *p) { if (p != NULL) { treeprint (p->left); printf (%4d %s\n”, p->count, p->word); treeprint (p->right); } }
treeprint Recursion Program Flow now 41 1 23 22 the is 2 40 21 24 18 men 31 17 30 time for of 3 20 32 39 29 16 19 13 25 26 12 35 36 party their to all good 4 11 27 28 8 14 15 33 34 37 38 7 aid come 5 6 9 10
Table Lookup, K&R 6.6 • struct for a linked list of names/definitions struct nlist { /* table entry */ struct nlist *next; /* link to next */ char *name; /* word name */ char *defn; /* word definition */ };
Table Lookup / Linked Lists • Array of pointers to null terminated linked lists of structs defining table entries 0 array nlist [0] [1] 0 nlist=0 means end of the list [2] 0 0 [3] [4] 0
Table Lookup / Linked List • Hash search- incoming name is converted into a non-negative integer which is used to index into an array of pointers • Hash function to select starting array element unsigned int hash (char *s) { for (hashval = 0; *s != ‘\0’; s++) hashval = *s + 31 * hashval; return hashval % HASHSIZE; } • In lookup ( ), code for following a linked list: for (ptr = head; ptr != NULL; ptr = ptr->next)
Lookup Function /* look for s in hashtab */ struct nlist *lookup(char *s) { struct nlist *np; for (np = hashtab[hash(s)]; np !=null; np=np->next) if (strcmp(s, np->name) ==0) return np; return NULL; }