lesson 4 struct and memory managementchengchc/nctu_prephd/2013_fall/icp_04... · lesson 4 struct...
TRANSCRIPT
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)
=