Presentation is loading. Please wait.

Presentation is loading. Please wait.

Abstract Data Type C and Data Structures Baojian Hua

Similar presentations


Presentation on theme: "Abstract Data Type C and Data Structures Baojian Hua"— Presentation transcript:

1 Abstract Data Type C and Data Structures Baojian Hua bjhua@ustc.edu.cn

2 Data Types A data type consists of: A collection of data elements (a type) A set of operations on these data elements Data types in languages: predefined: any language defines a group of predefined data types C e.g.: int, char, float, double, … user-defined: allow programmers to define their own (new) data types C e.g.: struct, union, …

3 Data Type Examples Predefined: type: int elements: …, -2, -1, 0, 1, 2, … operations: +, -, *, /, %, … User-defined: type: complex elements: 1+3i, -5+8i, … operations: new, add, sub, distance, …

4 Concrete Data Types (CDT) An concrete data type: both concrete representations and their operations are available Almost all C predefined types are CDT For instance, “ int ” is a 32-bit double-word, and +, -, … Knowing this can do dirty hacks See demo …

5 Abstract Data Types (ADT) An abstract data type: separates data type declaration from representation separates function declaration (prototypes) from implementation (definitions) A language must some form of mechanism to support ADT interfaces in Java signatures in ML (roughly) header files & typedef in C

6 Case Study Suppose we ’ d design a new data type to represent complex number c: a data type “ complex ” elements: 3+4i, -5-8i, … operations: new, add, sub, distance, … How to represent this data type in C (CDT, ADT or … )?

7 Complex Number // Recall the definition of a complex number c: c = x + yi, where x,y \in R, and i=sqrt(-1); // Some typical operations: complex Complex_new (double x, double y); complex Complex_add (complex c1, complex c2); complex Complex_sub (complex c1, complex c2); complex Complex_mult (complex c1, complex c2); complex Complex_divide (complex c1, complex c2); // Next, we’d discuss several variants of rep’s: // CDT, ADT.

8 CDT of Complex: Interface — Types // In file “complex.h”: #ifndef COMPLEX_H #define COMPLEX_H struct Complex_t { double x; double y; }; typedef struct Complex_t Complex_t; Complex_t Complex_new (double x, double y); // other function prototypes are similar … #endif

9 Client Code // With this interface, we can write client codes // that manipulate complex numbers. File “main.c”: #include “complex.h” int main () { Complex_t c1, c2, c3; c1 = Complex_new (3.0, 4.0); c2 = Complex_new (7.0, 6.0); c3 = Complex_add (c1, c2); Complex_output (c3); return 0; } Do we know c1, c2, c3’s concrete representation? How?

10 CDT Complex: Implementation // In a file “complex.c”: #include “complex.h” Complex_t Complex_new (double x, double y) { Complex_t c = {.x = x,.y = y}; return c; } // other functions are similar. See Lab1

11 Problem #1 int main () { Complex_t c; c = Complex_new (3.0, 4.0); // Want to do this: c = c + (5+i6); // Ooooops, this is legal: c.x += 5; c.y += 6; return 0; }

12 Problem #2 #ifndef COMPLEX_H #define COMPLEX_H struct Complex_t { // change to a more fancy one? Anger “main”… double a[2]; }; typedef struct Complex_t Complex_t; Complex_t Complex_new (double x, double y); // other function prototypes are similar … #endif

13 Problems with CDT? Operations are transparent. user code have no idea of the algorithm Good! Data representations dependence Problem #1: Client code can access data directly kick away the interface safe? Problem #2: make code rigid easy to change or evolve?

14 ADT of Complex: Interface — Types // In file “complex.h”: #ifndef COMPLEX_H #define COMPLEX_H // note that “struct complexStruct” not given typedef struct Complex_t *Complex_t; Complex_t Complex_new (double x, double y); // other function prototypes are similar … #endif

15 Client Code // With this interface, we can write client codes // that manipulate complex numbers. File “main.c”: #include “complex.h” int main () { Complex_t c1, c2, c3; c1 = Complex_new (3.0, 4.0); c2 = Complex_new (7.0, 6.0); c3 = Complex_add (c1, c2); Complex_output (c3); return 0; } Can we still know c1, c2, c3’s concrete representation? Why?

16 ADT Complex: Implementation#1 — Types // In a file “complex.c”: #include “complex.h” // We may choose to define complex type as: struct Complex_t { double x; double y; }; // which is hidden in implementation.

17 ADT Complex: Implementation Continued // In a file “complex.c”: #include “complex.h” Complex_t Complex_new (double x, double y) { Complex_t c; c = malloc (sizeof (*c)); c->x = x; c->y = y; return c; } // other functions are similar. See Lab1

18 ADT Summary Yes, that ’ s ADT! Algorithm is hidden Data representation is hidden client code can NOT access it thus, client code independent of the impl ’ Interface and implementation Do Lab1

19 Polymorphism To explain polymorphism, we start with a new data type “ tuple ” A tuple is of the form: (x, y) x  A, y  B (aka: A*B) A, B may be unknown in advance and may be different E.g: A=int, B=int: (2, 3), (4, 6), (9, 7), … A=char *, B=double: ( “ Bob ”, 145.8), ( “ Alice ”, 90.5), …

20 Polymorphism From the data type point of view, two types: A, B operations: new (x, y); // create a new tuple with x and y equals (t1, t2); // equality testing first (t); // get the first element of t second (t); // get the second element of t … How to represent this type in computers (using C)?

21 Monomorphic Version We start by studying a monomorphic tuple type called “ intTuple ” : both the first and second components are of “ int ” type (2, 3), (8, 9), … The intTuple ADT: type: intTuple elements: (2, 3), (8, 9), … Operations: tuple new (int x, int y); int first (int t); int second (tuple t); int equals (tuple t1, tuple t2); …

22 “ IntTuple ” CDT // in a file “int-tuple.h” #ifndef INT_TUPLE_H #define INT_TUPLE_H struct IntTuple_t { int x; int y; }; typedef struct IntTuple_t IntTuple_t; IntTuple_t IntTuple_new (int n1, int n2); int IntTuple_first (IntTuple_t t); … #endif

23 Or the “ IntTuple ” ADT // in a file “int-tuple.h” #ifndef INT_TUPLE_H #define INT_TUPLE_H typedef struct IntTuple_t *IntTuple_t; IntTuple_t IntTuple_new (int n1, int n2); int IntTuple_first (IntTuple_t t); int IntTuple_equals (IntTuple_t t1, IntTuple_t t2); … #endif // We only discuss “tupleEquals ()”. All others // functions left to you.

24 Equality Testing // in a file “int-tuple.c” int Tuple_equals (IntTuple_t t1, IntTuple_t t2) { return ((t1->x == t2->x) && (t1->y==t2->y)); } x y t1 x y t2

25 Problems? It ’ s ok if we only design “ IntTuple ” But we if we ’ ll design these tuples: (int, double), (int, char *), (double, double), … Same code exists everywhere, no means to maintain and evolve Nightmares for programmers Remember: never duplicate code!

26 Polymorphism Now, we consider a polymorphic tuple type called “ tuple ” : “ poly ” : may take various forms Every element of the type “ tuple ” may be of different types (2, 3.14), ( “ 8 ”, ‘ a ’ ), ( ‘ \0 ’, 99), … The “ tuple ” ADT: type: tuple elements: (2, 3.14), ( “ 8 ”, ‘ a ’ ), ( ‘ \0 ’, 99), …

27 The Tuple ADT What about operations? tuple new (??? x, ??? y); ??? first (tuple t); ??? second (tuple t); int equals (tuple t1, tuple t2); …

28 Polymorphic Type To resove this, C dedicates a special polymorphic type “ void * ” “ void * ” is a pointer which can point to “ any ” concrete types (i.e., it ’ s compatible with any pointer type), very poly … long history of practice, initially “ char * ” can not be used directly, use ugly cast similar to constructs in others language, such as “ Object ”

29 The Tuple ADT What about operations? tuple newTuple (void *x, void *y); void *first (tuple t); void *second (tuple t); int equals (tuple t1, tuple t2); …

30 “ tuple ” Interface // in a file “tuple.h” #ifndef TUPLE_H #define TUPLE_H typedef void *poly; typedef struct Tuple_t * Tuple_t; Tuple_t Tuple_new (poly x, poly y); poly first (Tuple_t t); poly second (Tuple_t t); int equals (Tuple_t t1, Tuple_t t2); #endif TUPLE_H

31 Client Code // file “main.c” #include “tuple.h” int main () { int i = 8; Tuple_t t1 = Tuple_new (&i, “hello”); return 0; }

32 “ tuple ” ADT Implementation // in a file “tuple.c” #include #include “tuple.h” struct Tuple_t { poly x; poly y; }; Tuple_t Tuple_new (poly x, poly y) { tuple t = malloc (sizeof (*t)); t->x = x; t->y = y; return t; } x y t

33 “ tuple ” ADT Implementation // in a file “tuple.c” #include #include “tuple.h” struct Tuple_t { poly x; poly y; }; poly Tuple_first (Tuple_t t) { return t->x; } x y t

34 Client Code #include “complex.h” // ADT version #include “tuple.h” int main () { int i = 8; Tuple_t t1 = Tuple_new (&i, “hello”); // type cast int *p = (int *)Tuple_first (t1); return 0; }

35 Equality Testing struct Tuple_t { poly x; poly y; }; // The #1 try: int Tuple_equals (Tuple_t t1, Tuple_t t2) { return ((t1->x == t2->x) && (t1->y == t2->y)); // Wrong!! } x y t

36 Equality Testing struct Tuple_t { poly x; poly y; }; // The #2 try: int Tuple_equals (Tuple_t t1, Tuple_t t2) { return (*(t1->x) == *(t2->x) && *(t1->y) == *(t2->y)); // Problem? } x y t

37 Equality Testing struct Tuple_t { poly x; poly y; }; // The #3 try: int Tuple_equals (Tuple_t t1, Tuple_t t2) { return (equalsXXX (t1->x, t2->x) && equalsYYY (t1->y, t2->y)); // but what are “equalsXXX” and “equalsYYY”? } x y t

38 Function as Arguments // So in the body of “equals” function, instead // of guessing the types of t->x and t->y, we // require the callers of “equals” supply the // necessary equality testing functions. // The #4 try: typedef int (*tf)(poly, poly); int Tuple_equals (tuple t1, tuple t2, tf eqx, tf eqy) { return (eqx (t1->x, t2->x) && eqy (t1->y, t2->y)); }

39 Change to “ tuple ” Interface // in file “tuple.h” #ifndef TUPLE_H #define TUPLE_H typedef void *poly; typedef int (*tf)(poly, poly); typedef struct Tuple_t *Tuple_t; Tuple_t Tuple_new (poly x, poly y); poly Tuple_first (Tuple_t t); poly Tuple_second (Tuple_t t); int Tuple_equals (Tuple_t t1, Tuple_t t2, tf eqx, tf eqy); #endif TUPLE_H

40 Client Code // in file “main.c” #include “tuple.h” int main () { int i=8, j=8, k=7, m=7; Tuple_t t1 = Tuple_new (&i, &k); Tuple_t t2 = Tuple_new (&j, &k); Tuple_equals (t1, t2, Int_equals, Int_equals); return 0; }

41 Moral void* serves as polymorphic type in C mask all pointer types (think Object type in Java) Pros: code reuse: write once, used in arbitrary context we ’ d see more examples later in this course Cons: Polymorphism doesn ’ t come for free boxed data: data heap-allocated (to cope with void *) no static or runtime checking (at least in C) clumsy code extra function pointer arguments

42 Function-Carrying Data Why we can NOT make use of data, such as passed as function arguments, when it ’ s of type “ void * ” ? Better idea: Let data carry functions themselves, instead passing function pointers such kind of data called objects

43 Function Pointer in Data int Tuple_equals (Tuple_t t1, Tuple_t t2) { // note that if t1->x or t1->y has carried the // equality testing functions, then the code // could just be written as: return (t1->x->equals (t1->x, t2->x) && t1->y->equals (t1->y, t2->y)); } equals …… equals_y x y t1 equals …… equals_x

44 Function Pointer in Data // To cope with this, we should modify other // modules. For instance, the “complex” ADT: struct Complex_t { int (*equals) (poly, poly); double a[2]; }; Complex_t Complex_new (double x, double y) { Complex_t c = malloc (sizeof (*c)); c->equals = Complex_equals; …; return n; } x n equals y

45 Function Call int Tuple_equals (Tuple_t t1, Tuple_t t2) { return (t1->x->equals (t1->x, t2->x) && t1->y->equals (t1->y,t2->y)); } a[0] equals a[0] t2 a[1] x y t1 x y

46 Client Code // in file “main.c” #include “complex.h” #include “tuple.h” int main () { Complex_t c1 = Complex_new (1.0, 2.0); Complex_t c2 = Complex_new (1.0, 2.0); Tuple_t t1 = Tuple_new (c1, c2); Tuple_t t2 = Tuple_new (c1, c2); Tuple_equals (t1, t2); // dirty simple! :-P return 0; }

47 Object Data elements with function pointers is the simplest form of objects object = virtual functions + private data With such facilities, we can in principal model object oriented programming In fact, early C++ compilers compiles to C That ’ s partly why I don ’ t love object- oriented languages

48 Summary Abstract data types enable modular programming clear separation between interface and implementation interface and implementation should design and evolve together Polymorphism enables code reuse Object = data + function pointers


Download ppt "Abstract Data Type C and Data Structures Baojian Hua"

Similar presentations


Ads by Google