指针

1.        什么是地址?
利用&获得地址

2.        指针是什么?
指针用来保存内存地址的变量

3.        空指针的作用?
避免失控指针。
int *p=0;

4.        指针与类型
由于不同类型的变量内存中所占用的字节数不同,因此指针只可以用来保存与其类型相同的变量的地址。

5.        容易混淆的概念
指针地址&p
指针保存的地址p
该地址的值:(指针保存的地址处的值)*p

6.        typedef unsignedshort int  ut;  //typedef的作用
ut *p=0;

7.        cout<<”\t”;   //\t的作用

8.        为什么使用指针?
在操作大型数据时,由于指针可以通过内存地址直接访问数据,从而避免在程序中复制大量的代码,因此指针的效率最高。
指针一般有三大用途:
(1)处理堆中存放的大量数据
(2)快速访问类的成员数据和函数
(3)以别名的方式向函数传递参数
数据在内存中的存放共分为以下几个形式
(1)栈区-----由编译器自动分配并且释放,该区域一般存放函数的参数值、局部变量的值
(2)堆区----一般由程序员分配释放,若程序员不释放,程序结束时,可由操作系统回收。
(3)寄存器区---用来保存栈顶指针和指令指针
(4)全局区(静态区static----全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由系统释放。
函数参数和局部变量存放在栈中,当函数运行结束并且返回时,所有的局部变量和参数就都被系统自动清除掉了,为了是释放掉,他们所占用的内存空间。全局变量可解决这个问题,但是全局变量永远不会被释放,而且由于全局变量被所有的类成员和函数所共享,所以它的值很容易被修改。使用

堆可以一举解决这两个问题。
 (1)栈中数据寿命短
(2)数据安全性,全局区不安全(很容易被修改)
堆为什么可以解决这两个问题
(1)堆是采用匿名的方式来保存数据的,你只能通过指针才能访问到这些匿名的数据,因此他的安全性好。
(2)同时由于堆区中的内存是由程序员分配和释放的,所以它的自由度也是最高的。
堆和栈的区别
1:内存申请方式上-------------栈是由系统自动分配,例如:我们在函数中声明一个局部                          变量int a,那么系统就会自动在栈中为变量a开辟空间。
                        堆需要程序员自己申请,因此也需要指明变量的大小。
2:系统响应不同----------------只要栈的剩余空间大于所申请空间,系统将为程序提供内存,系统将提示overflow,也就是栈溢出。
                       系统收到程序申请空间的要求后,会遍历一个操作系统用于记录内存空闲地址的链表,当找到一个空间大于所申请空间的堆结点后们就会将该结点从记录内存空闲地址的链表中删除。并将该结点的内存分配给程序,然后在这块内存区域的首地址处记录分配的大小。这样我们在使用delete来释放内存的时候,delete才能正确地识别并删除该内存区域的所有变量,另外,我们申请的内存空间与堆结点上的内存空间不一定相等,这时系统就会自动地将堆结点上多出来的那一部分内存空间回收到空闲链表中。
3;空间大小的不同--------------在windows下,栈是一块连续的内存区域,他的大小是2M,也有的说是1M,总之该数值是一个编译时就确定的常数,是由系统预先根据栈顶的地址和栈的最大容量定义好的,假如你的数据申请的内存空间超过栈的空间,那么就会提示overflow,因此别指望栈能存储比较大的数据。
                        堆是不连续的内存区域,各块区域由链表将他们串联起来,关于链表的知识将在后面的章节中讲解,这里只需要知道链表将各个不连续的内存区域连接起来你,这些串联起来的内存空间叫做堆,它的上限是由系统中有效的虚拟内存来决定,因此获得的空间比较大,而获得空间的方式比较灵活。
4:执行效率的不同-------------:由系统自动分配,因此速度比较,但是程序员不能对其进行操作
                         :是由程序员分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来很方便。
5:执行函数的不同-------------栈:在函数调用时,第一个进栈的是被调用函数下一行的内存地址,其次是函数的参数,假如参数多于一个,那么次序从右往左,最后才是函数的局部变量。
由于栈的先进后出原则,函数结束时,正好与其相反,首先是局部变量先出栈,然后是参数,次序是从左往右,这时所有的变量都已出栈,指针自然地指到第一个进栈的那行内存地址,也就是被调入函数的下一行地址,程序根据该地址跳转到被调用函数的下一行自动执行。
由于栈的先进后出原则,所以永远都不可能产生内存碎片
函数的局部变量

函数的参数
被调用函数下一行的内存地址
                        堆:堆是一个不连续的内存区域,在系统中由链表将他们串接起来,因此在使用的时候必须由程序员来安排,他的机制很复杂,有时候为了分配一块合适的内存,程序员需要按照一定的算法在堆中搜索可用的足够大小的内存区域,如果没有满足条件的空间,那么就要向系统发出申请,怎家一个部分内存空间,这样才有机会分配到足够大小的内存,然后将计算的数值返回,显然,堆的运行效率要比栈很多,而且容易产生碎片,但是好处是堆可以存储相大的数据,并且一些细节也可以由程序员来安排。
6:总节------------------从上面可以看出,栈的内存小,但是效率高,但是效率高,不过存储的数据只在函数就消失了,堆的可存储空间可非常大,但是容易产生内存碎片,效率也较低,好处是灵活性比较强。比如说我们需要创建一个对象,能够被多个函数所访问,但是又不想使其成为全局的,那么这个时候创建一个堆对象无疑是良好的选择。
由于堆和栈各有优缺点,因此好多时候我们是将堆和栈结合使用的,比如在存储一些较大数据的时候,我们将数据存放在堆中,却将指向该数据的指针放到栈中,这样可以有效地提高程序的执行速度,避免一些不该有的碎片。不过,一般来说,加入不是特大的数据,我们都是使用栈,比如:函数调用过程中的参数,返回地址、局部变量都存放到栈中,这样可以大大加快程序的运行速度。

 

 

9.4指针与堆

堆的好处:(1)可以存储比较大的数据

        (2)存储的数据只要不是程序员手动将其释放,那么就会永远保存在堆中。

         (3)采用这种匿名的内存访问方式,只有使用特定的指针才能访问特定的数据,这样就避免了任何试图修改它的非法操作。

堆的特点:为了数据隐秘起见,堆中的每个内存单元都是匿名的,因此你必须先在堆中申请一个内存单元的地址,然后把它保存在一个指针中,这样子你只要使用该指针才可以访问到该内存单元的数据。

在栈中:(1)存储的数据只在函数内有效,超出函数就消失了。

      (2)你可以为它其中的某个内存单元命名

全局变量:保存的数据只有程序结束才会释放,而且容易被修改

 

int *p=new int;

 

注意:由于你的计算机的内存是有限的,因此可能会出现没有足够内存而无法满足new的请求,在这种情况下,new会返回0,该值被赋给指针后,那么该指针就是一个空指针,空指针不会指向有效数据。new除了返回空值之外,还会引发异常。

 

9.5用指针删除堆中空间

问题:由于使用new创建的内存空间不会被系统自动释放,因此假如你不去释放它,那么该区域的内存将始终不能为其他数据所使用,而指向该内存的指针是个局部变量,当定

义该指针的函数结束并返回时,指针也就消失了,那么我们就再也找不到该块内存区域。

内存泄露:计算机再也找不到该区域的内存了,就好像丢失了这块内存一样。

方法:假如你不需要一块内存空间,那么就必须对指向它的指针使用关键字delete。

 

int *p=new int;

delete p; //这将释放指针所指向的内存,而不会释放指针,因此你还可以使用该指针

 

int *p=new int;

delete p;

delete p; //因为p所指向的内存区域已经释放,如果再进行释放,将会使程序崩溃

 

int *p=new int;

delete p;

p=0;

delete p; //不过,假如我们将该指针赋为0的话,那么删除一个空指针将是安全的。

 

10:内存泄露

 

11:在堆中创建对象

 

Human *p; //定义了一个Human类的指针p

p=new Human;//使用new创建一块内存空间,同时又调用了Human类的默认构造函数来构造一个对象,它所占用的内存大小根据Human类对象的成员变量来决定。

 

构造函数:一般是在创建对象时被自动调用,它的作用就是初始化该对象的成员数据。


12:在堆中删除对象


13:访问堆中的数据成员

Human *p=new Human;

(*p).get();   //使用括号是为了保证先使用*号读取p的内存地址中的值,即堆中对象,然后再使用成员运算符”.”来访问成员函数get()。

 

但是这样做会比较麻烦,因此c++专门为用指针来间接访问对象的成员设置了一个运算符---成员指针运算符“-à”.该符号可以实现读取对象的内存地址并且访问该对象的成员的作用。

p->get();

 

14:在构造函数中开辟内存空间

我们可以将类的数据成员定义为一个指针,然后在构造函数中开辟新空间,将该空间的地址赋给指针。而在析构函数中释放该内存。


在析构函数中还有一个 delete I;

15:对象在栈与堆中的不同:会不会自动的调用析构函数。


而一个存储在堆中的对象,如:new Human;

则需要程序员自行对其所占用的内存进行释放。否则该对象所占用的内存直到程序结束才会被系统回收。


16:this指针

this变量记录每个对象的内存地址,然后通过间接访问运算符—>访问该对象的成员。


这说明this变量记录每个单独的对象的内存地址,而this指针则指向每个单独的对象。因此不同的对象输出的this变量的内存地址也不同。

 

17:指针的常见错误

前面我们说过删除一个指针后一定要将该指针设置为空指针,这是因为删除该指针只会释放它所指向的内存空间,不会删除指针,因此这个指针还存在,并且它仍然会指向原来的内存空间,因此这时如果你再次尝试使用该指针,那么将会导致程序出错。

18.1常量指针

int * const p=&a; //它只可以指向该块内存区域,但是区域中的值是可以改变的,常量指针必须初始化。

 

18.2 指向常量的指针

const int *p;  //这块区域中值不可以改变,但是指针p可以改变去指向其他的区域

 

19指针总结

   指针可以通过内存地址间接访问数据,每个变量都有自己的地址,我们可以通过取址运算符(&获得他们的地址,他们的地址可以存储在指针变量中,我们可以通过间接运算符(*读取指针指向地址的值。

   指针的类型必须与它所指向的目标相一致,指针未被初始化一个内存地址或刚刚删除一个指针都要将该指针赋为0,否则的话将会导致该指针失控。

   加入不想改变指针,那么将该指针定义为const,假如不想改变指针指向的值,将指针指向的值定义为const,加入不想改变指针也不想改变指针指向的值,那么把指针和指针指向的值都定义为const。

   用new在堆中可以创建一个对象,然后将内存地址赋给指针,之后我们就可以通过该指针访问堆中的对象,加入要删除该对象,我们只需要对指针使用关键字delete,那么就会删除指针指向的对象并释放存储该对象的内存空间。但是我们要注意一点,指针并没有被删除,并且它仍然指向原来的内存空间,因此我们必须对它的内存地址清0或者重新赋值。

 

 

关键字:栈、堆、全局变量、内存泄露、对象在栈与堆中的不同

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值