数组下标运算实际上都是经过指针进行的。
数组名表明着指向该数组中下标为0的元素的指针,但有例外:sizeof(数组名)返回整个数组的大小,而非指针大小;&数组名返回一个指向数组的指针,而不是指向该数组中下标为0的元素的指针的指针。
数组名做为参数时,数组名会被转换成指向该数组下标为0的元素的指针。
指针操做可能比下标操做效率高,但可维护性却不必定有下标操做好。
数组和指针不相等。数组
野指针就是指向一个已删除的对象或者未申请访问受限内存区域的指针安全
智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。C++ 11中最经常使用的智能指针类型为shared_ptr,它采用引用计数的方法,记录当前内存资源被多少个智能指针引用。该引用计数的内存在堆上分配。当新增一个时引用计数加1,当过时时引用计数减一。只有引用计数为0时,智能指针才会自动释放引用的内存资源。对shared_ptr进行初始化时不能将一个普通指针直接赋值给智能指针,由于一个是指针,一个是类。能够经过make_shared函数或者经过构造函数传入普通指针。并能够经过get函数得到普通指针。app
当两个对象相互使用一个shared_ptr成员变量指向对方,会形成循环引用,使引用计数失效,从而致使内存泄漏。函数
为了解决循环引用致使的内存泄漏,引入了weak_ptr弱指针,weak_ptr的构造函数不会修改引用计数的值,从而不会对对象的内存进行管理,其相似一个普通指针,但不指向引用计数的共享内存,可是其能够检测到所管理的对象是否已经被释放,从而避免非法访问。指针
将可能会被继承的父类的析构函数设置为虚函数,能够保证当咱们new一个子类,而后使用基类指针指向该子类对象,释放基类指针时能够释放掉子类的空间,防止内存泄漏。
C++默认的析构函数不是虚函数是由于虚函数须要额外的虚函数表和虚表指针,占用额外的内存。而对于不会被继承的类来讲,其析构函数若是是虚函数,就会浪费内存。所以C++默认的析构函数不是虚函数,而是只有当须要看成父类时,设置为虚函数。对象
析构函数与构造函数对应,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统会自动执行析构函数。
析构函数名也应与类名相同,只是在函数名前面加一个位取反符~,例如~stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。
若是用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即便自定义了析构函数,编译器也老是会为咱们合成一个析构函数,而且若是自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它也不进行任何操做。因此许多简单的类中没有用显式的析构函数。
若是一个类中有指针,且在使用的过程当中动态的申请了内存,那么最好显示构造析构函数在销毁类以前,释放掉申请的内存空间,避免内存泄漏。
类析构顺序:1)派生类自己的析构函数;2)对象成员析构函数;3)基类析构函数。继承
静态函数在编译的时候就已经肯定运行时机,虚函数在运行的时候动态绑定。虚函数由于用了虚函数表机制,调用的时候会增长一次内存开销生命周期
重载:两个函数名相同,可是参数列表不一样(个数,类型),返回值类型没有要求,在同一做用域中
重写:子类继承了父类,父类中的函数是虚函数,在子类中从新定义了这个虚函数,这种状况是重写进程
strcpy是字符串拷贝函数,原型:
char strcpy(char dest, const char *src);内存
从src逐字节拷贝到dest,直到遇到'\0'结束,由于没有指定长度,可能会致使拷贝越界,形成缓冲区溢出漏洞,安全版本是strncpy函数。
strlen函数是计算字符串长度的函数,返回从开始到'\0'之间的字符个数。
多态的实现主要分为静态多态和动态多态,静态多态主要是重载,在编译的时候就已经肯定;动态多态是用虚函数机制实现的,在运行期间动态绑定。举个例子:一个父类类型的指针指向一个子类对象时候,使用父类的指针去调用子类中重写了的父类中的虚函数的时候,会调用子类重写事后的函数,在父类中声明为加了virtual关键字的函数,在子类中重写时候不须要加virtual也是虚函数。
虚函数的实现:在有虚函数的类中,类的最开始部分是一个虚函数表的指针,这个指针指向一个虚函数表,表中放了虚函数的地址,实际的虚函数在代码段(.text)中。当子类继承了父类的时候也会继承其虚函数表,当子类重写父类中虚函数时候,会将其继承到的虚函数表中的地址替换为从新写的函数地址。使用了虚函数,会增长访问内存开销,下降效率。
++i先自增1,再返回,i++先返回i,再自增1
常量在C++里的定义就是一个top-level const加上对象类型,常量定义必须初始化。对于局部对象,常量存放在栈区,对于全局对象,常量存放在全局/静态存储区。对于字面值常量,常量存放在常量存储区。
首先,new/delete是C++的关键字,而malloc/free是C语言的库函数,后者使用必须指明申请内存空间的大小,对于类类型的对象,后者不会调用构造函数和析构函数
子类若重写父类虚函数,虚函数表中,该函数的地址会被替换,对于存在虚函数的类的对象,在VS中,对象的对象模型的头部存放指向虚函数表的指针,经过该机制实现多态。
每个函数调用都会分配函数栈,在栈内进行函数执行过程。调用前,先把返回地址压栈,而后把当前函数的esp指针压栈。
父进程产生子进程使用fork拷贝出来一个父进程的副本,此时只拷贝了父进程的页表,两个进程都读同一块内存,当有进程写的时候使用写实拷贝机制分配内存,exec函数能够加载一个elf文件去替换父进程,今后父进程和子进程就能够运行不一样的程序了。fork从父进程返回子进程的pid,从子进程返回0.调用了wait的父进程将会发生阻塞,直到有子进程状态改变,执行成功返回0,错误返回-1。exec执行成功则子进程重新的程序开始运行,无返回值,执行失败返回-1
静态函数在编译的时候就已经肯定运行时机,虚函数在运行的时候动态绑定。虚函数由于用了虚函数表机制,调用的时候会增长一次内存开销
在C++中,虚拟内存分为代码段、数据段、BSS段、堆区、文件映射区以及栈区六部分。
代码段:包括只读存储区和文本区,其中只读存储区存储字符串常量,文本区存储程序的机器代码。
数据段:存储程序中已初始化的全局变量和静态变量
bss 段:存储未初始化的全局变量和静态变量(局部+全局),以及全部被初始化为0的全局变量和静态变量。
堆区:调用new/malloc函数时在堆区动态分配内存,同时须要调用delete/free来手动释放申请的内存。
映射区:存储动态连接库以及调用mmap函数进行的文件映射
栈:使用栈空间存储函数的返回地址、参数、局部变量、返回值
32bitCPU可寻址4G线性空间,每一个进程都有各自独立的4G逻辑地址,其中0~3G是用户态空间,3~4G是内核空间,不一样进程相同的逻辑地址会映射到不一样的物理地址中。其逻辑地址其划分以下: 各个段说明以下: 3G用户空间和1G内核空间 静态区域: text segment(代码段):包括只读存储区和文本区,其中只读存储区存储字符串常量,文本区存储程序的机器代码。 data segment(数据段):存储程序中已初始化的全局变量和静态变量 bss segment:存储未初始化的全局变量和静态变量(局部+全局),以及全部被初始化为0的全局变量和静态变量,对于未初始化的全局变量和静态变量,程序运行main以前时会统一清零。即未初始化的全局变量编译器会初始化为0 动态区域: heap(堆):当进程未调用malloc时是没有堆段的,只有调用malloc时采用分配一个堆,而且在程序运行过程当中能够动态增长堆大小(移动break指针),从低地址向高地址增加。分配小内存时使用该区域。 堆的起始地址由mm_struct 结构体中的start_brk标识,结束地址由brk标识。 memory mapping segment(映射区):存储动态连接库等文件映射、申请大内存(malloc时调用mmap函数) stack(栈):使用栈空间存储函数的返回地址、参数、局部变量、返回值,从高地址向低地址增加。在建立进程时会有一个最大栈大小,Linux能够经过ulimit命令指定。