10:
数组对象:
Humana[2];
十一:
指针
1:
typeddfunsignedshortintut;相当于#define
2:
为什么使用指针:
a.处理堆中存放的大型数据
b.快速访问类的成员数据和函数
c.以别名的方式向函数传递参数
3:
栈和堆:
一般来说,程序就是与数据打交道,在执行某一功能的时候,将该功能所需要的数据加载到内存中,然后在执行完毕的时候释放掉该内存
数据在内存中的存放共分为以下几个形式:
a.栈区(stack)--由编译器自动分配并且释放,该区域一般存放函数的参数值、局部变量的值等.
b.堆区(heap)--一般由程序员分配释放,若程序员不释放,程序结束时可能被操作系统回收.
c.寄存器--用来保存栈顶指针和指令指针.
d.全局区(静态区)(static)--全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域.程序结束后由系统释放.
e.文字常量区--常量字符串就是放在这里的,程序结束后由系统释放
f.程序代码区--存放函数的二进制代码
4:
为什么使用堆:
函数参数和局部变量存放在栈中,当函数运行结束并且返回时,所有的局部变量和参数就都被系统自动清除了,
为的是释放掉他们所占用的内存空间.全局变量可以解决这个问题,但是全局变量永远不会被释放,而且由于全局变量
被所有的类成员和函数所共享,所以它的值很容易被修改.使用堆可以一举解决这两个问题.
优点:
堆是采用匿名的方式来保存数据的,只能通过指针才能访问到这些匿名的数据,因此它的安全形势最好的,
同时由于堆区中的内存是由程序员来分配和释放的,所以它的自由度也是最高的.
5:
堆与栈内存申请方式的不同
栈:
由系统自动分配,例如我们在函数中声明一个局部变量inta,那么系统就会自动在栈中为变量a开辟空间.
堆:
需要程序员自己申请,因此也需要指明变量大小
6:
堆与栈系统响应的不同
栈:
只要栈的剩余空间大于所申请空间,系统为程序提供内存,否则将提示overflow,也就是栈溢出
堆:
系统收到程序申请空间的要求后,会遍历一个操作系统用于记录内存空闲地址的链表,当找到一个空间大于所申请空间的堆结点后,
就会将该结点从记录内存空闲地址的链表中删除,并将该节点的内存分配给程序,然后在这块内存区域的首地址处记录分配的大小,
这样我们在使用delete来释放内存的时候,delete才能正确地识别并删除该内存区域的所有变量,另外,我们申请的内存空间与堆结点
上的内存空间不一定相等,这时系统就会自动将堆结点上多出来的那一部分内存空间回收到空闲链表中.
7:
堆与栈空间大小的不同
栈:
在windows下,栈是一块连续的内存区域,它的大小是2M,也有的说是1M,总之该数值是一个编译时就确定的常数.是由系统预先根据栈顶
的地址和栈的最大容量定义好的.假如你的数据申请的内存空间超过栈的空间,那么就会提示overflow.因此,别指望栈能存储比较大的数据
堆:
堆是不连续的内存区域.各块区域由链表将它们串联起来,关于链表的知识将在后面的章节中讲解,这里只需要知道链表将各个不连续的内存区域
连接起来,这里串联起来的内存空间叫做堆,它的上限是由系统中有效的虚拟内存来定的.因此获得的空间比较大,而且获得空间的方式也比较灵活.
8:
堆与栈执行效率的不同
栈:
栈由系统自动分配,因此速度较快.但是程序员不能对其进行操作
堆:
堆是由程序员分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来很方便
9:
堆与栈执行函数是不同
栈:
a.在函数调用时,第一个进栈的是被调用函数下一行的内存地址,其次是函数的参数,假如参数多于一个,那么次序是从右往左,最后才是函数的局部变量
b.由于栈的先进后出的原则,函数结束时正好与其相反,首先是局部变量先出栈,然后是参数,次序是从左到右,这时所有的变量都已出栈,指针自然地指到
第一个进栈的那行内存地址,也就是被调函数的下一行内存地址.程序根据该地址跳转到被调函数的下一行自动执行
c.由于栈的先进后出原则,所以它永远都不可能产生内存碎片,因为上面的盘子没有拿完之前,下面的盘子是不可能抽出的,他们排列的是如此有序,
弹出时也非常有序,碎片想要产生也是非常艰难的.
堆:
堆是一大堆不连续的内存区域,在系统中由链表将它们串接起来,因此在使用的时候必须由程序员来安排.它的机制是很复杂的,有时候为了分配一块合适的内存,
程序员需要按照一定的算法在堆内存中搜索可用的足够大小的空间,如果没有满足条件的空间,那么就要向系统发出申请增加一部分内存空间,这样就才有机会分
到足够大小的内存,然后将计算后的数值返回.显然,堆运行效率比栈要低得多,而且也容易产生碎片,但是好处是堆可以存储相当大的数据,并且一些细节也可以由程序员来安排.
10:
堆的使用
a.堆是一大堆不连续的内存区域,在系统中由链表将它们串接起来,它不像栈,你可以为他其中的某个内存单元命名,为了数据隐秘起见,堆中的每个内存单元都是匿名的,因此你必须先在堆中申请
一个内存单元的地址,然而把它保存在一个指针中.这样你只要使用该指针才可以访问到该内存单元的数据.
b.采用这种匿名的内存方式,而不是使用公开的全局变量,好处是只有使用特定的指针才能访问特定的数据.这样就避免了任何试图修改它的非法操作.
11:
创建堆
a.首先创建一个堆,然后定义一个指向该堆的指针.这样就只能通过该指针才能访问堆中数据
b.在C++中使用关键字new创建一个堆并分配内存,在new后面跟一个要分配的对象类型,编译器根据这个类型来分配内存.
c.例子:
int*p;
p=newint(会返回一个地址);在堆中创建了4个字节内存
12:
用指针删除堆中的空间
a.由于使用new创建的内存空间不会被系统自动释放,因此假如你不去释放它,那么该区域的内存将始终不能为其他数据所使用,
为指向该内存的指针是个局部变量,当定义该指针的函数结束并返回时,指针也就消失了,计算机就再也找不到该区域的内存了,就好像丢失了一样,
我们把这种情况叫做内存泄露.所以就必须用delete(deletep)最好给它清零(p=0)
b.内存泄漏:
int*p=newint;
//deletep;
int*p=newint;
13:
在堆中创建对象Human*p=newHuman;
第二行使用new创建一块内存空间,同时有调用了Human类的默认构造函数来构造一个对象,他所占用的内存大小根据Human类对象的成员变量来决定,假如该类有两个int型成员变量,那么该对象占用
为2乘以4等于8个字节.构造函数一般都是在创建对象时被自动调用,它的作用就是初始化该对象的成员数据.本行的右半部分创建一个对象完毕后,跟着将该对象的内存地址赋给左边的指针变量p.
注意:
在堆只创建对象是匿名的,它没有名字,我们无法直接访问它,只能通过指针来访问它.
14:
在堆中删除对象
直接删除指向该对象的指针,这样会自动调用对象的析构函数来销毁该对象同时释放内存.
15:
访问堆中的数据成员
a.我们要访问对象的数据成员和函数,我们使用成员运算符"."
b.(*p).get();使用括号是为了保证先使用*号独缺p的内存地址中的值,即堆中对象,然后再使用成员运算符"."
来访问成员函数get().
c.成员指针运算符"->".p->.get()该符号可以实现读取对象的内存地址并且访问该对象的成员的作用.
16:
在构造函数中开辟内存空间
a.我们可以将类的数据成员定义为一个指针,然后在析构函数中开辟新空间,将该空间的地址赋给指针.而在析构函数中释放该内存.
b.private:
int*p;Human(){p=newint(999)}
c.一个在堆中创建的对象通过成员指针在创建新的空间用来保存数据并没有什么意义.因为在堆中创建对象时已经为它的所有数据成员提供了保存空间.
17:
this指针
a.对象要在属于自己的每个成员身上写下自己的名字,以证明该成员是自己的成员,而不是别的对象的成员.
this变量帮助对象做到这一点,this变量记录每个对象的内存地址,然后通过间接访问运算符->访问该对象的成员.
b.这说明this变量记录每个单独的对象的内存地址,而this指针则指向每个单独的对象.因此不同的对象输出的this变量的内存地址也不同.
c.由于this指针保存了对象的地址,因此你可通过该指针直接读取某个对象的数据,它的作用将会在后面的重载运算符中得到演示,现在我们只需要知道
this变量保存的是对象的地址,那么this指针就是指向对象的指针.另外this指针的创建与删除由编译器来完成.
d.需要注意的地方:
因此在删除一个指针后,我们一定要将其赋为空.虽然使用空指针是非法的,容易使程序崩溃,但是我们宁愿程序崩溃,也不愿意调试起来困难.
由于这程序运行以后立即崩溃了,而空指针使用不当又会导致程序崩溃,因此我们立即明白是哪里出了错,从而迅速纠正它.
18:
指针的各种常量
a.int*constp;常量指针,他自身的值是不可改变的,但是它指向的目标却是可以改变的.
b.constHuman*p指向常量的指针,只是限制我们修改它指向的目标,他自身是可以被修改的.
c.constHuman*constp;指向常量的常指针,都不可修改.
十二:
引用
1:
什么是引用