C/C++常见知识点总结

1. C/C++的内存分配方式:

(1)从静态存储区域进行分配,内存在程序编译的时候就已分配好,这块内存在程序运行的整个期间都存在,如静态变量,全局变量。
(2)从栈上进行分配。函数在执行时,函数体内局部变量的存储单元可以在栈上创建,函数执行结束时,这些存储单元自动释放,栈内存分配运算内置于处理器的指令集中,效率很高,但分配的内存容量有限。
(3)从堆区进行动态内存分配。动态内存分配使用new或者malloc进行分配,使用delete或free进行释放。

2. new、delete、malloc、free之间的关系

(1)delete不仅会释放内存,还会调用析构函数

#include <iostream>

class Person{
public:
    Person(){
        printf("构造函数被调用...\n");
    }
    ~Person(){
        printf("析构函数被调用...\n");
    }
};

int main(int argc, const char * argv[]) {
    Person *p = new Person;
    delete p;
    p = NULL;
    return 0;
}

使用delete释放对象时,析构函数被自动调用!
在这里插入图片描述
(2) malloc和free是C/C++中的标准库函数,new和delete是C++中的运算符,都可以用于动态内存申请与释放。
(3)对于非内部数据类型的对象而言,malloc和free无法满足动态对象的要求:对象的创建时要自动执行构造函数,对象的销毁要自动执行析构函数。
(4)由于malloc和free是库函数而不是运算符,不在编译的控制权限之内,不能自动执行构造函数和析构函数。

3. 多态

多态:不同继承关系的类对象去调用同一个函数时,产生不同的行为。
若要访问派生类中相同名字的函数,必须将基类中同名函数定义为虚函数,这样,将不同的派生类对象的地址赋值给基类指针变量后,就可以动态的调用不同类中的函数。

#include <iostream>
using namespace::std;
class Arm{
public:
    virtual void rotate(){ // 加virtual关键字 将该方法变为虚函数 子类重写该方法即可实现多态
        cout<<"rotate...\n";
    }
};


class BigArm:public Arm{
public:
    void rotate(){
        cout<<"quick rotate...\n";
    }
};

// 父类的引用指向子类的对象
void motor_rotate(Arm &obj){
    obj.rotate();
}

// 父类的指针指向子类的对象
void motor_rotate(Arm *obj){
    obj->rotate();
}


int main(){
    Arm ar;
    BigArm bar;
    motor_rotate(ar);
    motor_rotate(bar);
    
    Arm *arp = new Arm;
    BigArm *barp = new BigArm;
    motor_rotate(arp);
    motor_rotate(barp);
    
    return 0;
}

执行结果为:
在这里插入图片描述

4. 指针常量与常量指针

   int a = 10;
   int b =22;
   const int *p1 = &a;  // 常量指针
   cout<<p1<<endl;
//    *p= 100; // 指针所指向的值不能修改
   p1 = &b;
   cout<<p1<<endl;
   
   
   int c = 90;
   int d = 100;
   int * const p2 = &c; // 指针常量
   *p2 = 8888;
//    p2 = &d; // 指针的指向不能改变

5. new和malloc的区别:

  1. new/free是操作符,malloc/delete是库函数,需要引进相应的头文件才能使用。
void* malloc(size_t);
void free(void*);

void *operator new (size_t);
void operator delete (void *);
void *operator new[] (size_t);
void operator delete[] (void *);
  1. 使用new操作符申请内存分配时无须指定内存的大小,编译器会根据对象类型自动分配内存块的大小;malloc需要显式地指定内存的大小,malloc可以被remalloc
#include <iostream>
using namespace std;

int main(){
    char* str = (char*)malloc(sizeof(char*) * 6);
    strcpy(str, "hello");
    cout << str << endl;

    str = (char*)realloc(str, sizeof(char*) * 12);
    strcat(str, ",world");
    cout << str << endl;

    free(str);
}
  1. new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换;malloc内存分配成功是void *类型,需要强制转化我们自己需要的类型。new内存分配失败会报bad_alloc的异常,malloc内存分配失败返回NULL。
  2. 在实现方面,new会先调用operator new函数,申请足够的内存(通常底层采用malloc实现),然后调用构造函数初始化成员变量,最后返回自定义类型的指针;delete时先调用析构函数,然后调用operator delet释放内存(通常底层采用free实现)。
    mallo/free是库函数,只能动态地申请和释放内存,无法完成自定义类对象的构造和析构;new/delete允许重载,new不需要为对象分配内存,而是指定一个地址作为内存的起始区域,在这段内存上为对象调用构造函数完成初始化工作。
#include <iostream>
#include <stdio.h>
using namespace std;

class Player{
public:
    Player(){
        cout << "call Player::ctor\n";
    }

    ~Player(){
        cout << "call Player::dtor\n";
    }

    void Log(){
        cout << "i am player\n";
    }

};


int main(int argc, const char * argv[]) {
//    char s[40];
//    sprintf(s, "%s%d%c","hello",99,'c');
    

    cout << "Initiate by new\n";
    Player* p1 = new Player(); // new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换
    p1->Log();
    delete p1;

	cout<<"==============="<<endl;

    cout << "Initiate by malloc\n";
    Player* p2 = (Player*)malloc(sizeof(Player)); // malloc内存分配成功是void *类型,需要强制转化我们自己需要的类型。
    p2->Log();
    free(p2);
    
    
    return 0;
}

输出结果为:
在这里插入图片描述

  1. new操作符是从自由储存区为对象动态分配内存空间,malloc函数从堆上为对象动态分配存储空间。其中自由储存空间是C++基于new操做符的一个抽象概念,凡是通过new操作符进行申请的内存均为自由存储区。堆是操作系统OS维护的一段内存空间,用于动态分配内存,C语言使用malloc从堆上分配内存,使用free释放已分配的内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值