指针作函数参数,引用作函数参数以及内存释放

指针作为函数参数

1.  函数参数概念:

       形参:被调函数中的参数

       实参:主调函数中的参数

       形参和实参:
       C 中函数中实参和形参是按值传递的,调用函数后,会将实参的值拷贝给形参(即形参和实参之间是没有关系的,只是它们的值是相同的)。在被调函数中不可以改变实参的值, 同样形参定义在被调函数中,在整个函数体内都可以使用, 离开该函数则不能使用。

       (1) 形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元。

       (2) 在进行函数调用时,实参都必须具有确定的值,以便把这些值传送给形参。

       (3) 实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量。

       (4) 实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。

2.  指针作函数参数使用 

        实际编程中,经常要改动传入参数的值。这时,我们需要使用指针作为实参,用指针作为参数,即传入的是参数的地址而不是参数本身,形参中拷贝的也是内存地址,当对形参去(*)运算时,就可以得到指针实参所指向的值,改变该地址就可以直接改变实参所指向的值

        C中函数的变量是局部变量,也就是说主用函数与被调用函数的实参和形参在内存中占用的是不同的存储空间,但它们内存空间中的值是相同的。当指针作为函数参数时,它们的内存空间中即存储着相同的内存地址(指向另一块内存空间),所以取(*)运算之后,它们的值是相同的,并且是同一块地址中的值。

       这也就是我们在实际编程中会看见某些C函数会用到char ***的原因(一般编程,char** 已经够用了),它只是把想把char** 传入函数中,赋值之后返回。

main()
{
   int i;
   MyFun(&i);
}
MyFun(int *p)
{
   (*p) = 2;
}

       在上面简单的程序中&i则是i的地址,传入被调函数后,指针p所指向的内存地址即i的地址,(*p)则就是i,所以函数执行后i也会变成2。并且这里i是编译器自动对其进行了初始化,并分配了内存,所以&i是有值的(实参必须有确定的值)。

 3. 引用概念

      定义引用使用&符号。引用只在C++中可以使用,C中没有引用的概念。

      引用等于是对象的另一个名字,与原对象一模一样,并都指向同一块内存地址。

int a = 5;
int & b = a;

      这里定义了引用b,它就是a的一个别名,那么a=6和b=6效果是一样的。
      定义引用时应注意:

            1).  定义引用是必须给它初始化,并且不能初始化NULL,int &b;这样的定义是不正确的。

            2).  引用并不是对象的拷贝,也不是指针。

            3).  &这里并不是取地址,它只是代表引用。

           4).   引用不是一种数据类型,所以没有引用的引用,没有引用的指针。

4. 引用作函数参数

       实际编程中,要经常要改动传入参数的值,除了使用指针,还可以使用引用。这时,我们需要使用变量或类对作为实参,用引用作为形参,则形参和实参就是一样的。改变形参后,实参的值也会改变。

主调函数: 
void main(void)
{ 
   String str(_T"Hello World!");  
     Fun(str);  
 }
被调函数:  
void Fun(String & Ref_str)  
{  
......  
}  

 

在Fun函数中改变形参的话,实参也会跟着改变。
 
5. 内存概念
     在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区.
  1.       栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。
  2.       堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。在源程序里,堆里的变量等都是没有名字的,它们是通过指针被访问的。在堆区里生成变量的过程称为动态内存分配。
  3.       自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
  4.       全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
  5.       常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)。

       内存泄漏,用动态存储(new,malloc)分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。即所谓内存泄漏。如果程序一直执行,则长时间之后,会内存耗尽,发生死机等现象。

6. 内存释放

       在栈中的变量所占内存会自动释放,就像第二节中的局部变量i,由编译器自动进行了初始化,并分配了内存空间以存放 i 的值,在main函数结束时,变量i会自动释放其在栈内存中所占的空间。栈中内存由编译器自己控制,程序员可以不用管它,只管定义和使用即可。

      但是new出来的内存空间存储在堆内存空间中,它们则不会自动释放。例如,如果是int *a = new int,(*a)是动态分配的内存单元,a是指向该内存单元的指针,则函数执行完成后,(*a)所占的内存空间则不会自动释放,如果要释放该内存空间,必须使用

delete a,否则会出现内存泄露。 而int a;就不存在这种问题,程序会自动回收内存的。所以堆中内存由程序员来控制,在用new初始化内存空间后,需要考虑在什么时候去释放它。

       malloc分配的内存则需要由free();来释放内存空间。

       另外,需要注意的是 delete(&),参数是一个地址。假如有个指针p,delete(p)释放的是p所指向的内存,p指针并没有释放,p指针这时是个野指针;但p还是指向那个地址,如果那块内存被其他程序使用了,再用*p来修改其内容,这样对程序来说是非常危险的事,所以我们在delete删除指针所指向内存后,会加上p = NULL; 使指针指向为空。

int *p = new int;
.....
.....
delete p;
p = NULL;

       再需要注意的一个地方,delete p;实际上只是将p所指向的内存空间标记为可使用,让其他程序去使用该内存空间,并没有删除内存空间中所存储的数据,在该内存被其他程序使用之前 (*p)还是原来的值

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值