棧空間的分配方式對普通的程序開發來講是沒有意義的,有系統來完成相關操作,但有時棧空間的分配方式又會顯得很重要。棧的分配方式有兩種,其一是從高地址空間向低地址空間分配,其二是從低地址空間向高地址空間分配。那麼如何確定棧空間的分配方式呢,下述代碼可以用來確定棧的分配方式。
int fun(){ static int * pnt = 0; if(pnt == 0){ int abc; pnt = &abc; fun(); } else{ int bcd; if(pnt > &bcd){ printf("從高地址向低地址分配"); // Windows的分配方式 } else{ printf("從低地址向高地址分配"); } } return 0; }
+
成員指針的用法。指針可以算作C/C++的短刀利器了,指向類成員的指針包括指向類數據成員的指針和指向類方法(函數)的指針,下述代碼演示了這兩種指針的用法
class AClass{ public: AClass():m_name(0), m_age(0) { }; AClass(const char * name); ~AClass(); public: void SayHello(); void SayOkay(); private: char * m_name; int m_age; public: typedef char * AClass::*PACName; // 引入新的類型(指向數據成員的指針) operator PACName() { return &AClass::m_name; } // 執行類型轉換 typedef int AClass::*PACAge; operator PACAge() { return &AClass::m_age; } typedef void (AClass::*Say)(); // 指向成員函數的指針 }; int fun(void){ AClass a("AClass"); AClass::Say func = &AClass::SayHello(); (a.*func)(); // 調用成員函數 AClass * p = &a; func = &AClass::SayOkay; (p->*.func)(); // 調用成員函數 printf("%s\t%d\n", a.*AClass::PACName(a), a.*AClass::PACAge(a)); // 數據成員指針的使用。PS:是不是有些囉嗦?! }
+
對象在內存中的佈局。瞭解對象在內存中的佈局,可以很方便的通過數據成員找到包含該數據成員的對象的地址,續而執行更多的操作,這是C/C++的一個奇技淫巧。下面是示例代碼
struct A{ int a; double b; char c; } int fun(void){ A x; printf("%x,%x,%x,%x,%d\n", &x, &(x.a), &(x.b), &(x.c), sizeof(x)); // 運行結果:0x27AC48,0X27AC48,0X27AC50,0x27AC58,24(結構的大小是24而不是13!請參考相關文檔) // 如果知道了x.a的地址,那麼x的地址也就知道了。 return 0; }
+
new和delete操作符重載。new和delete操作符會經常用到,但對這兩個操作符進行重載的卻很少,通過這兩個操作符的重載,很容易實現把文件當內存來用。還可以通過這兩個操作符的重載,來跟蹤內存的使用情況,諸如,是否有內存泄露等。
//完成內存使用的跟蹤(通過重載全局new/delete操作符) void * operator new (size_t size, char * file, int line){ // 此處可以填寫記錄日誌代碼 return malloc(size); } void * operator delete(void * p){ // 此處可以填寫記錄日誌代碼 free(p); } #define NEW ::new #define DELETE ::delete // 接下來就需要使用NEW/DELETE替換掉new/delete了。
將對象分配到指定的內存空間(主要用作對象的成員函數來使用)
//重載全局new/delete操作符 void * operator(size_t size, void * p){ return p; } void * delete(void * p){ return; } // 成員函數操作符 class ClassA{ public: ClassA(); public: void * operator new (size_t, void *); void operator delete(void* p) }; void * ClassA::operator new(size_t size, void * p){ return p; } void ClassA::operator delete(void * p){ return; } int fun(void){ void * p = malloc(sizeof(ClassA)); // 是不是有點畫蛇添足的意味?就看你怎麼用了 ClassA a = new(p); delete a; free(p); }
+
strncpy函數,應該被經常用到,爲什麼這裏要提起呢,因爲這個函數隱藏了一個很大的危險,這個危險隱藏的很深,它會導致程序莫名其妙的問題。strncpy函數的原形是strncpy(char* DST, char* SRC, size_t LEN);其解釋是,strncpy將從SRC中複製不超過LEN個長度的字符到SRC中(包括NULL字符)。如果SRC的長度小於LEN, NULL字符被添加DES中,並且直到複製了LEN個字符。這裏沒有強調的是,如果SRC的長度超過了LEN,則NULL字符將不被添加到DST中。如果你在開發程序的時候沒有注意到這個問題,你已經引入了一個嚴重的錯誤。