C++常见知识点总结

1.new、delete、malloc、free的区别和联系
malloc/free
使用示例,

    int length = 32;
    int *p = (int*)malloc(sizeof(int)*length);
    ......
    if (p)
        free(p);

malloc的返回值是void*,所以在调用时要显式地进行类型转换,将其转换为所需要的指针类型。

new/delete

    int *p = new int[10];

    if (p)
        delete []p;//不可以漏掉[],否则相当于delete p[0]

两者的区别和联系
new/delete是C++的运算符,会调用对象的构造函数和析构函数;malloc/free是C++/C语言的标准库函数。两者都可以用于申请动态内存和释放内存。但是对于非内部数据类型的对象而言,malloc/free是无法满足动态对象的要求的,即对象在创建时自动执行构造函数,对象在消亡时自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够将执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。



2.子类/基类 构造函数和析构函数的调用顺序。
定义一个对象时,先调用基类的构造函数,然后再调用继承类的构造函数。而析构的时候恰好相反,先调用继承类的析构函数,然后再调用基类的析构函数。


3.引用作为函数参数使用
引用是指一个变量的别名,如,

    //test
    double num1 = 1;
    //变量num2是变量num1的别名,但没有复制num1,两者指向同一块内存,如果改变其中一个变量,另一个变量的值也会发生相应的改变
    double &num2 = num1;

需要注意的是,引用在定义的时候一定要初始化。
引用在函数传参时,具有重要作用。函数参数传递有值传递和引用传递两种,值传递在函数内部的操作不会对实参进行任何改变,而引用传递中的形参相当于是实参的一个别名,所以在函数中对形参的任何操作相当于对原实参的操作,如下所示,

void swap1(int x, int y){//值传递,实参变量值不发生改变
    int temp = x;
    x = y;
    y = temp;
}
void swap1(int x, int y){//值传递,实参变量值不发生改变
    int temp = x;
    x = y;
    y = temp;
}
void swap2(int &x, int &y){//引用传递,实参变量值交换
    int temp = x;
    x = y;
    y = temp;
}
void swap3(int *x, int *y){//指针传递,实参变量值交换
    int temp = *x;
    *x = *y;
    *y = temp;
}
void main{
    int x = 1, y = 2;
    swap1(x, y);
    swap1(x, y);
    swap1(&x, &y);
}

当以引用传参时,常使用const关键字,避免在函数中对参数数值的修改,有助于提高程序的可靠性,如,

void function(const int &x){...}

引用也可以在函数返回中被使用,这时候并没有复制返回值,二是返回对象的引用(即对象本身)。当函数使用引用返回时,可以是返回全局变量的引用,或者是在函数的形参表中有引用或者指针,这两者有一个共同点,就是函数返回时该变量依然存在,此时的引用才有意义。相比之下,是万万不可以将函数内部定义的局部变量返回的,因为函数调用时,函数内部定义的局部变量也会随之被撤销,那么此时返回的引用是没有意义的!下面举出一个返回函数引用的例子,

int& function(int a, int b, int &result){
    result = a + b;
    return result;
}

另外,如果不希望返回的对象被修改,可以在返回时加const修饰,如,

const int& function(int a, int b, int& result){
    .....
}
void main(){
int re;
function(1, 2, &re)++;//WRONG!
}

此时返回对象是不可以被修改的!



4.C++内存分配方式
主要有三种内存分配方式:静态区存储区、栈上创建和堆上分配。其中,静态存储区是程序编译的时候就已经分配好了,并且在程序的整个运行期间都存在,如全局变量,static变量;在执行函数时,函数内部的局部变量的存储单元在栈上创建,函数执行结束后,这些存储单元自动被释放;程序在运行的时候使用malloc或者new申请的内存,并且由程序员自己负责使用free和delete释放内存的变量是存放在堆上的。下面列举一个小例子,说明其中用到的变量的存储位置。

//main.cpp
int a = 0;//静态区
char *p1;//静态区
void main(){
    int b;//局部变量,栈区
    char *p2;//栈区
    char *p3 = "123";//123/0存放在常量区,p3在栈区
    p1 = (char*)malloc(10);//堆区
    p2 = (char*)malloc(20);//堆区
}

栈是由高地址向低地址扩展的数据结构,是一块连续的内存区域,主要是因为栈的大小通常是系统预先设定的(如2M),如果申请的空间超过栈的剩余空间时,将提示栈溢出。而堆是由低地址向高地址扩散的数据结构,用链表来存储空闲的内存地址,所以是不连续的内存区域,堆的大小受限于计算机系统中有效的虚拟内存。栈由系统自动分配,速度较快,但程序员是无法控制的;堆分配,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。



5.指针
基本用法,

int num = 42;
int *p1 = #//定义一个指针p,并将num变量的内存地址赋给指针p,也就是说p中保存着变量num的地址,这样p可以指向变量num
int *p2 = new int[10];//将new分配的地址的首地址赋给指针p2

获取指针所指向对象的值的方式,

cout<<*p;

初始化指针

int *p1 = 0;
int *p2 = NULL;//与使用0初始化指针是一样的效果
if(p1)//判断指针是否有效,此时返回false;只要指针的地址有效,则返回true
...

void指针

int num = 42;
void *p = &num;//正确;void*可以存放任意类型对象的地址

指向指针的指针

int n1 = 42;
int *p1 = &n1;//指针p1存放的地址为变量n1的地址
int **p2 = &p1;//指针p2存放的地址为p1指针变量的地址,可以通过**p2获取到最终指向的对象n1的值



6.struct结构体
struct是一种复合数据类型,其构成元素既可以是基本数据类型(如int,short等),也可以是复合数据类型(如struct,union等)。对于结构体,编译器会自动进行成员变量的对齐,以提高运算效率,缺省情况下,编译器会为结构体的每个成员按照所有成员中size最大的大小进行对齐,如,

struct va{//按照4字节对齐,所以struct占总的空间大小为12字节
char a;//1字节
short b;//2字节
int c;//4字节
}



可参考 http://blog.csdn.net/wdzxl198/article/details/9102759/

如有问题,欢迎指正~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值