這個版本是上個版本的加強版,上個版本的代碼:http://www.cnblogs.com/fengbohello/p/4542912.html
目錄
1、代碼
2、運行結果
1、代碼
1.1 調試信息的配置
//一個調試開關,如果要看調試信息,就把這個開關的注釋去掉 //#define USEDEBUG //如果調試開關打開了,就定義好調試的輸出函數(其實是個宏), #ifdef USEDEBUG #define DEBUG(fmt, arg...)\ do{\ printf("%s %d %s() : ", __FILE__, __LINE__, __func__);\ printf(fmt, ##arg);\ }while(0) #else //如果沒有打開,這個函數什么也不做 #define DEBUG(fmt, arg...) #endif
1.2 棧類的聲明
//定義模版類 ClsStack template<typename T> class ClsStack { //這個類的=型私有數據,主要用於對棧的內存分配進行管理, //用戶不需要關心內存,只需要調用對外提供的幾個方法就可以了 private : T ** __m_Data;//存儲數據的內存開始地址 int __m_pos;//記錄棧尾的位置,插入數據時插入這個位置 int __m_memsize;//記錄內存的總數 protected : //重新分配內存空間,可以減小,也可以增大 int __resize(int n); //獲取給定參數的雙倍內存,其實主要目的是防止參數是0 int __doublesize(int n); public : ClsStack(int n = 0); ~ClsStack(); //彈出棧頂 int pop (T ** ppData); //獲取棧頂元素,但是不彈出 int top (T ** ppData); //向棧添加數據 int push(T * pData); //清空整個棧的數據 int clear(void (*)(T*)); //輸出整個棧的數據,用於調試 void printStack(T * p[], int pos); };
1.3 構造函數的實現
//構造函數 //默認參數值是0 //參數非零時的作用是用於初始化棧空間的大小 template<typename T> ClsStack<T>::ClsStack(int n) { __m_Data = NULL; __m_pos = -1; __m_memsize = 0; if(0 != n) { __m_Data = new T * [n]; if(NULL != __m_Data) { __m_memsize = n; } } }
1.4) 析構函數的實現
//析構函數 //在棧對象被銷毀時,需要把申請的內存空間釋放 template<typename T> ClsStack<T>::~ClsStack() { if(NULL != __m_Data) { delete __m_Data; __m_Data = NULL; } __m_pos = -1; __m_memsize = 0; }
1.5)內存控制函數
//計算新的內存空間 //當參數是0的時候,指定內存空間是1 //參數不是0的時候,內存加倍 template<typename T> int ClsStack<T>::__doublesize(int n) { int x = 0; if(0 == n) { x = 1; } else { x = n * 2; } return x; } //重新設定棧的大小 //就是擴展當前的內存容量到指定的大小 template<typename T> int ClsStack<T>::__resize(int n) { T ** p = new T * [n]; if(NULL == p) { return -1; } memset(p, 0, sizeof(T *) * (n)); if(NULL != __m_Data) { //printStack(__m_Data, __m_pos); if( NULL == memcpy(p, __m_Data, __m_memsize * sizeof(T *))) { DEBUG("memcpy faild\n"); delete p; return -1; } //printStack(p, __m_pos); delete __m_Data; } __m_Data = p; __m_memsize = n; return 0; }
1.6)棧操作函數的實現
//彈出數據 //數據通過參數指定的指針返回 template<typename T> int ClsStack<T>::pop(T ** ppData) { if(NULL == ppData) { return -1; } int r = 0; if(-1 == __m_pos) { *ppData = NULL; r = -1; } else { *ppData = __m_Data[__m_pos --]; r = 0; DEBUG("memsize : [%u], pos : [%d], p = [0X%08X]\n", __m_memsize, __m_pos + 1, (unsigned int)*ppData); } return r; } //獲取棧頂元素,並不彈出 template<typename T> int ClsStack<T>::top(T ** ppData) { if(NULL == ppData) { return -1; } int r = 0; if(-1 == __m_pos) { *ppData = NULL; r = -1; } else { *ppData = __m_Data[__m_pos]; r = 0; } return r; } //向棧壓入元素 //棧會自己判斷內存,如果內存不足會自動增加內存 template<typename T> int ClsStack<T>::push(T * pData) { if(__m_pos + 1 >= __m_memsize) { int n = __doublesize(__m_memsize); if(0 != __resize(n)) { return -1; } } __m_Data[++__m_pos] = pData; DEBUG("memsize : [%u], pos : [%d], p = [0X%08X]\n", __m_memsize, __m_pos, (unsigned int)__m_Data[__m_pos]); return 0; }
1.7)清空棧數據函數
//清空棧,需要指定回收元素數據的函數, //否則無法知道如何回收由用戶申請的內存空間 template<typename T> int ClsStack<T>::clear(void (*F)(T *)) { if(NULL == F && __m_pos >= 0) { return -1; } if(NULL != __m_Data && 0 != __m_memsize) { for(int i = 0; i <= __m_pos; i++) { F(__m_Data[i]); __m_Data[i] = NULL; } delete __m_Data; } __m_Data = NULL; __m_pos = -1; __m_memsize = 0; }
1.8)調試輔助函數
//輸出棧的內存狀態,調試時使用 template<typename T> void ClsStack<T>::printStack(T * p[], int pos) { int i = 0; for(i = 0; i <= pos; i++) { printf("[%08u] = [0X%08X]\n", i, NULL == p ? 0 : p[i]); } printf("----------------------------\n"); }
1.9)測試代碼
//test 函數定義 #define TEST_EQ(a, b)\ do{\ if(a == b)\ {\ printf("\033[0;32m[SUCCESS %5d]\033[0m\n", __LINE__);\ }\ else\ {\ printf("\033[0;31m[FAILD %5d]\033[0m\n", __LINE__);\ }\ }while(0) int main() { ClsStack<int> objStack; int x = 10; int * p = &x; //向棧內壓入數據 objStack.push(p); int i = 0; for(i = 0; i <= 10; i++) { int * z = new int; *z = i; objStack.push(z); } //開始彈出數據 for(i = 10; i >= 0; i--) { int * z = NULL; objStack.pop(&z); if(NULL == z) { printf("z == NULL\n"); continue; } //測試彈出的數據和壓入的數據是否一致 TEST_EQ(i, *z); delete z; } int * g = NULL; objStack.pop(&g); TEST_EQ(x, *g); }
完整代碼如下(折疊了) :

1 /* 2 * ===================================================================================== 3 * 4 * Filename: stack.cpp 5 * 6 * Description: a template stack library 7 * 8 * Version: 1.0 9 * Created: 10/13/2016 09:52:46 AM 10 * Revision: none 11 * Compiler: gcc 12 * 13 * Author: YOUR NAME (fengbohello@foxmail.com), 14 * Organization: 15 * 16 * ===================================================================================== 17 */ 18 #include <stdio.h> 19 #include <string.h> 20 21 //一個調試開關,如果要看調試信息,就把這個開關的注釋去掉 22 //#define USEDEBUG 23 24 //如果調試開關打開了,就定義好調試的輸出函數(其實是個宏), 25 #ifdef USEDEBUG 26 #define DEBUG(fmt, arg...)\ 27 do{\ 28 printf("%s %d %s() : ", __FILE__, __LINE__, __func__);\ 29 printf(fmt, ##arg);\ 30 }while(0) 31 #else 32 //如果沒有打開,這個函數什么也不做 33 #define DEBUG(fmt, arg...) 34 #endif 35 36 //定義模版類 ClsStack 37 template<typename T> class ClsStack 38 { 39 //這個類的=型私有數據,主要用於對棧的內存分配進行管理, 40 //用戶不需要關心內存,只需要調用對外提供的幾個方法就可以了 41 private : 42 T ** __m_Data;//存儲數據的內存開始地址 43 int __m_pos;//記錄棧尾的位置,插入數據時插入這個位置 44 int __m_memsize;//記錄內存的總數 45 46 protected : 47 //重新分配內存空間,可以減小,也可以增大 48 int __resize(int n); 49 50 //獲取給定參數的雙倍內存,其實主要目的是防止參數是0 51 int __doublesize(int n); 52 53 public : 54 ClsStack(int n = 0); 55 ~ClsStack(); 56 57 //彈出棧頂 58 int pop (T ** ppData); 59 60 //獲取棧頂元素,但是不彈出 61 int top (T ** ppData); 62 63 //向棧添加數據 64 int push(T * pData); 65 66 //清空整個棧的數據 67 int clear(void (*)(T*)); 68 69 //輸出整個棧的數據,用於調試 70 void printStack(T * p[], int pos); 71 }; 72 73 //構造函數 74 //默認參數值是0 75 //參數非零時的作用是用於初始化棧空間的大小 76 template<typename T> ClsStack<T>::ClsStack(int n) 77 { 78 __m_Data = NULL; 79 __m_pos = -1; 80 __m_memsize = 0; 81 82 if(0 != n) 83 { 84 __m_Data = new T * [n]; 85 if(NULL != __m_Data) 86 { 87 __m_memsize = n; 88 } 89 } 90 } 91 92 //析構函數 93 //在棧對象被銷毀時,需要把申請的內存空間釋放 94 template<typename T> ClsStack<T>::~ClsStack() 95 { 96 if(NULL != __m_Data) 97 { 98 delete __m_Data; 99 __m_Data = NULL; 100 } 101 __m_pos = -1; 102 __m_memsize = 0; 103 } 104 105 //計算新的內存空間 106 //當參數是0的時候,指定內存空間是1 107 //參數不是0的時候,內存加倍 108 template<typename T> int ClsStack<T>::__doublesize(int n) 109 { 110 int x = 0; 111 if(0 == n) 112 { 113 x = 1; 114 } 115 else 116 { 117 x = n * 2; 118 } 119 120 return x; 121 } 122 123 //重新設定棧的大小 124 //就是擴展當前的內存容量到指定的大小 125 template<typename T> int ClsStack<T>::__resize(int n) 126 { 127 T ** p = new T * [n]; 128 if(NULL == p) 129 { 130 return -1; 131 } 132 memset(p, 0, sizeof(T *) * (n)); 133 if(NULL != __m_Data) 134 { 135 //printStack(__m_Data, __m_pos); 136 if( NULL == memcpy(p, __m_Data, __m_memsize * sizeof(T *))) 137 { 138 DEBUG("memcpy faild\n"); 139 delete p; 140 return -1; 141 } 142 //printStack(p, __m_pos); 143 delete __m_Data; 144 } 145 __m_Data = p; 146 __m_memsize = n; 147 148 return 0; 149 } 150 151 //彈出數據 152 //數據通過參數指定的指針返回 153 template<typename T> int ClsStack<T>::pop(T ** ppData) 154 { 155 if(NULL == ppData) 156 { 157 return -1; 158 } 159 int r = 0; 160 if(-1 == __m_pos) 161 { 162 *ppData = NULL; 163 r = -1; 164 } 165 else 166 { 167 *ppData = __m_Data[__m_pos --]; 168 r = 0; 169 DEBUG("memsize : [%u], pos : [%d], p = [0X%08X]\n", __m_memsize, __m_pos + 1, (unsigned int)*ppData); 170 } 171 172 return r; 173 } 174 175 //獲取棧頂元素,並不彈出 176 template<typename T> int ClsStack<T>::top(T ** ppData) 177 { 178 if(NULL == ppData) 179 { 180 return -1; 181 } 182 int r = 0; 183 if(-1 == __m_pos) 184 { 185 *ppData = NULL; 186 r = -1; 187 } 188 else 189 { 190 *ppData = __m_Data[__m_pos]; 191 r = 0; 192 } 193 194 return r; 195 } 196 197 //向棧壓入元素 198 //棧會自己判斷內存,如果內存不足會自動增加內存 199 template<typename T> int ClsStack<T>::push(T * pData) 200 { 201 if(__m_pos + 1 >= __m_memsize) 202 { 203 int n = __doublesize(__m_memsize); 204 if(0 != __resize(n)) 205 { 206 return -1; 207 } 208 } 209 __m_Data[++__m_pos] = pData; 210 DEBUG("memsize : [%u], pos : [%d], p = [0X%08X]\n", __m_memsize, __m_pos, (unsigned int)__m_Data[__m_pos]); 211 212 return 0; 213 } 214 215 //清空棧,需要指定回收元素數據的函數, 216 //否則無法知道如何回收由用戶申請的內存空間 217 template<typename T> int ClsStack<T>::clear(void (*F)(T *)) 218 { 219 if(NULL == F && __m_pos >= 0) 220 { 221 return -1; 222 } 223 if(NULL != __m_Data && 0 != __m_memsize) 224 { 225 for(int i = 0; i <= __m_pos; i++) 226 { 227 F(__m_Data[i]); 228 __m_Data[i] = NULL; 229 } 230 delete __m_Data; 231 } 232 __m_Data = NULL; 233 __m_pos = -1; 234 __m_memsize = 0; 235 } 236 237 //輸出棧的內存狀態,調試時使用 238 template<typename T> void ClsStack<T>::printStack(T * p[], int pos) 239 { 240 int i = 0; 241 for(i = 0; i <= pos; i++) 242 { 243 printf("[%08u] = [0X%08X]\n", i, NULL == p ? 0 : p[i]); 244 } 245 printf("----------------------------\n"); 246 } 247 248 249 //test 函數定義 250 #define TEST_EQ(a, b)\ 251 do{\ 252 if(a == b)\ 253 {\ 254 printf("\033[0;32m[SUCCESS %5d]\033[0m\n", __LINE__);\ 255 }\ 256 else\ 257 {\ 258 printf("\033[0;31m[FAILD %5d]\033[0m\n", __LINE__);\ 259 }\ 260 }while(0) 261 262 int main() 263 { 264 ClsStack<int> objStack; 265 int x = 10; 266 int * p = &x; 267 268 //向棧內壓入數據 269 objStack.push(p); 270 int i = 0; 271 for(i = 0; i <= 10; i++) 272 { 273 int * z = new int; 274 *z = i; 275 objStack.push(z); 276 } 277 //開始彈出數據 278 for(i = 10; i >= 0; i--) 279 { 280 int * z = NULL; 281 objStack.pop(&z); 282 if(NULL == z) 283 { 284 printf("z == NULL\n"); 285 continue; 286 } 287 //測試彈出的數據和壓入的數據是否一致 288 TEST_EQ(i, *z); 289 delete z; 290 } 291 int * g = NULL; 292 objStack.pop(&g); 293 TEST_EQ(x, *g); 294 }
2、運行結果
2.1、編譯
g++ -g -c -o stack.o stack.cpp -Wall -I./
g++ -g -o stack stack.o -Wall -I./
2.2、運行結果
$ ./stack [SUCCESS 288] [SUCCESS 288] [SUCCESS 288] [SUCCESS 288] [SUCCESS 288] [SUCCESS 288] [SUCCESS 288] [SUCCESS 288] [SUCCESS 288] [SUCCESS 288] [SUCCESS 288] [SUCCESS 293]
本文同步發表於博客園:http://www.cnblogs.com/fengbohello/p/4547598.html
作者: 風波
mail: fengbohello@foxmail.com