struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C...

18
C struct Types Computer Organization I 1 CS@VT ©2005-2019 McQuain struct Properties The C struct mechanism is vaguely similar to the Java/C++ class mechanisms: - supports the creation of user-defined data types - struct types encapsulate data members struct Location { int X, Y; }; But there are vital differences: - struct data members are "public", in fact there is no notion of access control - struct types cannot have function members - there is no concept of inheritance or of polymorphism

Transcript of struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C...

Page 1: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

1

CS@VT ©2005-2019 McQuain

struct Properties

The C struct mechanism is vaguely similar to the Java/C++ class mechanisms:

- supports the creation of user-defined data types

- struct types encapsulate data members

struct Location {

int X, Y;

};

But there are vital differences:

- struct data members are "public", in fact there is no notion of access control

- struct types cannot have function members

- there is no concept of inheritance or of polymorphism

Page 2: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

2

CS@VT ©2005-2019 McQuain

A struct Example

struct Location { // declare type globally

int X, Y;

};

int main() {

struct Location A; // declare variable of type Location

A.X = 5; // set its data members

A.Y = 6;

struct Location B; // declare another Location variable

B = A; // copy members of A into B

return 0;

}

Note:

- assignment is supported for struct types

- type declaration syntax used here requires specific use of struct in instance

declarations

Page 3: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

3

CS@VT ©2005-2019 McQuain

Another struct Example

struct _Location { // declare type globally

int X, Y;

};

typedef struct _Location Location; // alias a type name

int main() {

Location A; // declare variable of type Location

A.X = 5; // set its data members

A.Y = 6;

Location B; // declare another Location variable

B = A; // copy members of A into B

return 0;

}

Note:

- use of typedef creates an alias for the struct type

- simplifies declaration of instances

Page 4: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

4

CS@VT ©2005-2019 McQuain

struct Limitations

What else is supported naturally for struct types? Not much…

- no automatic support for equality comparisons (or other relational comparisons)

- no automatic support for I/O of struct variables

- no automatic support for deep copy

- no automatic support for arithmetic operations, even if they make sense…

- can pass struct variables as parameters (default is pass-by-copy of course)

- can return a struct variable from a function

- can implement other operations via user-defined (non-member) functions

Page 5: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

5

CS@VT ©2005-2019 McQuain

A struct Function Example

struct _Location { // declare type globally

int X, Y;

};

typedef struct _Location Location; // alias a type name

void initLocation(Location* L, int x, int y) {

(*L).X = x; // alternative: L->X = x;

(*L).Y = y;

}

Note:

- must pass Location object by pointer so function can modify original copy

- given a pointer to a struct variable, we access its members by dereferencing the

pointer (to get its target) and then using the member selector operator '.'

- the parentheses around the *L are necessary because * has lower precedence than .

- however, we can write L->X instead of (*L).X.

- use of address-of '&' operator in call to create pointer to A

Location A;

// call:

initLocation(&A, 5, 6);

Page 6: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

6

CS@VT ©2005-2019 McQuain

Another struct Function Example

struct _Location { // declare type globally

int X, Y;

};

typedef struct _Location Location; // alias a type name

Location updateLocation(Location Old, Location Move) {

Location Updated; // make a local Location object

Updated.X = Old.X + Move.X; // compute its members

Updated.Y = Old.Y + Move.Y;

return Updated; // return copy of local object

}

Note:

- we do not allocate Updated dynamically (via malloc); there is no need since we

know at compile time how many we need (1) and we can just return a copy and avoid

the cost of a dynamic allocation at runtime

- in C, dynamic allocation should only be used when logically necessary

Page 7: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

7

CS@VT ©2005-2019 McQuain

Typical struct Code Organization

// header file Location.h contains declaration of type and

// supporting functions

#ifndef LOCATION_H

#define LOCATION_H

struct _Location { // declare type globally

int X, Y;

};

typedef struct _Location Location; // alias a clean type name

Location updateLocation(Location Old, Location Move);

. . .

#endif

// Source file Location.c contains implementations of supporting

// functions

#include "Location.h"

Location updateLocation(Location Old, Location Move) {

. . .

}

. . .

Page 8: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

8

CS@VT ©2005-2019 McQuain

More Complex struct Types

// A struct type may contain array members, members of other

// struct types, anything in fact:

#ifndef QUADRILATERAL_H

#define QUADRILATERAL_H

#include "Location.h"

#define NUMCORNERS 4

struct _Quadrilateral {

Location Corners[NUMCORNERS];

};

typedef struct _Quadrilateral Quadrilateral;

. . .

#endif

Note:

- even though you cannot assign one array to another and you cannot return an array

from a function, you can do both of those things with a struct variable that contains

an array member

- Why?

Page 9: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

9

CS@VT ©2005-2019 McQuain

Example: Rational Numbers

The following slides are a case study based on a course project.

One shortcoming in C is the lack of a type to represent rational numbers.

A rational number is the ratio of two integers, where the denominator is not allowed to be

zero.

Rational numbers are important because we cannot represent many such fractions exactly in

decimal form (e.g., 1/3).

The struct mechanism in C allows us to implement a type that accurately represents

rational numbers (within the restrictions imposed by the limited range of integer types).

Page 10: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

10

CS@VT ©2005-2019 McQuain

Designing Data Representation

One fact is clear enough: a rational value consists of two integer values.

The obvious C approach would be:

struct _Rational {

int32_t Top;

int32_t Bottom;

};

typedef struct _Rational Rational;

A forward-looking approach might use int64_t instead, buying increased range and

doubling the storage cost.

Another thought would be to normalize the representation by using a uint32_t for the

denominator, so that a negative rational would always use a negative numerator.

For this example, we'll stick with the C code shown above.

Page 11: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

11

CS@VT ©2005-2019 McQuain

Designing Operations

When implementing a data type, we must consider what operations would be expected or

useful to potential users.

In this case, we have mathematics as a guide:

- creating a Rational object with any valid value

- adding two Rational objects to yield a third Rational object

- subtracting two Rational objects to yield a third Rational object

- multiplying two Rational objects to yield a third Rational object

- dividing two Rational objects to yield a third Rational object

- taking the absolute value of a Rational object, yielding a second Rational

object

- negating a Rational object, yielding a second Rational object

- comparing two Rational objects, with equals, less-than, etc.

- taking the floor/ceiling of a Rational object, yielding an integer

Page 12: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

12

CS@VT ©2005-2019 McQuain

/**

* Compute the sum of Left and Right.

* Pre:

* *Left and *Right have been properly initialized.

* Returns:

* A pointer to a Rational object equal to *Left + *Right.

*/

Rational* Rational_Add(const Rational* Left, const Rational* Right)

{

Rational *Sum = malloc(sizeof(Rational));

Sum->Top = Left->Top * Right->Bottom +

Left->Bottom * Right->Top;

Sum->Bottom = Left->Bottom * Right->Bottom;

Rational_Normalize(Sum);

return Sum;

}

A Specific Operation

Rational First, Second;

... // initialize First and Second

Rational *Sum = Rational_Add(&First, &Second);

Page 13: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

13

CS@VT ©2005-2019 McQuain

A Different Take on That

/**

* Compute the sum of Left and Right.

* Pre:

* *pSum is a Rational object

* Left and Right have been properly initialized.

* Post:

* *pSum is a normalized representation of Left + Right.

*/

void Rational_Add(Rational* const pSum, const Rational Left,

const Rational Right) {

pSum->Top = Left.Top * Right.Bottom +

Left.Bottom * Right.Top;

pSum->Bottom = Left.Bottom * Right.Bottom;

Rational_Normalize(pSum);

}

Rational First, Second, Sum;

... // initialize First and Second

Rational_Add(&Sum, First, Second);

Page 14: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

14

CS@VT ©2005-2019 McQuain

An Array Type

One way to address (some of) the shortcomings in C arrays would be to implement:

struct _iArray {

int32_t* Data;

uint32_t Dimension;

uint32_t Usage;

};

typedef struct _iArray iArray;

bool iArray_Init(iArray* const pA, uint32_t Size) {

if ( pA == NULL ) return false;

pA->Data = calloc(Size, sizeof(int32_t));

if ( pA->Data == NULL ) {

pA->Dimension = pA->Usage = 0;

return false;

}

pA->Dimension = Size;

pA->Usage = 0;

return true;

}

Page 15: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

15

CS@VT ©2005-2019 McQuain

Safe Array Insertion

Mutator operations could now be implemented safely:

bool iArray_Append(iArray* const pA, int32_t Elem) {

if ( pA == NULL ||

pA->Dimension == pA->Usage) {

return false;

}

pA->Data[Usage] = Elem;

pA->Usage++;

return true;

}

Data[usage] is the first

unused cell in the array

Reject insertion if array is full

Page 16: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

16

CS@VT ©2005-2019 McQuain

Or…

bool iArray_Append(iArray* const pA, int32_t Elem) {

if ( pA == NULL ) return false;

if ( pA->Dimension == pA->Usage) {

int32_t *temp = realloc(pA->Data, 2 * pA->Dimension);

if ( pA->Data == NULL ) {

return false;

}

pA->Data = temp;

pA->Dimension = 2 * pA->Dimension;

}

pA->Data[Usage] = Elem;

pA->Usage++;

return true;

}

Check whether array is full

realloc() will:

• Allocate new array or

simply "grow" the old one

• Copy data from old array

to new array, if necessary

• Deallocate old array, if

necessary

• Return NULL if fails

Page 17: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

17

CS@VT ©2005-2019 McQuain

Making a Deep Copy

/** Makes a duplicate of an existing iArray object.

* Pre:

* pA points to a correctly-initialized iArray object

* Post:

* A new iArray object has been created such that:

* - Data[] duplicates the content and dimension of

* the original

* - Usage and Dimension equal the original

* - no memory is shared between the two iArray objects

* Returns:

* Pointer to the new iArray object; NULL if it could not

* be created.

*/

iArray* iArray_Copy(iArray* const pA);

Assignment only copies the actual data members (fields) of a struct variable.

This is referred to as a shallow copy, and it's not suitable if there is dynamically-allocated

content.

To make a full (deep) copy, we must write a suitable copy function:

Page 18: struct Properties C 1 - Virginia Techcourses.cs.vt.edu/~cs2505/spring2020/notes/T18_Cstruct...C structTypes Computer Organization I 2 CS@VT ©2005-2019 McQuain A structExample struct

C struct Types

Computer Organization I

18

CS@VT ©2005-2019 McQuain

Making a Copy

iArray* iArray_Copy(iArray* const pA) {

if ( pA == NULL ) return NULL;

iArray pCpy = calloc(1, sizeof(iArray));

if ( pCpy == NULL ) return NULL;

pCpy->Data = malloc(pA->Dimension * sizeof(int32_t));

if ( pCpy->Data == NULL ) {

free( pCpy );

return NULL;

}

memcpy(pCpy->Data, pA->Data, pA->Usage);

pCpy->Dimension = pA->Dimension;

pCpy->Usage = pA->Usage;

return pCpy;

}

Create new iArray object

Create array field

Copy array elems

Set static fields