COMP2006
C++ Programming
Lecture 5
Dr Chao Chen
1
This lecture
• C-type structs
– C++ builds on these and adds features
– Accessing operators (. and ->)
• Dynamic memory allocation
• Memory re-allocation to grow arrays
2
structs
A brief review and reference
3
structs
• We will start with C-type structs
– C++ structs and classes can be considered to be extensions of C
structs, e.g. allowing member functions, inheritance etc
– structs and classes are virtually the same thing in C++
• The only difference is default public or default private
• Examples:
– Group three integers together to specify a time:
struct Time
{
int hour;
int minute;
int second; Note the ; at the end!
};
– Shorter version, for day, month, year:
struct Date { int d, m, y };
4
Accessing members of a struct
Creates a
• Example: struct on
struct Date { int d, m, y; }; the stack
int main( int argc, char* argv[] ) No malloc(),
no ‘new’
{ operator is
struct Date dob = { 1, 4, 1990 }; used!!!
printf( “DOB: %02d/%02d/%04d\n”,
dob.d, dob.m, dob.y );
dob.d = 2;
return 0;
}
5
Accessing members of a struct
• Use the . operator to access members
– Exactly as for Java classes
• Example:
struct Date { int d, m, y; };
int main( int argc, char* argv[] )
{
struct Date dob = { 1, 4, 1990 };
printf( “DOB: %02d/%02d/%04d\n”,
dob.d, dob.m, dob.y );
dob.d = 2; Initialisation
return 0; Like an array
} Access values 6
structs act like any other type
Once defined, you can use structs:
• You can take the address of a variable of type struct
and store it in a struct pointer, e.g.
struct Date* pDob = &dob;
– C++ does not need this ‘struct’ keyword (but necessary in C,
unless typedef)
• You can embed a struct as a member of another
struct
• You can create an array of structs
• You can ask for the sizeof() a struct
7
Array of structs (on the stack)
Date arrayOfDatesOnStack[5];
Array of 5 elements
for ( i=0 ; i < 5 ; i++ )
printf( "arrayOfDatesOnStack[%d] is : %02d/%02d/%04d\n",
i,
arrayOfDatesOnStack[i].d,
arrayOfDatesOnStack[i].m,
arrayOfDatesOnStack[i].y );
arrayOfDatesOnStack[0] is : 00/00/0000
arrayOfDatesOnStack[1] is : 02/00/0000
arrayOfDatesOnStack[2] is : -104/-51/0034
arrayOfDatesOnStack[3] is : -41/53/24833
arrayOfDatesOnStack[4] is : -71/-74/24854
Values are uninitialised!!! 8
Array of dates (on the stack)
/* Uses array initialiser and struct initialiser */
Date initArrayOfDatesOnStack[] = {
{1,1,2001}, {2,2,2002}, {3,3,2003},
{4,4,2004}, {5,5,2005} };
for ( i=0 ; i < 5 ; i++ )
printf( "initialisedArray[%d] is : %02d/%02d/%04d\n",
i,
initArrayOfDatesOnStack[i].d,
initArrayOfDatesOnStack[i].m,
initArrayOfDatesOnStack[i].y );
initalisedArrayOfDatesOnStack[0] is : 01/01/2001
initalisedArrayOfDatesOnStack[1] is : 02/02/2002
initialisedArrayOfDatesOnStack[2] is : 03/03/2003
initialisedArrayOfDatesOnStack[3] is : 04/04/2004
9
initialisedArrayOfDatesOnStack[4] is : 05/05/2005
Passing structs into functions
struct Date dob = {1, 4, 1990};
• Either pass the struct into a function
foo( dob );
– A (bit-wise) copy of the struct is put on the stack
• You can change this, using C++ copy constructor – see later
– Any changes made inside the function affect the copy
void foo(struct Date dob)
{
dob.m = 3;
} Use . to access struct members
10
Passing a pointer to a struct
struct Date dob = {1, 4, 1990};
• Or a pointer to the struct
bar( &dob );
– A copy of the pointer is put on the stack
– You can use the pointer to access the original struct
void bar(struct Date* pdob)
{
(*pdob).m =3;
} For a pointer you could use (*pdob).m
void bar(struct Date* pdob)
{
pdob->m =3;
} X->Y equivalent to (*X).Y 11
Dynamic Memory Allocation
from the heap
12
The heap and malloc()
I need this many
• Avoid waste of memory bytes of memory:
malloc( size )
• You can ask for memory when HEAP
needed using malloc(),
Use this address:
calloc(), realloc() <Address>
I no longer need
• free() when no longer this memory
free( address )
needed
HEAP
13
5 steps to dynamic memory bliss
Step 1: Work out how much memory you need to allocate
– Remember the sizeof() operator!
Step 2: Ask for that amount of memory
– Use malloc( memory_size )
Step 3: Store the returned pointer e.g. :
int* pInt = (int*)malloc( sizeof(int) );
Note: C++ needs the cast, C does not
Step 4: Use the memory through the pointer, as if it was
the correct type
*pInt = 5; (*pInt)++; *pInt += 12;
Step 5: When finished, free the memory
free( pInt );
14
malloc, calloc and realloc
• All of these functions return NULL on failure
void* malloc(size_t sz);
• Allocate sz bytes of uninitialised memory
void* calloc(size_t count, size_t sz);
• Allocate memory for count elements of size sz each
• The memory is initialised to zeroes!!!
void* realloc(void *old_pointer, size_t sz);
• old_pointer is a pointer from an existing malloc()
• If possible, grow or shrink the existing memory allocation
to be size sz bytes
• If not, then allocate new memory for the new size (sz
bytes), copy the bytes of the existing memory to the new
address and free the old memory
• If it fails (returns NULL) the old memory will be unchanged
15
Creating a simple array
int* pInt = (int*)malloc( sizeof(int) );
*pInt = 5;
(*pInt)++; Stack: Heap:
*pInt += 12; pInt int
free( pInt );
parray int
int iSize = 6;
int
int* parray = (int*)malloc(
iSize * sizeof(int) ); int
*parray = 3; /* Index 0 */ int
parray[5] = 5; int
free( parray ); int
16
Positioning of struct elements
17
Positions in memory
Like arrays, the positions of the members inside a
Time first struct are known
time Elements will be placed sequentially in memory, in
the order they are defined in the structure
day
Address Size
month dt 0x7fffaab18180 8
year dt.time 0x7fffaab18180 4
dt.day 0x7fffaab18184 1
dt.month 0x7fffaab18185 1
dt.year 0x7fffaab18186 2
18
Gaps when day is first
Day first
day 0x7fff69becaf0
time 0x7fff69becaf4
Size of structure: 12
month 0x7fff69becaf8
year 0x7fff69becafa
19
May have gaps at the end…
Month last
day 0x7fff69becaf0
time 0x7fff69becaf4
Size of structure: 12
year 0x7fff69becaf8
month 0x7fff69becafa
20
#pragma
• structs may get empty space in them
• To align members for maximum speed
• You can usually tell compiler to pack structs,
ignoring speed
– e.g. with gcc can use the command:
#pragma pack(1)
• #pragma means a compiler/operating system
specific pre-processor directive
21
Tell it to pack on 1 byte boundaries
#pragma pack(1)
day
time
Address Size
month
dt 0x7fff7e004280 8 year
dt.day 0x7fff7e004280 4
dt.time 0x7fff7e004281 1
dt.month 0x7fff7e004285 1
dt.year 0x7fff7e004286 2
22
Positions in memory
Time first Day first #pragma pack(1)
time day day
time
day time
month month
year year
month
year
23
Structs and component positions
struct DateTime printf(
{ "Address of dt = %p, size %d\n",
int time; &dt, sizeof(dt) );
char day;
char month; printf(
short year; "Address of dt.time = %p, size %d\n",
}; &(dt.time), sizeof(dt.time) );
printf(
"Address of dt.day = %p, size %d\n",
int main( int argc, &(dt.day), sizeof(dt.day) );
char* argv[] )
{ printf(
DateTime dt = { "Address of dt.month = %p,size %d\n",
80000, &(dt.month), sizeof(dt.month));
01,
04, printf(
1990 }; "Address of dt.year = %p, size %d\n",
&(dt.year), sizeof(dt.year) );
24
unions
Treating something as
“one thing OR another”
Very rarely used compared with structs
usually for low-level (e.g. o/s) code
25
Unions
• unions are very similar to structs except
that the data members are in the same place
• In structs data members are one after
another in memory (possibly with gaps)
• In unions data members all have the same
address
• i.e. data is of one type OR another, not both
26
Unions
• Elements of unions are in the SAME place
• Elements of unions may be different sizes
– A union is as big as the biggest thing in it (plus
any packing)
• Unions are a way of providing different ways of looking
at the same memory Addr: ul ar
1000 [0]
union charorlong
1001 ul [1]
{
Size 4? 1002 [2]
unsigned long ul; 1003 [3]
char ar[8]; Size 8 1004 [4]
}; 1005 [5]
1006 [6]
27
1007 [7]
Predict the sizes
28
Sizes of unions and structs
• Be aware of packing issues
If there is no excess space for packing:
• sizeof(struct) is total of the size of the
members (i.e. sum of member sizes)
– Members are one after another in memory
• sizeof(union) is size of the largest
member (i.e. maximum of member sizes)
– All members are in the same place
– Largest member determines size
29
#pragma pack(1)
#include <cstdio>
struct A { int i; char c; }; Example:
union B { int i; char c; }; char : 1
int : 4
#pragma pack(1) struct A : ?
struct C { int i; char c; }; union B : ?
union D { int i; char c; }; struct C : ?
union D : ?
int main( int argc, char** argv )
{
printf( "sizeof(char): %d\n", sizeof(char) );
printf( "sizeof(int): %d\n", sizeof(int) );
printf( "sizeof(struct A): %d\n", sizeof(struct A) );
printf( "sizeof(union B): %d\n", sizeof(union B) );
printf( "sizeof(struct C): %d\n", sizeof(struct C) );
printf( "sizeof(union D): %d\n", sizeof(union D) );
return 0;
}
30
#pragma pack(1)
#include <cstdio>
struct A { int i; char c; }; Example:
union B { int i; char c; }; char : 1
int : 4
#pragma pack(1) struct A : 8
struct C { int i; char c; }; union B : 4
union D { int i; char c; }; struct C : 5
union D : 4
int main( int argc, char** argv )
{
printf( "sizeof(char): %d\n", sizeof(char) );
printf( "sizeof(int): %d\n", sizeof(int) );
printf( "sizeof(struct A): %d\n", sizeof(A) );
printf( "sizeof(union B): %d\n", sizeof(B) );
printf( "sizeof(struct C): %d\n", sizeof(C) );
printf( "sizeof(union D): %d\n", sizeof(D) );
return 0;
}
31
C++ only things
NOT C!
32
C++ classes and structs
• Can still use structs in C++
• Everything for structs so far applies to both C and C++
– We will call them C-style structs or POD structs (Plain Old Data)
• If you use only C features:
– structs in C++ work as for C, i.e. you can predict sizeof(),
can malloc() space for them, etc
– Everything we have seen so far is valid for C++ POD structs
• C++ structs can also act as full classes though
– The only difference between a struct and class in C++ is default
access
– Structs default to public access, so you don’t need to say ‘public’
– Classes default to private access – methods and data is hidden
unless you say otherwise
– For the moment we will continue to use structs, to avoid issues 33
of
access privileges
C++ classes and structs
• For the moment we will use your Java knowledge and I
will tell you:
– You can add member functions to structs/classes
– You can add constructors – called when objects are created
– You can use new to create objects of a class
– You can pass parameters to a constructor
– You can have multiple different constructors
– You can also use inheritance with structs, defaults to public
• Unlike Java:
– You can also add destructors to objects
• Called automatically when object is destroyed
• Equivalent of calling constructor automatically when object is created
– You need to manually destroy heap objects
– Objects on the stack will be destroyed properly when the function
ends – including calling destructor.
– Will see later, you can write code to destroy objects on the stack
automatically when the last (smart) pointer to them is destroyed34
Example : new and delete
struct MyStruct
{
Create a new object
public:
of type MyStruct
int ai[4];
on the heap
short j;
};
Really creates the
int main()
object, e.g. calls the
{ constructor
MyStruct* pOb = new MyStruct;
MyStruct * pObArray = new MyStruct[4];
pOb->ai[2] = 3;
pObArray[3].j = 5; Uses default constructor
pObArray[1].ai[3] = 5; for each object in array
delete pOb;
delete [] pObArray; delete [] to match new []
return 0; 35
}
new vs malloc
MyClass* pOb = new MyClass;
• new knows how big the object is
– No call to sizeof() is needed (unlike malloc())
• new creates an object (and returns a pointer)
– Allocates memory (probably in same way as malloc())
• new knows how to create the object in memory
– C++ objects can consist of more than the visible data members
(an example later, with hidden vtable ptrs)
• new calls the constructor (malloc() will not!)
• new throws an exception (bad_alloc) if it fails
– By default, unless you tell it not to (e.g. new(nothrow) int)
– Some older compilers may return NULL – but new ones should
not (malloc() returns NULL on failure)
– Ignore this for the moment! 36
delete, new[] and delete[]
• delete destroys an object
– More about this later
MyClass* pOb = new MyClass;
delete pOb;
• new and delete have a [] version for
creating and destroying arrays
– Default constructor is called for the elements
• You MUST match together:
new and delete
new [] and delete []
malloc() and free() 37
Next lecture
• Using some standard C++
classes
string
cin, cout
vector, list
etc (enough for CW part 2)
38