🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
C++被人骂娘最多的就是指针。 夜深人静的时候,拿出几个使用指针容易出现的坑儿。可能我的语言描述有些让人费劲,尽量用代码说话。 **通过指向类的NULL指针调用类的成员函数** 试图用一个null指针调用类的成员函数,导致崩溃: ~~~ #include <iostream> using namespace std; class A { int value; public: void dumb() const {cout << "dumb()\n";} void set(int x) {cout << "set()\n"; value=x;} int get() const {cout << "get()\n"; return value;} }; int main() { A *pA1 = new A; A *pA2 = NULL; pA1->dumb(); pA1->set(10); pA1->get(); pA2->dumb(); pA2->set(20);//崩溃 pA2->get(); return 0; } ~~~ 为什么会这样? 通过非法指针调用函数,就相当于给函数传递了一个指向函数的非法指针! 但是为什么pA2->dumb()会成功呢? 因为导致崩溃的是访问了成员变量!! **使用已经释放的指针** ~~~ struct X { int data; }; int foo() { struct X *pX; pX = (struct X *) malloc(sizeof (struct X)); pX->data = 10; free(pX); ... return pX->data; } ~~~ **使用未初始化的指针** 如果你这样写,编译器会提示你使用了未初始化的变量p。 ~~~ void fooA() { int *p; *p = 100; } ~~~ 那么如果我释放一个初始化的指针呢? ~~~ void fooB() { int *p; free(p); } ~~~ 结果是一样的!! **释放已经释放的指针** 直接看看代码: ~~~ void fooA() { char *p; p = (char *)malloc(100); cout << "free(p)\n"; free(p); cout << "free(p)\n"; free(p); } ~~~ 这样的问题也许不会立即使你的程序崩溃,那样后果更加严重!! **没有调用子类的析构函数** 之前的博客讲过,父类的析构函数最好声明为虚!! ~~~ ParentClass *pObj = new ChildClass; ... delete pObj; ~~~ 上述代码会造成崩溃,如果父类的析构函数不声明为虚,那么不会调用继承类的析构函数,造成内存泄露。 **内存溢出** 当我们拷贝字符串的时候,我们常常会用到 memcpy函数。这里特别需要注意的就是字符串结尾的null字符: ~~~ char *p = (char *)malloc(strlen(str)); strcpy(p, str); ~~~ 为了躲过这个坑,只需要把 strlen(str) 改为 strlen(str)+1。