#include #include struct StringSet { int num_elts; int array_size; char ** array; }; struct StringSet * new_string_set(); void free_string_set(struct StringSet *set); int string_set_member(struct StringSet *set, char* str); void string_set_add(struct StringSet *set, char* str); void string_set_foreach(struct StringSet *set, void (*f)(char*)) { int i; for(i=0; inum_elts; ++i) (*f)(set->array[i]); } // hmm, to write a string-length summer we would with // foreach, where we would put "sofar"? // Only choice is a static or global variable and that // will _not_ work with recursion, threading, etc. and // is very bad style (don't!) // what we need is a better foreach, here are two ways // this first way is like how pthread_create gets an arg to the new thread void foreach1(struct StringSet *set, void (*f)(void*,char*), void*data) { int i; for(i=0; inum_elts; ++i) (*f)(data,set->array[i]); } // Simple example: void summer_helper(void* data, char * str) { int * sofar = (int*)data; *sofar += strlen(str); } int length_summer(struct StringSet * set) { int * sofar = (int*)malloc(sizeof(int)); *sofar = 0; foreach1(set,summer_helper,sofar); int res = *sofar; free(sofar); return res; } // this second wasy is more object-like struct StringDoer { void (*f)(struct StringDoer*,char*); // take pointer to this! }; void foreach2(struct StringSet *set, struct StringDoer* d) { int i; for(i=0; inum_elts; ++i) (*d->f)(d,set->array[i]); } // Simple example (with one technically illegal cast that works on attu // on almost all compilers/machines): struct StringLengthSummer { // very important that f field is first! void (*f)(struct StringLengthSummer*,char*); int (*getSum)(struct StringLengthSummer*); int sofar; }; // this isn't a keyword, but it's a great choice since it's // how the C++/Java compiler does it! void summer_helper2(struct StringLengthSummer* this,char*s) { this->sofar += strlen(s); } int getSumHelper(struct StringLengthSummer* this) { return this->sofar; } // new_ is just part of the function name, but we use it like C++'s new struct StringLengthSummer * new_StringLengthSummer() { struct StringLengthSummer * d = (struct StringLengthSummer*)malloc(sizeof(struct StringLengthSummer)); d->sofar = 0; d->f = summer_helper2; d->getSum = getSumHelper; return d; } void delete_StringLengthSummer(struct StringLengthSummer * this) { free(this); } int length_summer2(struct StringSet * set) { struct StringLengthSummer * d = new_StringLengthSummer(); foreach2(set,(struct StringDoer*)d); // upcast (cast needed)! int ans = d->getSum(d); delete_StringLengthSummer(d); return ans; } // if we had more time, I'd show how to do overriding, super calls, etc.