Homework / Quiz • Exam 2 • Continuing K&R Chapter 6

Download Report

Transcript Homework / Quiz • Exam 2 • Continuing K&R Chapter 6

Homework / Quiz
• Exam 2
– Solutions Posted
– Questions?
• Continuing K&R Chapter 6
• HW6 is on line – due class 22
1
Self Referential structs, K&R 6.5
• Look at this binary tree structure (Pg. 139)
now
is
for
all
aid
the
men of
good
time
party their
to
come
2
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!
3
tnode *root
Tree of struct tnodes
char *word
int count
tnode *left
tnode *right
char *word
int count
tnode *left
tnode *right
keyword \0
…
char *word
int count
tnode *left
tnode *right
…
…
…
…
…
4
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
5
Declarations / Prototypes
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include “getch.h”
(see functions in App. B2, pp. 248-249, K&R)
(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 *);
6
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;
}
7
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);
}
}
8
getword ( )
int getword(char *word, int lim) {
int c; 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, word empty
*/
}
for( ; --lim > 0; w++)
if (!isalnum(*w = getch())) {
/* identfier alpha or digits */
ungetch(*w); break; /* e.g., + might be needed later */
}
*w = '\0';
return word[0];
}
9
addtree ( )
struct tnode *talloc(void);
char *strdup(char *);
/* allocate. return ptr to tnode
/* allocate space, copy word there
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;
}
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
10
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
11
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);
12
addtree ( )
• No, root is already a pointer, struct tnode *, but it
is the pointer root itself that must be modified
• To modify root, we would need to declare addtree
with a pointer to a struct tnode * as the first arg:
void addtree(struct tnode **pptr, char *w)
{
struct tnode *p = *pptr;
• Call it from main recursively by invocation:
addtree(&root, word);
• Then, addtree could set the value for root directly
*pptr = p;
• Same is true when adding a left or right child
13
talloc ( )
• How to write talloc to allocate a tnode and
return a pointer.
struct tnode *talloc(void)
{
return (struct tnode *) malloc
(sizeof(struct tnode));
}
14
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)
{
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;
}
15
Intro to HW6
• Memory model for malloc( ) and free( )
Before any calls to alloc( ):
Free
allocbuf:
After two calls to alloc( ) and before call to freef( ):
Free
In Use
In Use
allocbuf:
After call to freef( ) on first block alloc gave out:
allocbuf:
Free
In Use
Free
16
Intro to HW6
• Fragmentation with malloc( ) and free( )
Before call to alloc( ) for a large memory block:
allocbuf:
In use
Free
In use
Free In use
Free In use
alloc can NOT provide a large contiguous block
of memory - even though there is theoretically
sufficient free memory! Memory is fragmented!!
17
Intro to HW6
• Not possible to “defragment” allocbuf memory after
the fact as you would do for a disk
• On a disk, the pointers to memory are in the disk
file allocation table and can be changed
• With malloc, programs are holding pointers to
memory they own - so can’t be changed!!
• Can only defragment as blocks are freed by using
program
18
Intro to HW6
• Initial structures in allocbuf[]
blockl
blockr
Free Memory
• Structures after two calls to alloc()
blockl
blockr blockl
Free Memory
blockr blockl
Inuse 2
blockr
Inuse 1
19
Intro to HW6
• Structures after free call on first block only
blockl
blockr blockl
Free Memory
blockr blockl
Inuse 2
blockr
Free Memory
• Structures after free call on second block only
blockl
blockr blockl
Free Memory
blockr
Inuse 1
Note effect of coalesce!
20
Intro to HW6
• Four possible states for block being freed
–
–
–
–
Between two blocks that are still in-use
Above a free block and below an in-use block
Above an in-use block and below a free block
Above a free block and below a free block
• When freeing a block, coalesce with adjacent
free blocks to avoid unnecessary fragmentation
of allocbuf (allows alloc to serve later requests
for large amounts of memory)
21