You are on page 1of 61

POINTER

PROGRAMMING TECHNIQUES
ADVISOR: Trương Toàn Thịnh

1
CONTENTS
Heap & stack
Memory support functions
Memory manipulation functions
Allocate & use dynamic array
Pointer-checking techniques
Exercise

2
HEAP & STACK
The stack is allocated for each function when
they are called
Stack contains the parameters (input / output)
and local variables
When function is finished, the memory of
stack is returned to OS
Terminology ‘stack’ implies it operates with
‘last in – first out’ rule
The heap is global (does not depend on caller)
Must explicitly free the memory of heap
3
HEAP & STACK
Memory model of C/C++ program
Information of function caller STACK High address

Unallocated memory

Data dynamically allocated HEAP

Better Save
Uninitizlied global/static variables
Space
Initizlied global/static variables Global / static

Code data Code Low address


4
MEMORY SUPPORT FUNCTIONS
 Functions work with the memory heap
 Need to declare “#include <malloc.h>”
 constant NULL (zero) in
“<stdio.h>”
 void* malloc(int nSz)
◦ Allocate the memory with nSz bytes
◦ Return the address of this memory
 Example of malloc:
◦ int* a = (int*)malloc(3*sizeof(int));
◦ for(int i = 0; i < 3; i++){*(a + i) = i;}
◦ for(int i = 0; i < 3; i++){cout << *(a + i);}
◦ free((int*)a)
5
MEMORY SUPPORT FUNCTIONS
 Functions work with the memory heap
 void* realloc(void* p, int nSz)
◦ Re-allocate the old memory with new nSz bytes
◦ Returning the address of old memory or new memory depends
on the compiler’s optimization
 Example of realloc:
◦ int* a = (int*)malloc(3*sizeof(int));
◦ cout << hex << a << endl;
◦ for(int i = 0; i < 3; i++){*(a + i) = i;}
◦ for(int i = 0; i < 3; i++){cout << *(a + i) << endl;}
◦ realloc(a, 4);
◦ cout << hex << a << endl;
◦ for(int i = 0; i < 4; i++){cout << *(a + i) << endl;}
◦ free((int*)a)
6
MEMORY SUPPORT FUNCTIONS
 Functions work with the memory stack
 Can allocate in the memory stack
 Not allowing to free after using
 Data in this memory are automatically destroyed when
finishing calling function
 void* _alloca(int nSz): similar to malloc, but allocated in
stack STACK
 Example: <20>
<10>
◦ int* a = (int*)_alloca(8); 5
<20>
◦ *a = 5; <24>

◦ *(a+1) = 10; 10

◦ cout << *a << endl;


◦ cout << *(a+1) << endl;
7
MEMORY SUPPORT FUNCTIONS
 Functions work with the memory stack
 void* _expand(void* p, int nSz): similar to realloc, but only supported
in C++
 If you want to know a number of bytes allocated, we can use some
functions
◦ int _msize(void* p): return a number of bytes p manages, only used in Windows
◦ int malloc_size(void* p): similarly but used in Mac OS
◦ int malloc_usable_size(void* p): similarly but used in Linux
 Note: _msize only returns a number of bytes allocated by malloc, realloc
or calloc STACK HEAP
 Ex: int _msize(void*):
<20>
◦ int* a = (int*)malloc(8); <10>
5
◦ *a = 5; <20>
◦ *(a+1) = 10; <24>

◦ cout << *a << “ ” << *(a+1)<<endl; 10


◦ cout << _msize(a) << endl;
8
MEMORY SUPPORT FUNCTIONS
Functions work with the memory heap
Build three support functions
◦ Allocate memory: re-use malloc function
◦ Free memory: re-use free function
◦ Return the bytes allocated
void* mAlloc(int size){//example size is 5 bytes
◦ void* p = malloc(size + sizeof(int));
◦ *(int*)p = size; <20>
<10> 5
◦ return ((int*)p) + 1; <20>
<24>
<24>
}

9
MEMORY SUPPORT FUNCTIONS
Functionswork with the memory heap
void* mAlloc(int size){//example size is 5 bytes
◦ void* p = malloc(size + sizeof(int));
◦ *(int*)p = size;
◦ return ((int*)p) + 1;
}
void mFree(void* p){
◦ p = ((int*)p) – 1; <10>
<20>

5
◦ free(p); <20>
<24>
<24>
}

10
MEMORY SUPPORT FUNCTIONS
 Functionswork with the memory heap
 void* mAlloc(int size){//example size is 5 bytes
◦ void* p = malloc(size + sizeof(int));
◦ *(int*)p = size;
◦ return ((int*)p) + 1;
<20>
} <10>
5
 int mSize(void* p){ <20>
<24>
◦ return *(((int*)p) – 1); <24>

}
 void main(){
◦ char* p = (char*)mAlloc(5);
◦ gets(p);
◦ cout<<p<<endl;
◦ cout<<mSize(p)<<endl;
◦ mFree(p);
}
11
MEMORY MANIPULATION
FUNCTIONS
 Library <memory.h> contain memory manipulation
functions
 void* memset(void* des, int ch, int n): Initialize n bytes
with value of ch for the memory des
 void main(){
<100>
◦ char* s = (char*)malloc(6); s <20> <20> A
◦ s[5] = 0;
<200> A
◦ char* p = memset(s, 65, 5); p <20>
A
◦ cout << s << endl;
◦ cout << (int*)s << endl; A

◦ cout << (int*)p << endl; A


◦ free(s); 0
}
12
MEMORY MANIPULATION
FUNCTIONS
 Library <memory.h> contain memory manipulation functions
 void* memmove(void* des, const void* src, int n): Copy n bytes
from memory src to memory des. This function returns the address
of des pointer
 void main(){
◦ char* s = (char*)malloc(6);
<100>
◦ s[5] = 0; s <20> <20> A
◦ memset(s, 65, 5);
<50> A A
◦ char* d = (char*)malloc(6); <200>
d <50> A A
◦ d = (char*)memmove(d, s, 6);
◦ cout << d << endl; A A
◦ cout << (int*)d << endl;
A A
◦ free(s);
◦ free(d); A
0
}
0
13
MEMORY MANIPULATION
FUNCTIONS
 Library <memory.h> contain memory manipulation functions
 int memcmp(const void* buf1, const void* buf2, int n): Compare
n bytes of two memories buf1 and buf2. Function returns 1 if buf1
> buf2, -1 if buf1 < buf2 and 0 if equality. Note: This function
only compares value of each byte
 void main(){
◦ char* s = (char*)malloc(6);
◦ s[5] = 0;
◦ memset(s, 65, 5);
◦ char* d = (char*)malloc(6);
◦ d = (char*)memmove(d, s, 6);
◦ cout << memcmp(s, d, 6) << endl;
◦ free(s);
◦ free(d);
}
14
MEMORY MANIPULATION
FUNCTIONS
 Library <memory.h> contain memory manipulation functions
 int _memicmp(const void* buf1, const void* buf2, unsigned int
n): Similar to memcmp, but case insensitive
 void main(){
◦ char* s = (char*)malloc(6);
◦ s[5] = 0;
◦ memset(s, 65, 5);
◦ char* d = (char*)malloc(6);
◦ d = (char*)memmove(d, s, 6);
◦ d[0] = ‘a’;
◦ cout << memcmp(s, d, 6) << endl;
◦ cout << _memicmp(d, s, 6) << endl;
◦ free(s);
◦ free(d);
}
15
ALLOCATE & USE DYNAMIC ARRAY
(WITH PRIOR SIZE)
Separatefunctions of input/output
void main() <100>
B <500>
◦ int nB; float* B = inputArray(&nB); <200>
<300>
◦ if(B != NULL) n <200> nB 3

 outputArray(B, nB); free(B);


<400> <500><504><508>
void inputArray(int* n) a <500> 5 6 7

◦ cin>>(*n);
◦ float* a = (float*)calloc((*n), sizeof(float));
◦ if(a != NULL)
 for(int i = 0; i < (*n); i++){cin>>a[i];}
◦ return a; 16
ALLOCATE & USE DYNAMIC ARRAY
(WITH PRIOR SIZE)
Build
struct intArray
Example
◦ struct intArray{ int n, *arr;}; <200> <204> <300>
B 3 <500> a <200>
◦ void main(){
 intArray B;
 nhap(&B); <500> 1
 xuat(&B); <504> 2
 huy(&B); <508> 3
◦}
◦ void nhap(intArray* a){
 cin >> a->n;
 a->arr = (int*)malloc(a->n * sizeof(int));
 for(int i = 0; i < a->n; i++) cin >> a->arr[i];
◦} 17
ALLOCATE & USE DYNAMIC ARRAY
(WITH PRIOR SIZE)
Build
struct intArray
<200> <204> <300>
Example B 3 <500> a <200>
◦ struct intArray{ int n, *arr;};
◦ void main(){
<500> 1
 intArray B;
 nhap(&B); <504> 2

 xuat(&B); //xuat(B); <508> 3


 huy(&B);
◦} <200> <204> <300> <304>
B 3 <500> a 3 <500>
◦ void xuat(const intArray* a){
 for(int i = 0; i < a->n; i++) cout << a->arr[i];
◦} <500> 1
◦ void xuat(intArray a){ <504> 2
 for(int i = 0; i < a.n; i++) cout << a.arr[i];
<508> 3
◦} 18
ALLOCATE & USE DYNAMIC ARRAY
(WITH PRIOR SIZE)
Build
struct intArray
Example
◦ struct intArray{ int n, *arr;}; B
<200> <204> <300>
a <200>
3 <500>
◦ void main(){
 intArray B; 1
<500>
 nhap(&B); xuat(&B); huy(&B); <504> 2
◦} <508> 3

◦ void huy(intArray* a){


 if(a != NULL)
 if(a->arr != NULL)
 free(a->arr);
◦} 19
ALLOCATE & USE DYNAMIC ARRAY
(WITH UNKNOWN SIZE)
User determines when to stop input
Ex: Use version of ‘nhap’ function with parameter of reference
pointer <200> <204>
◦ void main(){ B <500>
a
null nB n 3120
 int* B, nB;
 nhap(B, nB); xuat(B, nB); free(B); <300>

◦} anew <500>
null 3210 x

◦ void nhap(int*& a, int &n){ 2130 m


 int x, m, *anew;
<500> 1
 anew = a = NULL;
 m = x = n = 0; <504> 2
 while(cin >> x){
 m = n + 1; <508> 3
 anew = (int*)realloc(a, m * sizeof(int));
 if(anew != NULL){ anew[n++] = x; a = anew;}
 }
 cin.clear();
◦} 20
ALLOCATE & USE DYNAMIC ARRAY
(WITH UNKNOWN SIZE)
User determines when to stop input
Ex: Use version of ‘nhap’ function with parameter of level 2 pointer
◦ void main(){ <200> <204>
 int* B, nB; B <500>
null nB n 2310
 nhap(B, nB); xuat(B, nB); free(B); <250>
◦} a <200>
2310 x
◦ void nhap(int** a, int &n){ <300>
 int x, m, *anew; anew <500>
null 3120 m
 anew = *a = NULL;
 m = x = n = 0; <500> 1
 while(cin >> x){ <504> 2
 m = n + 1;
 anew = (int*)realloc(*a, m * sizeof(int)); <508> 3
 if(anew != NULL){ anew[n++] = x; *a = anew;}
 }
 cin.clear();
◦}
21
ALLOCATE & USE DYNAMIC ARRAY
(WITH UNKNOWN SIZE)
Template function allows us to use with various
datatypes
Ex: Use version of ‘nhap’ function with parameter of
level 2 pointer
◦ template <class T>
◦ void nhap(T** a, int &n){
 T x, *anew; int m;
 anew = *a = NULL; Need overload operator ‘>>’ for user-defined type
 m = n = 0;
 while(cin >> x){
 m = n + 1;
 anew = (T*)realloc(*a, m * sizeof(T));
 if(anew != NULL){ anew[n++] = x; *a = anew;}
 }
 cin.clear();
22
ALLOCATE & USE DYNAMIC ARRAY
(WITH UNKNOWN SIZE)
Template function allows us to use with various datatypes
Ex: Use version of ‘nhap’ function with parameter of level 2
pointer
◦ struct PhanSo{int tu, mau;};
◦ void nhap(T** a, int &n){
 //…
◦}
◦ istream& operator>>(istream& inDev, PhanSo& p){
 inDev >> p.tu >> p.mau;
 return inDev;
◦}
◦ void main(){
 PhanSo* B; int nB;
 nhap(B, nB); xuat(B, nB); free(B);
◦} 23
ALLOCATE & USE DYNAMIC ARRAY
Goals: build support functions processing
1D array
The functions’ advantage:
◦ Process with GENERAL TYPE
◦ Need not vector<T>
Need firstly checking array with float

Store a number of items …

header data
24
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ The size of header: int headSize = sizeof(int)
◦ int memSize(int nItem): calculate needed size
(bytes) to store nItem
 int memSize(int nItem){
 return headSize + nItem * sizeof(float);
}

Need 4 bytes …

header data Need nItem * sizeof(float) bytes


25
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ void* origin_addr(float* aData): take the
head’s address from the data’s address
 void* origin_addr(void* aData){
 return (char*)aData – headSize;
} <6> - 4*sizeof(char)

<2> <6>

header data
26
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ float* data_addr(void* origin): take the data’s
address from the head’s address (pointer
origin points to the head’s address)
 float* data_addr(void* origin){
 return (float*)((char*)origin + headSize); <2> + 4*sizeof(char)
}
<2> <6>

header data
27
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ void set_nItem(float* aData, int nItem): assign
value nItem into the head’s memory
 void set_nItem(float* aData, int nItem){
 *((int*)origin_addr(aData)) = nItem;
}
*(<2>)

<2> <6>

header data
28
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ int get_nItem(float* aData): take the value
nItem of the head’s memory
 int get_nItem(float* aData){
 return *((int*)origin_addr(aData));
}

<2> <6>


header data
29
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ int floatArrSize (float* aData): take a number
of items of 1D array aData
 int floatArrSize(float* aData){
 if(aData != NULL) return get_nItem(aData);
 return 0;
}
<2> <6>


header data
30
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ void floatArrFree (float* aData): destroy all
memory allocated (from address of head
portion)
 void floatArrFree (void* aData){
 if(aData != NULL)
 free(origin_addr(aData))
}
<2> <6>

header data
31
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ float* floatArrResize(float* aData, int nItem): resize
to new size (nItem: a new number of items)
 float* floatArrResize (float* aData, int nItem){
12
8  int sz = memSize(nItem); 21
 float* anew = NULL; void* originAddr = NULL;
 if(aData != NULL) originAddr = origin_addr(a);
 anew = (float*)realloc(originAddr, sz);
 if(anew != NULL){
 if(aData == NULL) memset(anew, 0, sz); h d d
 aData = data_addr(anew);
anew <4>
null 102 0
 set_nItem(aData, nItem); <4> <8>
 } originAddr <4>
null

 return aData;
aData <8>
null
 } 32
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ int floatArrPushback(float** aData, float x):
add x into 1D array aData
 int floatArrPushback(float** aData, float x){
 int n = floatArrSize(*aData); 10
 float* anew = floatArrResize(*aData, n + 1);
 if(anew != NULL){
 anew[n] = x;
 *aData = anew;
 return 1; aData <10>
} a <18>
null
 return 0; 21 x x
<10>
<18>
} anew <18>
33
<14>
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ float floatArrPopback(float** aData): take the
last item out of 1D array aData
 int floatArrPopback(float** aData){<78>
 int n = floatArrSize(*aData); <10> aData

 float x = 0;
a <18> 21 x x
 if(*aData != NULL && n > 0){
<10> <14> <18>
 n--; x = (*aData)[n];
 float* anew = floatArrResize(*aData, n);
1 <18> anew
 if(anew != NULL) *aData = anew; n
<58>
}
 return x;
}
34
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ float* floatArrInput(): return 1D array of float
items
 float* floatArrInput(){ <10> <20>
 float* a = NULL, x = 0; a <24>
null x 103 ctrl + x

 while(cin >> x) { <20> <24>


21 1 3
 floatArrPushback(&a, x);
}
 cin.clear();
 return a;
}

35
ALLOCATE & USE DYNAMIC ARRAY
Check array with float
◦ Demonstration of main()
 void main(){
 float* B = NULL; <10>
 B = floatArrInput(); B <24>
null
<20>

 floatArrFree(B); <20> <24>


} 2 1 3

36
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing
1D array with GENERAL TYPE
Store the size of each item aData

aOrigin

Store a number of items


header data

= sizeof(a number of item) + sizeof(the size of each item)

37
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing
1D array with GENERAL TYPE
Size of header: int headSize = sizeof(int)
+ sizeof(int)
memSize(): calculate sum of byte needed
int memSize(int nItem, int szItem){
◦ return headSize + nItem * szItem;
}
nItem sizeItem …

38
header data
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing
1D array with GENERAL TYPE
void* origin_addr (void* aData){
◦ if(aData != NULL)
 return (char*)aData – headSize;
◦ return NULL;
} (char*)aData aData

header data
39
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing
1D array with GENERAL TYPE
void* data_addr (void* aOrigin){
◦ if(aOrigin != NULL)
 return (char*)aOrigin + headSize;
◦ return NULL;
aOrigin
} (char*)aOrigin

header data
40
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing
1D array with GENERAL TYPE
void* sizeItem_addr (void* aData){
◦ if(aData != NULL)
 return (char*)aData – sizeof(int);
◦ return NULL;
} (char*)aData aData

header data
41
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing
1D array with GENERAL TYPE
int arrSize(void* aData){
◦ if(aData != NULL)
 return *(int*)origin_addr(aData);
◦ return 0;
} (char*)aData aData

nItem …

header data
42
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing
1D array with GENERAL TYPE
int arrItemSize(void* aData){
◦ if(aData != NULL)
 return *(int*)sizeItem_addr(aData);
◦ return 0;
} (char*)aData aData

szItem …

header data
43
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing
1D array with GENERAL TYPE
void arrFree(void* aData){
◦ if(aData != NULL) free(origin_addr(aData));
}
(char*)aData
aData

header data

44
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing 1D array with
GENERAL TYPE
arrInit(): Allocate the sum of byte
void* arrInit(int nItem, int szItem){
◦ int sz = memSize(nItem, szItem); Ex: nItem = 3 & szItem = 4

sz = 8 + 3 * 4
◦ void* aOrigin = malloc(sz); aData
aOrigin
◦ if(aOrigin != NULL){ <10> <18>

 memset(aOrigin, 0, sz); 30 40 0 0 0

 void *aData = data_addr(aOrigin);


header data
 *(int*)origin_addr(aData) = nItem;
 *(int*)sizeItem_addr(aData) = szItem;
 return aData;
◦}
◦ return NULL;
} 45
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing 1D array with GENERAL
TYPE
arrResize(): resize the memory of 1D array aData
Ex: nItem = 4
void* arrResize(void* aData, int nItem){
◦ if(aData == NULL || nItem < 0) return NULL;
◦ void* aOrigin = origin_addr(aData); aData sizeItem sz
◦ int sizeItem = *(int*)sizeItem_addr(aData); aOrigin aNew 4 24
◦ int sz = memSize(nItem, sizeItem); <10> <18>
◦ void *aNew = realloc(aOrigin, sz); 43 4 0 0 0
◦ if(aNew != NULL){
 aData = data_addr(aNew); header data

 *(int*)origin_addr(aData) = nItem;
 return aData;
◦}
◦ return NULL;
} 46
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing 1D array
with GENERAL TYPE
Function arrPushback(): Add x into 1D array aData
int arrPushback(void** aData, void* x){
◦ int nItem = arrSize(*aData), szItem = arrItemSize(*aData);
◦ void* aNew = arrResize(*aData, 1 + nItem);
◦ if(aNew != NULL){
 memmove((char*)aNew + nItem
aNew* szItem,<50>
x, szItem);
aData nItem szItem

 *aData = aNew; <18>


a
<18> <50> 3 4

 return 1; <10> <18>

43 4 9 8 7 6
◦}
◦ return 0; header data
<60>

} <70>
6
<60> 47
x
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing 1D
array with GENERAL TYPE
Example: rebuild floatArrIn(): create and return a
1D array of items with float
float* floatArrIn(){
◦ float* a = (float*)arrInit(0, sizeof(float)), x = 0;
◦ while(cin >> x){ <50>

<18>
 arrPushback((void**)&a, &x); a

<10> <18>
◦} 0 4 6 7 8

◦ cin.clear(); header data


◦ return a; <70>

} x
6708
48
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing 1D array with
GENERAL TYPE
Example: rebuild PhanSoArrIn(): create and return a
1D array of items with type of PhanSo
PhanSo* PhanSoArrIn(){
◦ PhanSo* a = (PhanSo*)arrInit(0, sizeof(PhanSo));
◦ PhanSo x = {0, 1};
◦ while(cin >> x){
 arrPushback((void**)&a, &x);
◦}
◦ cin.clear();
◦ return a;
} 49
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing 1D array with
GENERAL TYPE
arrPopback: Take the last item of 1D array aData, and
decrease it size by one
void* arrPopback(void** aData){
◦ int nItem = arrSize(*aData), szItem = arrItemSize(*aData);
◦ void* x = malloc (szItemSize);
◦ if(*aData != NULL && nItem > 0){
 nItem--;
 memmove(x, (char*)(*aData) + nItem * szItem, szItem);
 void* aNew = arrResize(*aData, nItem); aData nItem szItem
<50>
 if(aNew != NULL) *aData = aNew;
aNew <18> <50> 43 4
<18> a
◦} <10> <18>
<60> <70>
◦ return x; 6 <60>
x
43 4 9 8 7 6

} 50
header data
ALLOCATE & USE DYNAMIC ARRAY
Goal: build support functions processing 1D array
with GENERAL TYPE
Example: main() with float
void main(){
◦ cout << “Input items:\n”;
◦ float* B = floatArrIn();
◦ float* x = (float*)arrPopback((void**)&B);
◦ cout << “After pop: \n”;
◦ floatArrOut(B);
◦ cout << “\nPopped element: ” << *x << endl;
◦ free(x);
◦ arrFree((float*)B)
} 51
ALLOCATE & USE DYNAMIC ARRAY
(OPERATOR ‘[]’)
Goal: help code be more natural when
using struct to create array
Need to return reference when using []
//File.h //File.cpp
struct floatArray{ #include “File.h”
int n; float&floatArray::operator[](int i){
float* arr; if(arr != NULL && i >= 0 && i < n) return arr[i];
float& operator[](int); return dummy;
}; }
void floatArrayOutput(floatArray& a){
if(a.arr == NULL) return;
for(int i = 0; i < a.n; i++) cout << a[i] << “ ”; // a.operator[](i)
} 52
POINTER-CHECKING TECHNIQUES
Canconvert normal variable pointer
Need to carefully control
void markMem(void* a){ void main(){
cout<<“Address of a: ”<<&a; int* p = new int; *p = 10;
cout<<“Address a points: ”<<a; cout<<“Address of p: ”<<&p;
void** vh = (void**)a; cout<<“Address p points: ”<<p;
cout<<“Address of vh: ”<<&vh; cout<<“Value at address p points: ”<<*p;
cout<<“Address vh points: ”<<vh; markMem(p);
cout<<“Value at address vh points: ”<<*vh; free(p);
*vh = a; }
cout<<“Value at address vh points: ”<<*vh; <50>
} p <200>
<70> <200>
<200> 10
<200>
a
<90>
<200>
vh 53
POINTER-CHECKING TECHNIQUES
Canconvert normal variable pointer
Need to carefully control
void markMem(void* a){ void main(){
cout<<“Address of a: ”<<&a; int p = 10;
cout<<“Address a points: ”<<a; cout<<“Address of p: ”<<&p;
void** vh = (void**)a; cout<<“Value of p: ”<<p;
cout<<“Address of vh: ”<<&vh; markMem(&p);
cout<<“Address vh points: ”<<vh; }
cout<<“Value at address vh points: ”<<*vh;
*vh = a;
cout<<“Value at address vh points: ”<<*vh; <50>

} p <50>
10

<70>
<50>
a
<90>
<50>
vh 54
POINTER-CHECKING TECHNIQUES
Divide memory into 2 parts:
◦ Header: contains information of original
pointer and needed size for data
◦ Data: contains data
Needed size for data pData

pmem

Original address
header data

4 byte 4 byte
55
POINTER-CHECKING TECHNIQUES
Build markMem and checkMem
◦ static void markMem(void* pmem){
 *(void**)pmem = pmem;
<50>
◦} <200> pmem
<200>

<90>
<200>
vh

◦ static int checkMem(void* pmem){


 return *(void**)pmem == pmem;
◦} 56
POINTER-CHECKING TECHNIQUES
Build checkPtr and safeSize
◦ int checkPtr(void* pData){
 if(pData == NULL) return 0;
 void* pmem = (char*)pData – 8;
 return checkMem(pmem); <1000>

◦} <58> pData
<2000> <50> <54> <58>
pmem <50> <50> M (bytes) …

◦ size_t safeSize(void* pData){


<1000>
 if(checkPtr(pData) == 0) return 0;
<58> pData
 return
<2000> *(size_t*)((char*)pData
<50> <54> <58> – 4);

◦}
ptemp <54> <50> M (bytes)
57
POINTER-CHECKING TECHNIQUES
Build safeMalloc Example: szmem = 8

◦ void* safeMalloc(size_t szmem){


 size_t sz = szmem + 8; <10> 16
sz
 void* pmem = malloc(sz); <200>
<200> 0
0
<200>
<50> 0
pmem
 if(pmem != NULL){ 0
<204> 0
 memset(pmem, 0, sz); 0
8
0
 markMem(pmem); 0
<208>
 *(size_t*)((char*)pmem + 4) = szmem; 0
0
0
 return (char*)pmem + 8; <208> 0
<60>
vh
} <212> 0
0
0
 return NULL; 0

◦}
58
POINTER-CHECKING TECHNIQUES
Build safeFree
◦ void* safeFree(void* pData){ <200>
 if(pData != NULL){ <50> <200>
pmem
<200>

 void* pmem = (char*)pData - 8; <204>


 if(checkMem(pmem)){ <10>
sz
16
8

 size_t sz = safeSize(pData) + 8;
<208> 0
 memset(pmem, 0 ,sz); 0
0
 free(pmem); <60> <208> 0
pData <212> 0
} 0
0
} 0

◦}

59
POINTER-CHECKING TECHNIQUES
Buid safeRealloc Ex: nsz = 12

◦ void* safeRealloc(void* pData, size_t nsz){


 if(nsz <= 0) return NULL;
 if(pData == NULL) return safeMalloc(nsz); <200>
<200>
 void* pmem = (char*)pData – 8; <200>
<50>
pmem
 if(!checkMem(pmem)) return NULL; <204>
8
12
 void* pnew = realloc(pmem, nsz + 8);
 if(pnew != NULL){ <90> <200>
<208>
<208> 0
0
pnew
 markMem(pnew); 0
0
 *(size_t*)((char*)pnew + 4) = nsz; <212> 0
0
 pnew = (char*)pnew + 8; <60> <208>
pData 0
0
} <216>
<10> 12
 return pnew; nsz

◦} 60
POINTER-CHECKING TECHNIQUES
How to use <200>

◦ void main(){ <200>

 int* arr = (int*)safeMalloc(sizeof(int) * 4); <204>


16
 if(checkPtr(arr) != 0){
 arr[0] = 1; arr[1] = 2; <208>
1
 arr[2] = 3; arr[3] = 4;
 for(int i = 0; i < 4; i++) cout << arr[i]; <212>
2
}
 safeFree(arr); <216>
3
<60> <208>
arr
◦} <220>
4

61

You might also like