structs (c) - moodlearn.ariel.ac.il · structs 2 contiguously-allocated region of memory refer to...
TRANSCRIPT
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