Lesson 4 struct and memory managementchengchc/NCTU_PrePHD/2013_Fall/ICP_04... · Lesson 4 struct...

Preview:

Citation preview

Lesson 4 struct and memory management

Introduction to Computer and Program Design

James C.C. Cheng Department of Computer Science

National Chiao Tung University

2

enum l  Enumerators

u  Grouping the constant integers

enum LEVEL{ LV_EASY, LV_MID, LV_HARD, LV_GOD };

enum LEVEL lv; // In C++, the keyword enum is not neccesary

lv = LV_EASY; cout << lv << endl; // 0 lv = LV_GOD; cout << lv << endl; // 3 lv = LEVEL::LV_HARD; cout << lv << endl; // 2 lv = 1; // Error lv = (LEVEL)1; // lv = LEVEL::LV_MID; cout << lv << endl; // 1 enum LEVEL lv2 = LV_GOD; // The follwing statements cause compiler errors in C++ lv+=1; ++lv; lv = lv + LV_MID; lv = lv + lv2;

Don’t forget the semicolon

3

enum l  Enumerators

enum LEVEL{ LV_EASY = 2, LV_MID, LV_HARD = 10, LV_GOD, LV_NORMAL = 0, LV_ULTIMATE };

enum LEVEL lv = LV_MID; printf("%d\n", lv); // 3 lv = LV_GOD; printf("%d\n", lv); // 11 lv = LV_ULTIMATE; printf("%d\n", lv); // 1

Struct l  Consider a situation as follows:

4

float BMI(float w_kg, float h_m){ return (w_kg / (h_m * h_m); } … #define MAX_N 3 char* name [MAX_N][8] = {0}; float w [MAX_N] = {0.0f}, float h [MAX_N] = {0.0f}; int n = 0, i=0; do{ // Input the personal information printf("Name:");scanf("%s", &name[n]); if(name[n][0]>0){ printf("Weight(Kg):"); scanf("%f", &w[n]); printf("Height(m):"); scanf("%f", &h[n]); getchar(); ++n; } else break; }while(n < MAX_N); // Showing the personal information and calculating the BMI for(i=0; i<n; ++i) printf("[%d]Name:%s, w:%f, h:%f, BMI:%f\n", i, name[i], w[i], h[i], BMI(w[i], h[i]));

We have to use three independent data array to record the

personal information

5

Struct l  The struct can help us to group many data items to descript a complicated object

struct Person A[MAX_N]; // In C++, the keyword struct is not neccesary do{ // Input the personal information memset(A[n].name, 0, 8); // Clear the string printf("Name:");scanf("%s", A[n].name); if(A[n].name[0]>0){ printf("Weight(Kg):"); scanf("%f", &A[n].w); printf("Height(m):"); scanf("%f", &A[n].h); getchar();++n; } else break; }while(n < MAX_N); // Showing the personal information and calculating the BMI for(i=0; i<n; ++i) printf("[%d]Name:%s, w:%f, h:%f, BMI:%f\n", i, A[i].name, A[i].w, A[i].h, BMI(A[i].w, A[i].h));

struct Person{ char name[8]; float w, h; };

6

Struct l  Member selection operator

u  x.m ¡  x is an object of a data type T

¡  m is a name of a member of T

u  p->m

¡  p is a pointer

¡  m is a name of a member of T

struct Person x; // In C++, the keyword struct is not neccesary sprintf(x.name, "James"); x.w = 65.0f; x.h = 1.785f; // Using ‘.’ operator to access each member struct Person* px = &x; // In C++, the keyword struct is not neccesary printf("Name:%s, w:%f, h:%f, BMI:%f\n", px->name, px->w, px->h, BMI(px->w, x->h));

// Using ‘->’ operator to access each member

7

Struct l  If you want to pass an argument of a struct, you should pass its address or

reference

u  DO NOT use call-by-value to pass a struct to a function! void SetPerson(struct Person* px, const char *name, float w, float h){ sprintf(px->name, "%s", name); px->w = w; px->h = h; } void SetPerson(struct Person x, const char *name, float w, float h){ sprintf(x.name, "%s", name); x.w = w; x.h = h; } void PrintPerson(const struct Person* px){ printf("Name:%s, w:%f, h:%f, BMI:%f\n", px->name, px->w, px->h, BMI(px->w, px->h)); } … SetPerson(&x, "Bill", 90.0f, 2.0f); PrintPerson(&x);

8

Struct l  Word alignment

u  How many byte does a struct occupy?

struct Point3D{ int x, y, z; }; printf("%d\n", sizeof(struct Point3D)); // 12 Byte

struct EmptyBox{ }; printf("%d\n", sizeof(struct EmptyBox)); // 0 byte in C, but 1 byte in C++

struct Person{ char name[8]; float w, h; }; printf("%d\n", sizeof(struct Person)); // 16= 8+ 4 + 4

9

Struct l  Word alignment

struct Person{ char gender; // ‘M’: Male; ‘F’: Female char name[8]; float w, h; }; printf("%d\n", sizeof(struct Person)); // Is the answer 17?

struct Person{ char gender; // ‘M’: Male; ‘F’: Female char name[8]; float w, h; short age; }; printf("%d\n", sizeof(struct Person)); // Is the answer 19?

struct Person{ char gender; // ‘M’: Male; ‘F’: Female char name[8]; short age; float w, h; }; printf("%d\n", sizeof(struct Person)); // Is the answer 19?

10

Struct l  Word alignment

u  Word: ¡  The unit of memory accessing

¡  4 byte in 32-bit systems; 8 byte in 64-bit systems

u  Alignment: ¡  For efficient memory accessing, some “holes” are added in a struct to satisfy the

memory addressing.

struct Person{ char gender; char name[8]; float w, h; short age; };

address Data

Word 1

Word 2

Word 3

Word 4

Word 5

Word 6

Holes

11

Struct l  Word alignment

u  How to disable word alignment? ¡  Using the #prgma pack

#pragma pack(push, 1) // change to 1 byte alignment and store the original setting struct Person{ … }; #pragma pack(pop) // restore the original setting printf("%d\n", sizeof(struct Person)); // 19 byte

struct Person{ char gender; char name[8]; float w, h; short age; };

address Data

Word 1

Word 2

Word 3

Word 4

Word 5

12

Struct l  Bit filed

u  We can access each bit of member variable in a struct ¡  The member variables must be integers

struct Port{ unsigned short data:8; unsigned short address:4; unsigned short flagA:1; unsigned short flagB:1; unsigned short flagC:1; unsigned short flagD:1; }; // | A | B | C | D | Addr(4 bit) | Data (8 bit) |

struct Port io; unsigned short *pn = (unsigned short *)&io; *pn = 0; // Initialization io.data = 0xFF; io.flagD = 1; printf("%d\n", *pn); // 33023 = 32768 + 255 = 0x8000 + 0x00FF

Struct l  Struct assignment

u  The datatype of l-value & r-value must be the same

u  The struct should contain no any dynamic-size member

13

Person x1, x2; sprintf(x1.name, "James"); x1.w = 65.0f; x1.h = 1.785f; x2 = x1; x2.w = 80.0f; PrintPerson(&x1); // James, 65.0, 1.785 PrintPerson(&x2); // James, 80.0, 1.785

Struct l  Dynamic-size member

14

struct Person{ char* name; float w, h; };

void InPerson(struct Person* px){ char buf[256] = {0}; if(px->name) free(px->name); // Release data px->name = NULL; printf("Name:"); scanf("%s", buf); if(buf[0] > 0){ px->name = (char *)calloc(1, strlen(buf)+1 ); sprintf(px->name, "%s", buf); printf("Weight(Kg):"); scanf("%f", &px->w); printf("Height(m):"); scanf("%f", &px->h); getchar(); } }

struct Person A[MAX_N]; memset(A, 0, sizeof(struct Person) * MAX_N); // Clear all data do{ // Input the personal information InPerson(&A[n]); if(A[n].name) ++n; else break; }while(n < MAX_N); // Showing the personal information and calculating the BMI for(i=0; i<n; ++i) PrintPerson(&A[i]);

Struct l  Dynamic-size member

u  We need to design a function to copy a Person

u  What if we copy a Person by the assignment operator?

15

void CopyPerson(struct Person* px1, const struct Person* px2){ if(px1->name) free(px1->name); px1->name = NULL; if(px2->name ){ px1->name = (char *)calloc(1, strlen( px2->name ) + 1 ); sprintf(px1->name, "%s", px2->name ); px1->w = px2->w; px1->h = px2->h; } }

Person x1, x2 InPerson(&x1); x2 = x1; x1.name[0] = ‘X’; PrintPerson(&x1); PrintPerson(&x2); // ?

16

Struct l  Initialization

u  Initializer list

u  Uniform initialization ¡  C++11 and GCC ¡  Visual C++ 2010, 2012 not support

struct Student{! char name[8];! float w, h;!};!

Student x = {0}; !Student y = {"James", 75.2f, 175.6f};! // Notice the order !

Student x{0}; !Student y{"James", 75.2f, 175.6f}; ! // Notice the order !

17

Union l  A union object can contain only one of its members at a time. l  The size of the union is at least the size of the largest member.

union NewInt{ int nValue; unsigned char btValue[4]; };

NewInt x; x.nValue = 256; printf("%X, %X, %X, %X\n", x.btValue[0], x.btValue[1], x.btValue[2], x.btValue[3]); // 0, 1, 0, 0 printf("%d\n", sizeof(x)); // 4 byte

18

Union l  It usually combines union and struct in most cases

union Vector3D{ double data[3]; struct{double x, y, z;}; struct{double r, g, b;}; struct{double u, v, w;}; };

printf(“%d\n”, sizeof(union Vector3D)); // 24 byte union Vector3D vec; vec.x = 0; vec.y = 10, vec.b = 30; printf(“%f, %f, %f\n”, vec.u, vec.v, vec.w); for(i=0;i<3; ++i) printf(“%f, ”, vec.data[i]);

Dynamic memory allocation� l  malloc

u  Syntax: #include <stdlib.h>

void* malloc( size_t n );

¡  where the size_t is the same as unsigned int

¡  malloc() returns a pointer to a chunk of memory of n bytes, or NULL if there is an error. The memory pointed to will be on the heap, not the stack, so make sure to free it when you are done with it.

¡  The returned pointer must be typecast

l  free u  Syntax: #include <stdlib.h>

void free( void* ptr );

¡  free() deallocates the space pointed to by ptr, freeing it up for future use. ¡  ptr must be NULL or used in a previous call to malloc(), otherwise a runtime

error will occur on free().

19

Dynamic memory allocation� l  calloc

u  Syntax: #include <stdlib.h>

void* calloc (size_t unit, size_t n );

¡  calloc() returns a pointer to a chunk of memory of unit * n bytes with elements initialized t zero, or NULL if there is an error.

¡  The returned pointer must be typecast

20

Dynamic memory allocation� l  Example:

l  free a NULL pointer

21

char *pc = (char *)malloc(10); // 10 characters int *pi = (int *)malloc(sizeof(int) * 10); // 10 integers double *pd = (double *)malloc(80); // 10 doubles if( pc != NULL && pi != NULL && pd != NULL){ // Check the allocation for(int i=0; i<10; ++i) pd[i] = pi[i] = pc[i] = i + 65; for(int i=0; i<10; ++i) printf("%c, %d, %f\n", pc[i], pi[i], pd[i]); // A~J } free(pc); free(pi); free(pd);

int *p; // Non-NULL free(p); // Runtime error! p = NULL; free(p); // OK!

Dynamic memory allocation�

22

int n = 1024 * 1024 * 128; // 128 MB double rTime; clock_t clk0, clk1; char *pc = (char *)malloc(n); // clk0 = clock(); for(int i=0; i<n; ++i) pc[i] = 0; clk1 = clock(); rTime = (double)(clk1 - clk0) / (double)CLOCKS_PER_SEC; printf("iterative clearing time: %f\n", rTime);

// The time is proportional to n free(pc); clk0 = clock(); pc = (char *)calloc(1,n); // re-allocating with initialization clk1 = clock(); rTime = (double)(clk1 - clk0) / (double)CLOCKS_PER_SEC; printf("calloc time: %f\n", rTime);

// it's constant time if the hardware supports calloc free(pc);

Dynamic memory allocation� l  Memory leaks and dangling

23

Pointer� Memory�

Normal allocation

Pointer� Memory�

Memory leaks

Pointer� Memory�

Memory dangling

Dynamic memory allocation� l  Memory Leaks

u  There is no any pointer to point a allocated memory space ¡  Executing the system monitor to watch the memory usage ¡  Using two threads to execute the following program

¡  If the memory usage approach to the limitation, just stop the program

24

char key = 0, end = 0; do{ // Create 64M byte for input buffer int n = 1024 * 1024 * 64; char *pc =(char *)malloc(n); memset(pc, 0, n); // Clear all data scanf("%s", pc); key = pc[0]; end = pc[1]; }while(key != 'q' && key !='Q' || end != 0);

If the OS does not provide “Garbage Collection”, the allocated memory will never be released. Notice that the timing for releasing by garbage collection is when the program has been terminated.

Dynamic memory allocation� l  Memory Dangling

u  A pointer points an unallocated memory space

25

char *pc; *pc = 100; // Dangling pc = (char *)malloc(12); int *pi = (int *)pc; free(pi); *pc = 50; // Dangling

Dynamic memory allocation� l  Memory Manipulation Functions

u  memset, memory setting:

#include <memory.h> or #include <string.h>

void* memset( void *dest, int c, size_t count );

Ø  dest: the destination pointer

Ø  c: set the value, c & 0xFF, to each byte of dest

Ø  count: the number of byte to set

Ø  returns the value of dest

26

int n = 3; int *p = (int *)malloc(sizeof(int)*n); memset(p, 0, sizeof(int)*n); for(int i=0; i<n; ++i) printf("%d, 0x%0X\n", p[i], p[i]); memset(p, 255, sizeof(int)*n); for(int i=0; i<n; ++i) printf("%d, 0x%0X\n", p[i], p[i]); memset(p, 65537, sizeof(int)*n); for(int i=0; i<n; ++i) printf("%d, 0x%0X\n", p[i], p[i]); memset((int *)memset(p, 0, 12) + 1, 255, 4) ; for(int i=0; i<n; ++i) printf("%d, 0x%0X\n", p[i], p[i]);

Dynamic memory allocation� l  Memory Manipulation Functions

u  The needed time of memset

27

int n = 1024 * 1024 * 128; // 128 MB double rTime; clock_t clk0, clk1; char *pc = (char *)malloc(n); clk0 = clock(); for(int i=0; i<n; ++i) pc[i] = 0; clk1 = clock(); rTime = (double)(clk1 - clk0) / (double)CLOCKS_PER_SEC; printf("iterative clearing time: %f\n", rTime);

// The needed time is proportional to n clk0 = clock(); memset(pc, 0, n); clk1 = clock(); rTime = (double)(clk1 - clk0) / (double)CLOCKS_PER_SEC; printf("memset time: %f\n", rTime); /* The needed time is still proportional to n but less than iterative method */ free(pc);

Dynamic memory allocation� l  Memory Manipulation Functions

u  memcpy, memory copy:

#include <memory.h> or #include <string.h>

void* memcpy(void *dest, const void *src, size_t count );

u  dest: the destination pointer

u  src: the source pointer

u  count: the number of byte to copy

u  returns the value of dest

u  If the source and destination overlap, this function does not ensure that the original source bytes in the overlapping region are copied before being overwritten.

28

char s1[] = "Hello! My friend!"; // Why use char[]? const char *s2 = "Hi! Guys."; // Why use const char*? memcpy(s1+7, s2+4, 6); printf("%s\n", s1); // Hello! Guys. memcpy(s1+5, s1+7, 4); printf("%s\n", s1); // Maybe “HelloGuysys.”, maybe not

Dynamic memory allocation� l  Memory Manipulation Functions

u  memmove, memory move:

#include <string.h>

void *memmove( void *dest, const void *src, size_t count );

u  dest: the destination pointer

u  src: the source pointer

u  count: the number of byte to move

u  returns the value of dest u  It is similar to memcpy, but memmove ensures the copy of overlapping region.

29

char s1[] = “0123456789"; memcpy(s1 + 2, s1, 5); printf("%s\n", s1); // 0101234789

Dynamic memory allocation� l  Memory Manipulation Functions

u  memcmp, memory compare:

#include <memory.h> or #include <string.h>

int memcmp( const void *buf1, const void *buf2, size_t n );

Ø  buf1 and buf2: the pointers of memory

Ø  n: the number of byte to compare

Ø Return Value: relationship of first n bytes of buf1 and buf2

< 0: buf1 less than buf2 0: buf1 identical to buf2

> 0: buf1 greater than buf2

30

char first[] = "12345678901234567890"; char second[] = "12345678901234567895"; printf(“%d\n”, memcmp( first, second, 19 ) ); // 0 printf(“%d\n”, memcmp( first, second, 20 ) ); // -1 printf(“%d\n”, memcmp( first + 2, second, 18 ) ); // 1

Dynamic memory allocation� l  Dynamic multi-dimension array

31

int m=0, n=0,i ,j; scanf("%d %d", &m, &n); int **pp = (int **)malloc(sizeof(int *) * m); for(i=0; i<m; ++i) pp[i] = (int *)malloc(sizeof(int) * n); for(i=0; i<m; ++i) for(j=0; j<n; ++j) pp[i][j] = i * 10 + j; for(i=0; i<m; ++i){ for(j=0; j<n; ++j) printf("%2d, ", pp[i][j]); printf("\n"); } /* Do not forget to free the allocated memory in reverse order of dimension */ for(i=0; i<m; ++i) free(pp[i]); free(pp);

l  Linked List

u  It consists of a sequence of data items such that in each item there is a pointer or a reference to link the next item.

u  The memory addresses of elements may not be adjacent

struct Node{ int data; Node *next; }; Node* NewNode(int data){ Node *p = (Node *)calloc(sizeof(Node), 1); p->data = data; return p; } … Node *pHead = NewNode(0), *p = pHead; for( int i=1; i<5; ++i, p = p->next) p->next = NewNode(i); // Creating the list p = pHead; while(p != NULL) { printf("%d\n", p->data); Node *pTmp = p; p = p->next; free(pTmp); // Release each item }

Linked Lists�

32

data� next�

0� 1� 2� 3� 4�

Linked Lists� l  Doubly-Linked List

u  Each node has two pointers, one points the next node and the other points the previous node.�

33 0� 1� 2� 3�

struct Node{ int data; Node *next, *prev;}; Node* NewNode(int data){ Node *p = (Node *)calloc(sizeof(Node), 1); p->data = data; return p; } … Node *pHead = NewNode(0); Node *p = pHead; for( int i=1; i<5; ++i, p = p->next){ p->next = NewNode(i); p->next->prev = p; }

while(p != NULL) { printf("%d\n", p->data); Node *pTmp = p; p = p->prev; } p = pHead; while(p != NULL) { printf("%d\n", p->data); Node *pTmp = p; p = p->next; free(pTmp); // Release }

Arrays vs. Linked Lists� l  Performances

u  Random access ¡  Array: O(1) ¡  Doubly-Linked list: O(n)

u  Random insertion ¡  Array: O(n) ¡  Doubly-Linked list:

Search time + O(1)

u  Random remove ¡  Array: O(n) ¡  Doubly-Linked list:

Search time + O(1)

34

u  Push back ¡  Dynamic Array: O(1)

¡  Doubly-Linked list: O(1)

u  Pop back ¡  Dynamic Array: O(1)

¡  Doubly-Linked list: O(1)

u  Push front ¡  Dynamic Array: O(n)

¡  Doubly-Linked list: O(1)

u  Pop front ¡  Dynamic Array: O(n)

¡  Doubly-Linked list: O(1)�

where n is the number of data elements

Arrays vs. Linked Lists� l  Performances

u  Resize (from n to m) ¡  Array: O(m) ¡  Doubly-Linked list: O(m)

u  Clear ¡  Array: O(n) ¡  Doubly-Linked list: O(n)

u  Concatenation ¡  Array: O(n) ¡  Doubly-Linked list: O(1)

u  Swap ¡  Array: O(n) ¡  Doubly-Linked list: O(1)�

35

m

n u  Copy assignment

¡  Array: O(n)

¡  Doubly-Linked list: O(n)

=

Recommended