(另:关于“引用”更具体的讨论。见此。)

由做UVa133引发的一系列问题及讨论

1.引用类型    C++ Primer P51

引用就是对象的还有一个名字,使用多个变量名指向同一地址。

实际程序中。引用主要用作函数形參。

复合类型。不能定义引用类型的引用,但能够定义不论什么其它类型的引用。

格式: 类型名&  标示符=已声明的常变量;

2.引用形參    C++ Primer P201-205

非引用形參有普通的、指针形參、const形參(可传const对象或非const对象)

引用形參,3种情形:@改动实參,或返回多个值  @避免复制大型对象  @没办法实现对象的复制 (唯一目的是避免复制时应使用更灵活的const型引用形參,由于非const型引用形參不太灵活)

3.指针形參与指向指针的引用形參

在UVa133中,定义 Node* CreateList(Node* &head, int n) ,假设不用引用形參则是 Node* CreateList(Node* head, int n) 。在main函数里是这样调用的。Node *head=NULL;
  Node *mnode=CreateList(head,n); Node *knode=head->next;

假设是按另外一种定义,则在定义knode时会产生段异常,head->next是不可訪问的。而是用第一种定义即引用形參时。则能够正常是用head指针、达到程序本来的目的。

这两种定义的区别就在于多了一个引用符号&,函数的实现以及实參的形式都是一样的。而另外一种定义实际并没有改动实參指向的值;假设不用引用类型而非要用指针类型来实现,就得用Node** head作形參,函数实现中应该是*head=...; 

这里就产生这样结果的原因进行讨论。

我个人的理解,形參的传递就是一直值复制的过程。包含指针做形參时,仅仅只是指针做形參时,你传递的是指针的值(即该指针所在地址的内容,即所指向的值的地址,或者说要指向的地方/地址),所以在函数中用*运算符就可以达到目的。比方,在void swap(int *a,int *b)函数实现中。你通过对a进行取值*运算。就能够得到swap(c,d)的实參c所指向的值,所以能够达到交换值的目的,和void swap(int x,int y)不同。

但事实上,指针a本身的地址和实參c本身的地址还是不同的。

 假设使用引用形參。void
swap(int* &m,int* &n)实现例如以下{ int *tmp=n; n=m; m=temp; } 这里直接操作的是指针,而不是像指针形參的实现中使用的取值操作符*。

这里形參m和实參c本身的地址是同样的,它们是指向同一地址的多个变量名而已。

所以在指针引用形參中。能够直接交换地址,这样实參那个标示符指向的位置交换了,则取值后所指向的内容自然是交换的;而在指针形參中,仅仅能通过取值,来对两个指针所指向的值进行交换。

当然。还有void swap(int &z,int &w)非常好理解。  能够看到,void
swap(int , int ) 和 void swap(int& , int& ) 所相应的实參是同样的,实现也是同样的。不同的是终于的实现结果。void swap(int* , int* ) 和 void swap(int* &, int* &)所相应的实參也是同样的,实现的也是同样,不同的也是终于实现的结果。然后void swap(int& , int& ) 和 void swap(int* , int* )实现的结果经常是相似的,但具体实现又有所区别(即一个取值和一个用地址的区别)

所以就能够理解了为什么不用引用形參,上面的main函数里的head看起来是没有改变的,由于head实參传递给head形參的是它指向的地址,而在CreateList函数里对head形參进行了malloc返回值的赋值。即将head指向的位置又改变了,但这影响不了实參head的。所以非常多实现里把头指针直接用CreateList的返回值进行赋值来实现。而假设使用引用形參。则head形參仅仅是head实參这个变量的地址的还有一标示符。那么把形參head指向的位置改变了,由于实參head和形參head本身在同一地址上,所以实參head所指向的位置即改变。当然。也能够使用Node**
来作形參。

这里总结一下就是。对照CreateList(Node *head,int n)和CreateList(Node *&head,int n),形參head事实上也仅仅是一个新变量、暂时变量,head这个标识符标识的是一个新地址。然后这个地址处存的Node型地址(即head指向的地址)和实參指向的地址同样。对前一种来说,head是拷贝实參的Node型地址值,即head指向实參指针所指向的地方,假设你在CreateList函数里又对 head=malloc(...);
则相当于对head这个变量又又一次赋值,指向了另外一个地方,则实參的地址在该函数中已丢失,更不用说对其操作了。而对于有引用&的后一种实现,head就是实參本身。它只是是实參的还有一个名字,意思就是head这个标识符和实參标识符都是对同一地址的标识。当然它们肯定是指向同一地方了,所以在CreateList函数中对head的赋值啊或其它操作,就是在对实參操作。所以实參会改变。    这里主要注意的就是前一种实现形參head是一个新变量,仅仅只是拷贝或同样指向了实參所指的地方;后一种引用实现则是head和实參标识符标识的是同一个地址。它们指向的地方当然同样。对当中一个操作都会改变实參本身的值。

另外,我又加强了对指针的认识。指针就是存的一个地址,然后类型的话是说明这个地址所存的数据是如何的类型。

但你比方说声明Node *p指针时,它并没有创建Node结构体数据。它仅仅是创建了一个指针,该指针仅仅能用来指向Node类型数据。所以,链表中所提到的头指针事实上仅仅是声明一个这种指针,然后指向头结点,而不是创建一个头指针结点。(也就是说UVa133实现的时候是我自己理解错了,创建了一个头指针结点。

。感觉这些东西当初学数据结构时就应该懂的。还是应该在学习后进行总结,特别是对没搞太懂的或有疑问的。注重量的学习还是不是最重要的,还是应该进行总结,注重质。我一直坚持的是对的。不能一知半解得过且过。)

4.内存泄露及free相关

@free同一块内存多次会发生不可知的错误。

 參考

@一般我们常说的内存泄漏是指堆内存的泄漏。

堆内存是指程序从堆中分配的。大小随意的(内存块的大小能够在程序执行期决定)。使用完后必须显示释放的内存。

应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后。程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用。我们就说这块内存泄漏了。 

概念:简单的说就是你申请了一块内存空间,使用完成后没有释放掉。它的一般表现方式是程序执行时间越长。占用内存越多,终于用尽所有内存。整个系统崩溃。

由程序申请的一块内存,且没有不论什么一个指针指向它,那么这块内存就泄露了。

如 void fun(){ char *p=new char[100]; } 执行完上面的函数就发生了泄露,指针p是局部变量,函数执行完后。指针p被销毁,造成new char[100]的内存没有指针指向它,也就无法再使用。造成内存泄漏。(參考:http://bbs.csdn.net/topics/310089353)

引用,引用形參,指针形參与指向指针的引用形參,内存泄露及free相关的更多相关文章

  1. C语言指针(二)指向指针的指针

    注意:指向指针的指针适合于做链表 1.声明方式:在变量名前放置两个*符号 int**var; 2.实例: #include<stdio.h>int main (){intvar;int*p ...

  2. C指针(3)——指向指针的指针(程序讲解)

    int **q可以分成两部分,即int* 和 (*q),后面的 “q” 中的* 表示q是一个指针变量,前面的int*表示指针变量q只能存放int*型变量的地址.int** q表示为指针变量q只能存放i ...

  3. 通过数组初始化链表的两种方法:指向指针的引用node *&tail和指向指针的指针(二维指针)node **tail

    面试高频题:单链表的逆置操作/链表逆序相关文章 点击打开 void init_node(node *tail,char *init_array) 这样声明函数是不正确的,函数的原意是通过数组初始化链表 ...

  4. C语言 > 指向指针的指针

    Int **pt; 一个指向指针的指针: { int ** pt; //一个指向指针的指针; int *ppt; ; ppt = &a; pt = &ppt; printf(" ...

  5. Go 语言指向指针的指针

    如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量. 当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址: 指向指针的指针变量声 ...

  6. C基础知识(3):指针--概念、数组中指针的递增/递减、指针数组&数组指针、指向指针的指针

    指针是一个变量,其值为另一个变量的地址. 所有指针的值的实际数据类型,不管是整型.浮点型.字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数. 下面从4个代码例子分别讲述以下 ...

  7. 不可或缺 Windows Native (18) - C++: this 指针, 对象数组, 对象和指针, const 对象, const 指针和指向 const 对象的指针, const 对象的引用

    [源码下载] 不可或缺 Windows Native (18) - C++: this 指针, 对象数组, 对象和指针, const 对象,  const 指针和指向 const 对象的指针, con ...

  8. C++基础之引用与指针的区别与联系、常引用使用时应注意的问题

    什么是引用? 引用就是对变量起一个别名,而变量还是原来的变量,并没有重新定义一个变量.例如下面的例子:   #include<iostream> using namespace std; ...

  9. Android For JNI(三)——C的指针,指针变量,指针常见错误,值传递,引用传递,返回多个值

    Android For JNI(三)--C的指针,指针变量,指针常见错误,值传递,引用传递,返回多个值 C中比较难的这一块,大概就是指针了,所以大家还是多翻阅一下资料,当然,如果只是想了解一下,看本篇 ...

随机推荐

  1. Kali Linux on Android # 实测:小米2s离线安装Kali Linux

    小米2s 离线安装Kali Linux 2017年2月4日  by 小甘丶 前段时间也研究过一两天,没弄明白,今天突然来兴致了,说研究一下吧,结果一不小心,就弄明白了! 第一次研究,主要是没弄明白这个 ...

  2. vuecli3 引入script 针对没有cmd amd require等方式的js

    最近做高德开发,需要引入高德的js,但是 说实话 高德官方的文档不知道大佬们有没有看懂,反正我是没看懂,写的都什么鬼?我怎么引都引入不了,迫不得已想到了如下方法: 一.准备一个能够在页面中插入js的方 ...

  3. 连接ACCESS

    access2000-2003数据库连接字符串: ConStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=数据库名.mdb"; ...

  4. 使用API失效供应商地址Demo(转)

    原文地址  使用API失效供应商地址Demo DECLARE lv_return_status ) := NULL; ln_msg_count NUMBER; lv_errmsg ); lt_vend ...

  5. length,lengthb,substr,substrb,instr小用

    --字符串的字符长度 select length('wm.dfw.士农工商.sda.人马ss.dfw.4.sdf.332.sf.qq.sd') from dual; --字符串的字节长度 select ...

  6. 解决mac更新系统后git无法使用

    这只是个小笔记啊,记着以后忘了可以再找出来,你们遇到了这个问题也可以翻出来看,废话不多说了,直接讲吧 一.无法使用的原因 mac  更新系统后  git命令无法使用,输入git命令会出现这样的提示 进 ...

  7. win10 移动热点自动关闭

    解决win10移动热点自动关闭

  8. js上传图片前预览方法(支持预览多个图片)

    运用js实现上传图片前的预览(支持多张图片),实现的例子如下: 1.源码例子: 1)Js脚本页面 <!doctype html> <html> <head> < ...

  9. 通过ReRes让chrome拥有路径映射的autoResponse功能。

    前端开发过程中,经常会有需要对远程环境调试的需求.比如,修改线上bug,开发环境不在本地等等.我们需要把远程css文件或者js映射到本地的文件上,通过修改本地文件进行调试和开发.通常我们可以通过以下方 ...

  10. 《Python》 面向对象三大特性之多态、封装

    一.多态 1.什么是多态? 一个类表现出的多种状态:通过继承来实现的 在Java中的表现:在一个函数中需要给参数指定数据类型,如果这个地方可以接收两个以上类型的参数,那么这些类型应该有一个父类,这个父 ...