Download presentation
Presentation is loading. Please wait.
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
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.