560 likes | 683 Views
System Programming in C. Lecture 9. Lecture Summary. More language features: Libraries Recursion Unions time.h Continue on dynamic structures Queue. Libraries. Suppose there’s a need to create some “library” that will export some functions and variables.
E N D
System Programming in C Lecture 9
Lecture Summary • More language features: • Libraries • Recursion • Unions • time.h • Continue on dynamic structures • Queue
Libraries • Suppose there’s a need to create some “library” that will export some functions and variables. • For instance, you’ve written a set of functions for working with linked lists, and want to use them “as is” – i.e. without further modifications and possibly from several places.
Libraries • Possible ways of making code available for use: • Just copy-and pasted the code • Copy-and-Paste the functions • Share source and header file with functions • Make a library – share its interface (as an .H file) and the compiled library.
Libraries • Each further way (in a row 1-4) imposes more initial work, but better insulation between the utility code (in our example - set of functions for working with lists) and its user. • Why insulate library from its user? • Make the library user more independent of the library contents
Libraries • When creating a library, all the functions and variables defined at global scope can be made visible for library user. • Functions and variables defined at the scope other than global are not visible to library user. • Library is just a collection of functions, so presence of main() function in library is not necessary.
func1.h /* define the external interface for LIBRARY.LIB - all the functions from the library that will be called from outside the library, should be declared (not defined!) here */ #ifndef FUNC1_H /* to prevent multiple inclusion */ #define FUNC1_H /* here come definitions of external functions, variables, etc. - everything we want to make available to library user. In our case, it is a single function */ func1(); extern int a_variable; #endif /* FUNC1_H */
func1.c #include <stdio.h> /* define a variable in global scope - this variable may be made visible (by declaring it) to library users */ int a_variable = 0; /* define a function in global scope - this function may be made visible (by declaring it) to library users */ func1() { printf("func1 is called\n"); } /* everything that is declared not in global scope is NOT visible from outside of the program - for instance, following variable and functions declared at file scope cannot be made visible to library users and even other source files in the library */ static int intern_variable = 0; static int intern_function() {return 0;}
Libraries • At that moment, the library can be built. When library is built, LIBRARY.LIB is placed into the project directory (in our case - C:\WORK\LECT9\).
Using a library • From now on, every project may use the library – to do it, two files are needed: • FUNC1.H - functions prototypes • LIBRARY.LIB - actual code • Let’s create a project that does it
main.c /* a simple driver program for LIBRARY.LIB - uses a function from it*/ #include "func1.h" /* include definition of a function from LIBRARY.LIB*/ #include <stdio.h> main() { /* call a function exported by a LIBRARY.LIB */ func1(); /* use an external variable from LIBRARY.LIB */ printf("a_variable from LIBRARY.LIB is equal %d\n", a_variable ); }
Recursion • Recursive function – either directly or indirectly calling itself • Serves as a tool to solve algorithms by reducing the original problem to a smaller problems (and, in turn, reducing them to a smaller problems.
Recursion Example: /* use of recursion for calcularing the factorial: n! = n * (n-1) * (n-2) * ... * 3 * 2 * 1 */ int func1(int n) /* assumes n>=0 */ { if (!n) return 1; return ( n * func1 ( n-1 ) ); /* recursive call*/ }
Recursion /* use of recursion for reversing the user input */ void func2(void) /* assumes user input */ { int c; if ((c = getchar()) != '\n') func2(); /* recursive call */ putchar(c); }
Example – Tower of Hanoi • The Towers of Hanoi: Given 3 poles, with disks of different sizes numbered 1..n according to size. • Begin: all disks are stacked on pole A with disk 1 on the top and disk n at bottom. • End: all disks are stacked on pole C in the same order • Cannot place disk N on the top of disks 1, 2, ..., N-1
Example – Tower of Hanoi Move disk 1 from A to C Move disk 2 from A to B Move disk 1 from C to B Move disk 3 from A to C Move disk 1 from B to A Move disk 2 from B to C Move disk 1 from A to C => 7 moves for N=3 (..15, 31, 63)
Example – Tower of Hanoi • In general: • Move n-1 disks from A to B through C • Move disk n from A to C • Move n-1 disks from B to C through A
Example – Tower of Hanoi void hanoi (int n, char *a, char *b, char *c) { if (n==1) { printf("Move disk 1 from %s to %s\n", a, c); return; } hanoi(n-1, a, c, b); printf("Move disk %d from %s to %s\n", n, a, c); hanoi(n-1, b, a, c); }
Example – Linked List /* conversion function */ ListItem *array_to_list(int *a, int size) { ListItem *head; if (!size) return NULL; head = (ListItem*)malloc(sizeof(ListItem)); head->data = a[0]; if ( size > 1 ) head->next = array_to_list(a+1, size-1); else head->next = NULL; return head; }
Example – Linked List Definition of ListItem: struct listitem { int data; struct listitem *next; }; typedef struct listitem ListItem;
Unions • Unions are used as variables, when it’s convenient to have the same variable hold different types of data • In effect a union is a struct, in which all members have offset zero. The union is big enough to hold the largest member. • It holds one member at a time
Unions union int_or_float { int iVal; float fVal; }; union int_or_float x; x.iVal = 10; /* x as int */ x.fVal = 4.321; /* x as float, overwrites int */
Unions struct typed_value { enum { INT, FLOAT} type; union int_or_float value; }; struct typed_value aValue; /* aValue hold information on its type*/ aValue.type = INT; aValue.value.iVal = 10;
Unions struct typed_value divide (int a, int b) { struct typed_value answer; if (! (a % b) ) { answer.type = INT; answer.value.iVal = a/b; }else { answer.type = FLOAT; answer.value.fVal = (float)a/(float)b; } return answer; } ... aValue = divide (8,4); aValue = divide (2,3);
time.h • Header file defining structures, macros and functions for manipulating date and time • Usefule for timing your program
time.h typedef long time_t; /* time value */ typedef long clock_t; struct tm { int tm_sec; /* seconds after the minute - [0,59] */ int tm_min; /* minutes after the hour - [0,59] */ int tm_hour; /* hours since midnight - [0,23] */ int tm_mday; /* day of the month - [1,31] */ int tm_mon; /* months since January - [0,11] */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday - [0,6] */ int tm_yday; /* days since January 1 - [0,365] */ int tm_isdst; /* daylight savings time flag */ };
time.h • clock_t clock(void); • returns number of CPU clock ticks since the beginning of execution. Use clock()/CLOCK_PER_SECOND to convert to seconds • to measure time spent in program, call clock() at start of the program, and its return value should be substracted from subsequent calls • time_t time(time_t *tptr); returns current calendar time (number of seconds elapsed since midnight (00:00:00), January 1, 1970, coordinated universal time, according to the system clock.).
time.h • char *asctime(const struct tm *tp); • converts tm to a string, for printing • char *ctime(time_t *tptr); • converts time_t tptr to a string, for printing • double difftime(time_t t0, time_t t1); • returns t1-t0 • Use two calls for time and then difftime to compute how long your program runs.
Queue: Principles of Operations • Queue is quite similar to stack. • Possible to implement in linked list and array – will discuss both ways • Just an ordered list with two ends – possible operations are: inserting element to the first end and getting/removing element from the second. Operations with other elements are not allowed.
Implementing in Linked List Each node will looks like this: typedef struct tagINFO{ int r,i; /* represent a complex number - r(real) and i(imaginary) parts */ }INFO; typedef struct tagNODE{ INFO info; /* information in the queue node*/ struct tagNode *next; /* link to next node*/ }NODE;
Queue Definition typedef struct tagQUEUE{ NODE *head; /* pointer to head of the queue is sufficient, but we use pointer to */ NODE *tail; /* tail also to optimize add/get operations */ }QUEUE;
Operations with Queue • FlushQueue – erase all elements from the queue • Add – add an element to queue • Get – get an element from queue • IsEmpty – check if queue contains no elements • Length – return number of elements in a queue • PrintQueue – print all the elements of the queue
Module with queue - Interface /* Should contain ONLY what is needed to LIBRARY user! */ typedef struct tagINFO{ int r,i; }INFO; struct tagQUEUE; /* !!! */ typedef struct tagQUEUE QUEUE; /* !!! */ void put( QUEUE *q, INFO *info); void get( QUEUE *q, INFO *info); void init_queue(QUEUE **q); /* init queue */ void destroy_queue(QUEUE *q); /* de-initialize queue */ void flush_queue(QUEUE *q); /* clear the queue */ int is_empty(QUEUE *q);
Using the Queue Interface QUEUE *q; INFO a ={1,2}, b = {3,4}, c = {5,6},d; init_queue(&q); put(q,&a); put(q,&b); put(q,&c); get(q, &d); get(q, &d); get(q, &d); destroy_queue(q);