0% found this document useful (0 votes)
22 views

COMP2006 Lecture 5 Structs

This lecture covers C-type structs in C++, including defining and accessing struct members using dot notation. It discusses dynamically allocating memory for structs using malloc() and free(), as well as how struct members are positioned sequentially in memory based on their order of definition. The lecture notes that padding may be added between struct members to optimize alignment, but that #pragma pack can be used to pack structs without gaps.

Uploaded by

zombiten3
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views

COMP2006 Lecture 5 Structs

This lecture covers C-type structs in C++, including defining and accessing struct members using dot notation. It discusses dynamically allocating memory for structs using malloc() and free(), as well as how struct members are positioned sequentially in memory based on their order of definition. The lecture notes that padding may be added between struct members to optimize alignment, but that #pragma pack can be used to pack structs without gaps.

Uploaded by

zombiten3
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 38

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

You might also like