Structs (C) - moodlearn.ariel.ac.il · Structs 2 Contiguously-allocated region of memory Refer to...

Post on 31-May-2020

3 views 0 download

Transcript of Structs (C) - moodlearn.ariel.ac.il · Structs 2 Contiguously-allocated region of memory Refer to...

Structs (C)

Structs

2

Contiguously-allocated region of memory

Refer to members within structure by

names

Members may be of different types

Example: struct rec

{

int i;

int a[3];

int *p;

};

Memory Layout

i a p

0 4 16

Struct initialization

3

structs can be initialized in a way similar to arrays:

struct rec { int i; int a[3]; int *p; };

int k;

struct rec r = { 5, { 0,1,2}, &k };

r.i=1;

r.a[0]=5; r.p=&k;

typedef

4

• Synonyms for variable types – make your

program more readable

typdef unsigned int size_t;

typedef in C

5

• No need to write “struct Complex” each

time:

typedef struct Complex

{

double _real, _imag;

} Complex;

Complex addComplex(Complex, Complex);

Complex subComplex(Complex, Complex);

complex.h

C++

6

• No need to write “struct Complex” each time

even if we don’t use a typedef

struct Complex

{

double _real, _imag;

} Complex;

Complex addComplex(Complex, Complex);

Complex subComplex(Complex, Complex);

complex.h

Pointers to structs

7

• You can have a pointer to structures or array or

structs the same way you have pointers to built in

type.

• Pointers to anything can be cast between

themselves, it may be useful sometimes, but

beware…

Structs - Code

8

Offset of each structure member determined

at compile time

struct rec

{

int i;

int a[3];

int *p;

};

i a p

0 4 16

r + 4 + 4*idx

r

int *find_a(struct rec *r, int idx)

{

return &(r->a[idx]);

}

struct

• Sequential in memory, but may have gaps: sizeof(S1) != sizeof(char)+sizeof(double)+sizeof(int)*2

• Member offset determined in compile time

• Access member with "." e.g. a.i[0], a.v.

• Access member of struct pointer contents:

(*p). or p->

struct S1 { char c; int i[2]; double v; } struct S1 a,*p;

v i[0] c i[1]

P+0 P+4 P+16

9

P+24

10

Structs – poor oop

10

Complex.c

struct Complex

{

double _real, _imag;

};

struct Complex addComplex(struct Complex, struct Complex);

complex.h

#include "complex.h"

// implementation

struct Complex addComplex(struct Complex a, struct Complex b)

{

complex.c

#include "complex.h"

int main()

{

struct Complex c;

...

MyProg.c

#ifndef – header safety

11

Complex.h:

struct Complex

{

...

MyStuff.h:

#include "Complex.h"

Main.c:

#include "MyStuff.h"

#include "Complex.h"

Error:

Complex.h:1: redefinition

of `struct Complex'

#ifndef – header safety

12

Complex.h (revised):

#ifndef COMPLEX_H

#define COMPLEX_H

struct Complex

{

...

#endif

Main.c:

#include "MyStuff.h"

#include "Complex.h" // no error this time

#pragma once – header safety

13

Complex.h (revised):

#pragma once

struct Complex

{

...

Main.c:

#include "MyStuff.h"

#include "Complex.h" // no error this time

structs copying

14

Copy structs using ‘=‘:

copy just struct values!!!

Complex a,b;

a._real = 5;

a._imag = 3;

b = a;

_real = 5

_imag = 3

a:

_real = ?

_imag = ?

b:

structs copying

15

Copy structs using ‘=‘:

copy just struct values!!!

Complex a,b;

a._real = 5;

a._imag = 3;

b = a;

_real = 5

_imag = 3

a:

_real = 5

_imag = 3

b:

Arrays in structs copying

16

struct definition:

typedef struct Vec

{

double _arr [MAX_SIZE];

}

Vec;

Vec addVec(Vec, Vec);

...

vec.h

Arrays in structs copying

143

copy struct using ‘=‘:

Vec a,b;

a._arr[0] = 5;

a._arr[1] = 3;

b = a;

_arr =

{5,3,?,…}

a:

_arr =

{?,?,?,…}

b:

Arrays in structs copying

18

Copy struct using ‘=‘:

copy just struct values!!!

Vec a,b;

a._arr[0] = 5;

a._arr[1] = 3;

b = a;

_arr =

{5,3,?,…}

a:

_arr =

{5,3,?,…}

b:

19

Pointers in structs copying

20

struct definition:

typedef struct Vec

{

double _arr [MAX_SIZE];

double * _p_arr;

}

Vec;

Vec addVec(Vec, Vec);

...

vec.h

Pointers in structs copying

21

Copy structs using ‘=‘:

copy just struct values!!!

Vec a,b;

a._arr[0] = 5;

a._arr[1] = 3;

a._p_arr =

a._arr;

b = a;

_arr = {5,3,?,…}

_p_arr = 0x55

a: _arr = {?,?,?,…}

_p_arr = ?

b:

Pointers in structs copying

22

Copy structs using ‘=‘:

copy just struct values!!!

Vec a,b;

a._arr[0] = 5;

a._arr[1] = 3;

a._p_arr =

a._arr;

b = a;

_arr = {5,3,?,…}

_p_arr = 0x55

a: _arr = {?,?,?,…}

_p_arr = 0x55

b:

Pointers copied by value!!!

Pointers in structs copying

23

The result:

Vec a,b;

a._arr[0] = 5;

a._arr[1] = 3;

a._p_arr = a._arr;

b = a;

*(b._p_arr) = 8;

printf ("%f", a._arr[0]);

// output

8

How to copy structs correctly?

24

Implement a clone function:

void cloneVec (Vec *a, Vec *b)

{

int i=0;

for (i=0;I<MAX_SIZE;i++)

{

b->_arr[i] = a->_arr[i];

}

b->_p_arr = b->_arr;

}

Arrays & structs as arguments

25

When an array is passed as an

argument to a function, the address of

the 1st element is passed.

Structs are passed by value, exactly as

the basic types.

Arrays & structs as arguments

26

struct MyStr

{

int _a[10];

};

void f(int a[])

{

a[7] = 89;

}

void g(MyStr s)

{

s._a[7] = 84;

}

main()

{

MyStr x;

x._a[7] = 0;

f(x._a);

printf("%d\n", x._a[7]);

g(x);

printf("%d\n", x._a[7]);

}

Output: 89

89

Access to struct members via pointers

27

struct MyStr

{

int _a[10];

};

main()

{

MyStr x;

MyStr *p_x = &x;

x._a[2] = 3;

(*p_x)._a[3] = 5;

p_x->_a[4] = 6;

}

Classes (C++)

Motivating Example

29

Goal:

1. Graphics package

2. Handle drawing of different shapes

3. Maintain list of shapes

Solution #1

30

struct shape { enum { RECTANGLE, CIRCLE, TRIANGLE } _type; double _x, _y; double _height, _width; }; void Draw( shape const* Shape ) { switch( Shape->type ) { case RECTANGLE: ... case CIRCLE:

...

Solution #1 - Discussion

31

Pros:

Simple, direct

Cons:

Adding new shapes requires changing all

procedures that deal with shape

A lot of "if"/"switch" in runtime

Solution #3 – C++ classes

32

Language provides tools for objects

Ideas similar to Java, but many

differences in details.

(We will not show this solution now, since we need yet to

learn these details…)

Simple Class Declaration

33

#ifndef _COUNTER_H_

#define _COUNTER_H_

class Counter

{

public:

Counter(); // Constructor

void increment(); // A method

int value(); // Another one

private:

int _count;

};

#endif // _COUNTER_H_

Using the class

34

#include "Counter.h"

#include <cstdio>

int main()

{

Counter cnt; // Call to constructor!

printf("Initial value= %d\n", cnt.value());

cnt.increment();

printf("New value = %d\n", cnt.value() );

}

Class Implementation

35

void Counter::increment()

{

_count++;

}

int Counter::value()

{

return _count;

}

Scope operator

Class Implementation

36

Constructor - like a function, but no return

type

Counter::Counter()

{

_count = 0;

}

How do we compile it?

37

g++ -c -Wall Counter.cpp –o Counter.o

g++ -c -Wall app.cpp –o app.o

g++ -Wall Counter.o app.o –o app

Declaration + implementation

38

#ifndef _COUNTER_H_

#define _COUNTER_H_

class Counter

{

public:

Counter(); // Constructor

// A method with inline implementation :

void increment(){ _count++; }

private:

int _count;

};

#endif // _COUNTER_H_

Class Basics: Public/Private

39

Declare which parts of the class are accessible outside the class

class Foo

{

public:

// accessible from outside

private:

// private - not accessible from outside

// (compilation error)

// but visible to user!

};

Class Basics: Public/Private

40

Declare which parts of the class are accessible outside the class

class Foo

{

public:

// accessible from outside

private:

// private - not accessible from outside

// (compilation error)

// but visible to user!

};

Without using “dirty” tricks

Example

41

class MyClass

{

public:

int a();

double _x;

private:

int b();

double _y;

};

int main() { MyClass foo; // legal: foo._x = 1.0; foo.a(); //compile error: foo._y = 2.0; foo.b(); }

Example

42

class MyClass

{

public:

int a();

double _x;

private:

int b();

double _y;

};

int MyClass::a()

{

// legal

_x = 1.0;

// also legal

_y = 2.0;

b();

}

Example - Point

class Point

{

public:

Point(int x, int y);

~Point();

int getX() const;

int getY() const;

private:

int _x, _y;

};

43

Circle

#include "Point.h"

class Circle

{

public:

Circle(int x, int y, double r);

~Circle();

// ...

private:

Point _center;

// ...

};

44

Circle.cpp

#include "Circle.h“

Circle::Circle(int x, int y, double r) :

_center(x,y)

{

// ...

}

Circle::~Circle()

{

printf("in ~Circle()");

}

45

this

The address of the instance for which the member

method was invoked

bool Node::isChild(const Node* other) const

{

for (const Node* curr=this; curr; curr=curr->next)

{

if (curr==other) return true;

}

return false;

}

class Node { Node* next; public: bool isChild(const Node*) const; // ... };

46

structs

47

Where did structs go?

• In C++ class==struct, except that by default

struct members are public and class members are private:

struct MyStruct { int x; };

class MyClass { int x; };

int main() { MyStruct s; s.x = 1; // ok MyClass c; c.x = 1; // error }

struct / class keyword

48

1. No need to typdef the class declaration to avoid

using "struct MyStruct" or "class MyStruct".

2. But, it is legal. (May be useful if you want to use the

same name for a variable and a class which itself is a

bad idea).

int main() {

//All legal:

struct MyStruct s1; class MyClass c1; MyStruct s2; MyClass c2; }

Class Basics - member/static

49

class List { public: static int getMaxSize(); int getSize(); static int max_size=1000; //error! (only outside, below) int size=0; //error! (only in ctor, coming slides) }; int List::max_size=1000 //ok. int main() { List l; l.getSize(); List::getMaxSize(); l.getMaxSize(); }

this

50

static int List::getMaxSize() //no this!

{

return this->size; // compile error!

return max_size; // ok

}

int List::getSize()

{

return this->size; //ok

}

Class Basics: Constructors

51

Initialize the class object upon construction

class MyClass

{

public:

MyClass();

MyClass( int i );

MyClass( double x, double y );

...

};

MyClass a; // Calls 1

MyClass b(5); // Calls 2

MyClass c( 1.0, 0.0 ); // Calls 3

1

2

3

Constructors – implicit default ctor

52

class MyClass

{

public:

MyClass(); // default ctor.

//...

};

//...

int main()

{

MyClass a; // default ctor. is called

// ...

Constructors – implicit default ctor

53

class MyClass

{

public:

...

};

int main()

{

MyClass a; // default ctor. is called

Constructors – implicit default ctor

54

class MyClass

{

public:

MyClass(int x); // no default cons.

};

int main()

{

MyClass a; // complier error –

// no default cons.

Destructors

55

1. Ensure propose “cleanup” when the object

is destructed

2. Use for freeing memory, notifying related

objects, etc.

Class Basics: Destructors

56

#include <cstdlib> class MyClass { public: MyClass(); ~MyClass(); // destructor private: char* _mem; }; MyClass::MyClass() { _mem=(char*)malloc(1000); } MyClass::~MyClass() { free(_mem); }

int main()

{

MyClass a;

if( ... )

{

MyClass b;

}

}

C Interface

57

struct IntList;

typedef struct IntList IntList;

IntList* intListNew();

void intListFree( IntList* List );

void intListPushFront( IntList* List, int x);

void intListPushBack( IntList* List, int x);

int intListPopFront( IntList* List );

int intListPopBack( IntList* List );

int intListIsEmpty( IntList const* List);

typedef void (*funcInt)( int x, void* Data );

void intListMAPCAR( IntList* List,

funcInt Func, void* Data );

C++ Class

58

In header file:

class IntList

{

public:

IntList();

~IntList();

void pushFront(int x);

void pushBack(int x);

int popFront();

int popBack();

bool isEmpty() const;

private:

struct Node

{

int value;

Node *next;

Node *prev;

};

Node* m_start;

Node* m_end;

};

Classes & Memory allocation

59

Consider this C++ code

main()

{

IntList L;

}

What is the difference?

Compare to C style:

main()

{

IntList* L =

(IntList*)malloc

(sizeof(IntList));

free(L)

}

Classes & Memory allocation

60

IntList* L =

(IntList*)malloc(sizeof(IntList));

Does not call constructor!

Internal data members are not initialized

free(L);

Does not call destructor!

Internal data members are not freed

new & delete

61

Special operators:

IntList *L = new IntList;

1. Allocate memory

2. Call constructor

3. Return pointer to the constructed object

delete L;

1. Call destructor

2. Free memory

new

62

Can be used with any type:

int *i = new int;

char **p = new (char *);

• new is a global operator

• new expression invokes the new operator to

allocate memory, and then calls ctor

• Can be overloaded (or replaced)

• By default, failure throws exception. Can be

changed.

• See <new> header

Global operator new (simplified)

63

void *operator new(size_t size)

{

void *p;

if((p = malloc(size)) == 0)

{

throw std::bad_alloc;

}

return p;

}

New & Constructors

64

class MyClass

{

public:

MyClass();

MyClass( int i );

MyClass( double x, double y );

};

MyClass* a;

a = new MyClass; // Calls

a = new MyClass(5); // Calls

a = new MyClass( 1.0, 0.0 ); // Calls

1

2

3

1

2

3

New & arrays

65

To allocate arrays, use

int n = 4;

int *a = new int[10]; // array of 10

//ints

IntList *b = new IntList[n];

// array of n IntLists

Objects in allocated array must have an

argument-less constructor!

Allocate array of objects w/o def. cons.

66

int n = 4; MyClass **arr = new MyClass *[n]; // array of n pointers to MyClass (no

// cons. is invoked)

for (int i=0;i<n;i++) { arr[i] = new MyClass (i); // each pointer points to a MyClass

// object allocated on the heap, and

// the cons. is invoked. }

Delete & array

67

Special operation to delete arrays

int *a = new int[10];

int *b = new int[10];

delete [] a; // proper delete command

delete b; // may work, but may

// cause memory leak!

Free an allocated array of pointers to objects

on the heap

68

int n = 4; for (int i=0;i<n;i++) { delete (arr[i]); // invoked the dest. of each MyClass

// object allocated on the heap, and

// free the memory. } delete [] arr; // free the memory allocated for the

// array of pointers. No dest. is invoked