栈空间的分配方式对普通的程序开发来讲是没有意义的,有系统来完成相关操作,但有时栈空间的分配方式又会显得很重要。栈的分配方式有两种,其一是从高地址空间向低地址空间分配,其二是从低地址空间向高地址空间分配。那么如何确定栈空间的分配方式呢,下述代码可以用来确定栈的分配方式。
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中。如果你在开发程序的时候没有注意到这个问题,你已经引入了一个严重的错误。