structures c and data structures baojian hua bjhua@ustc.edu.cn

Post on 19-Dec-2015

248 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Structures

C and Data StructuresBaojian Hua

bjhua@ustc.edu.cn

Why need “Structure”?

So far, we’d discussed two kinds of data: Simple: char, int, long, double, etc. Scalar: array, pointer, etc.

It’s inconvenient in some applications: See next slides for an example

Example// We want to represent time as year/month/date:int f (){ int year1, year2, month, date;

year1 = 2050; year2 = 2020; month = 12; date = 30; date++; // Should we increase year1 or year2?}// The problem is that there is no logical// connection between them. We need “structure”!

Structure Declaration// Start with key word “struct” and followed by // an optional structure tag, and then a list // (one or more) of fields. // Example, to represent a two-dimensional point:struct point2d{

int x; int y;

}; // note the semicolon// point2d contains two fields x and y, both of // type int.// struct point2d (as a whole) is a (user-define

d) // new type.

Variable Definition// Given the declaration above, we may declare a

// variable pt:

struct point2d pt;

// to be of type “struct point2d”, just the same

// way as we write:

int i;

Structure Fields// Given the variable definition

struct point2d pt;

// fetching its fields x or y:

pt.x;

pt.y;

// which act as ordinary variables, such as:

pt.x = 9;

pt.y = 10;

// or:

printf (“%d\n”, pt.x + pt.y);

Structure in Structure// Having known that structures are types, we may

// study its memory layout. Technically, a

// structure occupies a piece of continuous space:

// So, we may even nest structures

// in other structures, as in:

struct rect

{

struct point2d pt1;

struct point2d pt2;

};

x

yx

y

x

y

Structures and Functions// A function creating a point2d structure:struct point2d create (int ax, int ay){ struct point2d pt;

pt.x = ax; pt.y = ay; return pt;}

// And a sample call:struct point2d p = create (3, 4);

3 4

ax==3 ay==4

Structures and Functions// A function creating a point2d structure:struct point2d create (int ax, int ay){ struct point2d pt;

pt.x = ax; pt.y = ay; return pt;}

// And a sample call:struct point2d p = create (3, 4);

x=???

y=???

3 4

ax==3 ay==4

Structures and Functions// A function creating a point2d structure:struct point2d create (int ax, int ay){ struct point2d pt;

pt.x = ax; pt.y = ay; return pt;}

// And a sample call:struct point2d p = create (3, 4);

3 4

ax==3 ay==4x=???

y=???

Structures and Functions// A function creating a point2d structure:struct point2d create (int ax, int ay){ struct point2d pt;

pt.x = ax; pt.y = ay; return pt;}

// And a sample call:struct point2d p = create (3, 4);

x==3

y==4

3 4

ax==3 ay==4

Structures and Functions// A function creating a point2d structure:struct point2d create (int ax, int ay){ struct point2d pt;

pt.x = ax; pt.y = ay; return pt;}

// And a sample call:struct point2d p = create (3, 4);

x==3

y==4

3 4

ax==3 ay==4

Structures and Functions// A function creating a point2d structure:struct point2d create (int ax, int ay){ struct point2d pt;

pt.x = ax; pt.y = ay; return pt;}

// And a sample call:struct point2d p = create (3, 4);

x==3

y==4

3 4

ax==3 ay==4

x==3

y==4

Structures and Functions// A function creating a point2d structure:struct point2d create (int ax, int ay){ struct point2d pt;

pt.x = ax; pt.y = ay; return pt;}

// And a sample call:struct point2d p = create (3, 4);

x==3

y==4

p

3 4

Structures as Functions Arguments// Like the structure return value, passing// structures to functions copy the whole // structure field-by-field (call-by-value):struct point2d mult2 (struct point2d pt){ pt.x *= 2; pt.y *= 2; return pt;}

// A sample call:struct point2d p = mult2 (initPt);// Much like the previous example// Analysis leave to you

x==3

y==4

Moral Structures returned from function and

passed to functions are call-by-value Pros: a simple style of functional programming

result in elegant and easy-to-reason code ideas from functional languages (lisp, ML, F#), but

may also be useful in imperative and OO languages Cons: may be too inefficient

stupidly copy a big value semantics inconsistent with array

Next, we’d discuss a more imperative style Update in place

Pointers to Structures// Pointers to structures are just like pointers

// to any other kind of data:

struct point2d *pt;

// declares pt to be a pointer to a structure

// ponit2d, which looks like:

// To reference x and y, we use:

(*pt).x;

(*pt).y;

// or a more concise shorthand:

pt->x;

pt->y;pt

x==3

y==4

Structure Pointers as Functions Arguments// Address passing:void mult2 (struct point2d *pt){ pt->x *= 2; pt->y *= 2; return;}

// A sample call (no return value):struct point2d p = creat (3, 4);mult2 (&initPt);// Analysis leave to you

Self-referential Structures// With structures pointer mechanism, we may

// write self-referential structures (structures

// fields point to same type of structures):

struct node

{

int data;

struct node *next;

};

data

next

data

next

data

next

Union

A union may hold (at different times) objects of different types and sizes compilers take care of the space

allocation, alignment, etc. Unions provide a way to manipulate

different kinds of data in a single area of storage

Union// A sample union type:

union intOrArray

{

int i;

int a[2];

};

// which declares intOrArray to have two fields:

// integer i and int array a of length 2.

i, a[0]

a[1]

Union// A sample union type:

union intOrArray

{

int i;

int a[2];

};

// which declares intOrArray to have two fields:

// integer i and int array a of length 2.

union intOrArray u;

u.a[0] = 88;

u.a[1] = 99; // u.i == ???

i, a[0]

a[1]

Union// A sample union type:

union intOrArray

{

int i;

int a[2];

};

// which declares intOrArray to have two fields:

// integer i and int array a of length 2.

union intOrArray u;

u.i = 77;;

// u.a[2] = ???

i, a[0]

a[1]

Union// A sample union type:union intOrArray{ int i; int a[2];};// Even worse. What if we write an “output”?void output (union intOrArray x){

printf (“%d\n”, x.i);// or:printf (“%d, %d\n”, x.a[0], x.a[1]);

}

i, a[0]

a[1]

Moral on Union

Union gives us a magical bag to let us bypass the C’s type system store an integer, but take out an array

It’s the programmers’ responsibility to keep union data consistent But what if the union value is written

by others or from a library, which we may know nothing about?

Tagged Union// In order to distinguish union states, we

// annotate unions with tags:

struct ss

{

enum {INT, ARRAY} tag;

union intOrArray

{

int i;

int a[2];

} u;

};

i, a[0]

a[1]

tag

Tagged Union// And for variable temp:

struct ss temp;

// now we must take care of temp’s tag fields:

temp.u.i = 99;

temp.tag = INT;

// Or to store an array:

temp.u.a[0] = 3;

temp.u.a[1] = 4;

temp.tag = ARRAY;

i, a[0]

a[1]

tag

Tagged Union// data accessing is guarded:

void output (struct ss x)

{

switch (x.tag) {

case INT:

printf (“%d”, x.u.i);

break;

case ARRAY:

printf (“%d, %d”, x.u.a[0], x.u.a[1]);

break;

default:

// error handling… }

}

i, a[0]

a[1]

tag

typedef---Define Our Own Types And it’s rather stupid and annoying t

o always write long type names like these:

struct point2d pt;struct point2d *pp;

And even some types are rather crazy:int (*f[10])(int, int);int (*f(char c))(int, int);

Are there some better methods? Yes! It’s the “typedef”

typedef---Define Our Own Types// C has a mechanism called “typedef” allowing us

// to define our own types (abbreviations).

// For instance:

typedef struct point2d pt2d;

// defines “pt2d” to be a type equivalent to

// “struct point2d”. And next, “pt2d” could be

// used just as any other type:

pt2d pt;

pt.x = 3;

pt.y = 4;

typedef---Define Our Own Types// Not only structures can be typedefed, but also // any type name, even the pre-defined ones in C:typedef int sizeT;

sizeT i;i = sizeof (int);sizeT j;j = i;

typedef---Define Our Own Types// More examples of typedef:typedef int *t1;typedef int (*t2)();typedef char **t3;typedef int *t4[10];typedef int (*t5)[10];typedef int *t6();typedef char (*(*t7())[])();typedef (*(*t8[3])())[5];

typedef---Define Our Own Types// More examples of typedef:typedef int *t1;typedef int (*t2)();typedef char **t3;typedef int *t4[10];typedef int (*t5)[10];typedef int *t6();typedef char (*(*t7())[])();typedef char (*(*t8[3])())[5];

// How to read these crazy stuffs? // Next, to show the general principal, I’ll take // type t7 as a running example:

Inorder Analysistypedef char (*(*t7())[])();

// t7 is a function, takes void// function returns a pointer// pointing to an array// array storing pointers// pointing to functions (taking void returning // char)

// Really annoying! Better solutions? Yes!

Preordertypedef char (*(*t7())[])();

// Step by step:typedef char (*t71)();typedef t71 t72[];typedef t72 *t7();

// Question: How to rewrite t8?

Type Cast Revisit

We’d discussed type cast Ex: (int)3.14 unsafe in general

Type cast on pointers is more flexible, subtle, and dangerous we’d discuss an example below

Type Cast on Pointerschar c = ‘a’;

char *p = &c;

int *q = (int *)p;

*q = 9999;

short *r = (short *)q;

*r = 88;

‘a’

?

?

?

?

p

1000

1001

1002

1003

1004

Exampleint sum (int x, int y){

int temp = x + y; return temp;}

int main () { char *s = (char *)sum;

return 0;}

temp=x+y

?

return temp

?

sum:

10001004100810121016

s

Exampleint sum (int x, int y){

int temp = x + y; return temp;}

int main () { char *s = (char *)sum;

char a[100];

return 0;}

temp=x+y

?

return temp

?

sum:

10001004100810121016

s

Exampleint sum (int x, int y){

int temp = x + y; return temp;}

int main () { char *s = (char *)sum;

char a[100];int i;for (i=0; i<100; i++) a[i] = s[i];

return 0;}

temp=x+y

?

return temp

?

sum:

10001004100810121016

s

Example

int main () { char *s = (char *)sum;

char a[100];int i;for (i=0; i<100; i++) a[i] = s[i];

// call array a?

return 0;}

temp=x+y

?

return temp

?

sum:

10001004100810121016

s

int sum (int x, int y){ int temp = x + y; return temp;}

Example

int main () { char *s = (char *)sum;

char a[100];int i;for (i=0; i<100; i++) a[i] = s[i];

// call array a?a(3, 4);

return 0;}

temp=x+y

?

return temp

?

sum:

10001004100810121016

s

int sum (int x, int y){ int temp = x + y; return temp;}

An Array Can be Called!

typedef int (*tf)(int, int);int main () { char *s = (char *)sum;

char a[100];int i;for (i=0; i<100; i++) a[i] = s[i];

// call array a?(tf(a)) (3, 4);

return 0;}

temp=x+y

?

return temp

?

sum:

10001004100810121016

s

int sum (int x, int y){ int temp = x + y; return temp;}

Summary of Typedefs typedef doesn’t create any new type

name it creates shorthands for known types

typedef is an important mechanism: to make program maintenance and porti

ng easy to enable information hiding

more on this later

Bit-fields// What’s bit-fields, and why do we want them?

// We start by defining a student structure:

struct student

{

char *name;

int gender; // 0 or 1

int classNum; // 0~7

int isLeader; // 0 or 1

};

// See the problem?

Bit-fields// To save space, We use bit-fields:

struct student

{

char *name;

unsigned int gender : 1; // 0 or 1

unsigned int classNum : 3; // 0~7

unsigned int isLeader : 1; // 0 or 1

};

// Question: what the size of “struct student”?

Bit-fields// Sample operations:#define FEMALE 0x00#define MALE 0x01#define CLASS1 0x00…#define CLASS8 0x07

struct student s;s.name = “Bill Gates”;s.gender = MALE;s.classNum = CLASS0;s.isLeader = 0x00;

Bit-fields for Data // Besides saving space, some externally-imposed

// data formats require compact data rep’.

// As a final example in this slide, we discuss

// x86’s interrupt descriptor (id):

Bit-fields for Data

struct idtEntry{

unsigned int offset0_15 : 16;unsigned int selector : 16;unsigned int notUsed : 5;unsigned int zeros : 3;unsigned int reserved : 5;unsigned int dpl : 2;unsigned int p : 1;unsigned int offset16_31 : 16;

};

top related