Preparing for the Midterm Exam
• Exam logistics o Date/time: Thursday October 26 in lecture o Open books, open notes, open mind, but not open laptop/PDA Abstract Data Types (ADTs), o Covering material from lecture, precept, and reading, but not tools After More on the Heap • Preparing for the midterm o Lecture and precept materials available online o Course textbooks, plus optional books on reserve Prof. David August o Office hours and the course listserv o Old midterm exams on the course Web site COS 217
1 2
A Little More About the Heap… Example: Read a Line (or URL)
• Memory layout of a C program • Write a function that reads a word from stdin o Text: code, constant data o Read from stdin until encountering a space, tab, ‘\n’, or EOF o Data: initialized global & static variables o Output a pointer to the sequence of characters, ending with ‘\0’ BSS: uninitialized global & static variables 0 o Text • Example code (very, very buggy) o Heap: dynamic memory Stack: local variables Data o #include
• But, why would you ever do this??? scanf(“%s”, buf); o Glutton for punishment??? printf(“Hello %s\n”, buf); return 0; } Stack 0xffffffff 3 4 Problem: Need Storage for String Problem: Input Longer Than Array
• Improving the code • Improving the code o Allocate storage space for the string o Don’t allow input that exceeds the array size Example: define an array o • Example (better, but not perfect) • Example (still somewhat buggy) #include
5 } 6
Problem: How Much Storage? Really Solving the Problem
• Improving the code • Remaining problems o Finding out how much space you need from the user o User can’t input long words o Allocate exactly that much space, to avoid wasting o Storage wasted on short words • Beginning of the example (is this really better?) • But, how do we proceed? o Too little storage, and we’ll run pass the end or have to truncate int main(void) { Yet, we don’t know how big the word might be int n; o char* buf; • The gist of a solution Pick a storage size (“line_size”) and read up to that length printf(“Max size of word: “); o scanf(“%d”, &n); o If we stay within the limit, we’re done o If the user input exceeds the space, we can buf = malloc((n+1) * sizeof(char)); – Allocate space for another line, and keep on reading scanf(“%s”, buf); – At the end, allocate one big buffer and copy all the lines into it printf(“Hello %s\n”, buf); return 0; } 7 8 Abstract Data Type (ADT)
• An ADT module provides: o Data type o Functions that operate on the type • Client does not manipulate the data representation directly Abstract Data Types (ADTs) o The client should just call functions • “Abstract” because the observable results (obtained by client) are independent of the data representation • Programming language support for ADT o Ensure that client cannot possibly access representation directly o C++, Java, other object-oriented languages have private fields o C has opaque pointers
9 10
An ADT Example: Stacks Stack Interface (stack.h)
• LIFO: Last-In, First-Out #ifndef STACK_INCLUDED What’s this for? • Like the stack of trays at the cafeteria #define STACK_INCLUDED o “Push” a tray onto the stack o “Pop” a tray off the stack typedef struct Item *Item_T; typedef struct Stack *Stack_T; • Useful in many contexts extern Stack_T Stack_new(void); extern int Stack_empty(Stack_T stk); extern void Stack_push(Stack_T stk, Item_T item); extern Item_T Stack_pop(Stack_T stk);
#endif
11 12 Notes on stack.h Stack Implementation: Array
•Type Stack_T is an opaque pointer stack.c Clients can pass Stack_T around but can’t look inside #include
Stack_T Stack_new(void) { Stack_T stk = malloc(sizeof(*stk)); assert(stk != NULL); stk->count = 0; return stk; } 13 14
Careful Checking With Assert Stack Implementation: Array (Cont.) stack.c int Stack_empty(Stack_T stk) { #include
CAPACITY too large: waste memory struct Stack { val int val; data wasted space next struct Stack *next; } *head; CAPACITY too small: head empty stack data
push(1); push(2); push(3); assertion failure (if you were careful) buffer overrun (if you were careless) 3 2 1 head 17 18
Popping and Pushing Stack Implementation: Linked List
3 2 1 stack.c head #include
Client Program: Uses Interface Problem: Multiple Kinds of Stacks? client.c • Good, but still not flexible enough What about a program with multiple kinds of stacks #include
•Heap o Memory allocated and deallocated by the programmer o Useful for making efficient use of memory o Useful when storage requirements aren’t known in advance Backup Slides • Abstract Data Types (ADTs) on Void Opaque Pointers o Separation of interface and implementation o Don’t even allow the client to manipulate the data directly o Example of a stack – Implementation #1: array – Implementation #2: linked list o Backup slides on void pointers follow…
25 26
stack.h (with void*) Stack Implementation (with void*) stack.c #ifndef STACK_INCLUDED #define STACK_INCLUDED #include
Client Program (With Void) Structural Equality Testing
Suppose we want to test two stacks for equality: client.c (with void*) #include
int main(int argc, char *argv[]) { int Stack_equal(Stack_T s1, Stack_T s2) { int i; Stack_T s = Stack_new(); return (s1 == s2); for (i = 1; i < argc; i++) } Stack_push(s, Item_new(argv[i])); while (!Stack_empty(s)) We want to test whether two stacks are equivalent stacks, printf(“%s\n”,Stack_pop(s)); not whether they are the same stack. return 0; } 31 32 Almost, But Not Quite... Item ADT Provides Equal Test How about this: How about this: int Stack_equal(Stack_T s1, Stack_T s2) { int Stack_equal(Stack_T s1, Stack_T s2) { struct List *p, *q; struct List *p, *q; for (p=s1->head, q=s2->head; p && q; for (p=s1->head, q=s2->head; p && q; p=p->next, q=q->next) p=p->next, q=q->next) if ( ! Item_equal(p->val, q->val)) if (p->val != q->val) return 0; return 0; return p==NULL && q==NULL; return p==NULL && q==NULL; } } This is good for the “Item_T” version of stacks (provided the This is better, but what we want to test whether s1->val is Item interface has an Item_equal function), but what about equivalent to s2->val, not whether it is the same. 33 the void* version of stacks? 34
Function Pointers Passing a Function Pointer
How about this: int Stack_equal(Stack_T s1, Stack_T s2, int (*equal)(void *, void *)) { int Stack_equal(Stack_T s1, Stack_T s2, struct List *p, *q; int (*equal)(void *, void *)) { for (p=s1->head, q=s2->head; p && q; p=p->next, q=q->next) struct List *p, *q; if ( ! equal((void*)p->val, (void*) q->val)) for (p=s1->head, q=s2->head; p && q; return 0; return p==NULL && q==NULL; p=p->next, q=q->next) } if ( ! equal((void*)p->val, (void*) q->val)) Client: return 0; int char_equal (char *a, char *b) { return p==NULL && q==NULL; return (!strcmp(a,b)); } } int string_stacks_equal(Stack_T st1, Stack_T st2) { return Stack_equal(st1, st2, The client must pass an equality-tester function to Stack_equal. (int (*)(void*, void*)) char_equal); } 35 cast 36