链表-单向链表-值传递&地址传递
2015-12-20 23:13
351 查看
1. 单向链表算法实现
解释:
void DeleteLinkNode(Link
* head, int idNumber) -----------------(1)
与
template<typename type, typename typeT>
void DeleteLinkNode(type* & head, typeT idNumber) ------------------(2)
现象描述:
当使用(1)时,虽然在函数中改变了头指针,但是,在调用函数中head指针并未发生变化。
原因:
在(1)中,函数声明为一个指向link的指针,此时传入的是头指针head,这个head本身是一个指针。因此,在传输的过程中,head实际是按值拷贝,拷贝的是地址。因此,被调用函数中,head仅仅是调用函数中head的拷贝。
在(2)中,head是type*的一个引用,因此,head实际就是调用函数中的实际值,这实际上是引用拷贝。
通常来讲,出现这种错误的几率很小,因为void
DeleteLinkNode(Link * head, int
idNumber) 在使用过程中常常如下:
Link
link;
DeleteLinkNode(&link,19);
此时,传入的是link的地址。在调用函数中,能够修改link
但本题中,
Link
* head;
DeleteLinkNode(head,19);
此时,head是作为一个link * 的实参传入的,并不是一个link * 指针的地址或者引用。因此,会发生以上错误。
3. 总结
在处理这种问题时,应把握两点:
1)值拷贝和地址拷贝
值拷贝不能修改原来的值。如果传入的只是某种变量类型,如Link, Link *(注意传入指针变量),并不是对这些变量的取地址,那么仍旧是值拷贝;
地址拷贝能改变原来的值,但是地址拷贝要求传入某种变量的地址或者引用。变量可以分为两种,一中是常用变量,一种是指针变量,。对于常用变量,如int ,传入的是( int *)
或者& (int);如果是指针变量,想要改变指针的值,则必须传入该指针变量的地址或者引用,如(int* *)或者 &(int
*)。
其中,千万不要把传入的指针变量看作是可以修改的。如果形参中,没有对指针变量进行取地址操作,那么传入的指针变量仅仅是一个值拷贝。
2)MSDN中的数据结构定义总是定义一个变量和指针变量?
因为,当传入的变量是一个指针变量时,实际仅仅是对指针变量的值拷贝,并不能达到修改指针变量值得效果。而程序猿有时会混淆这种指针变量的传递,错误的以为传入的就是指针变量的地址,实际上传递的仅仅是变量,而不是地址。因此,MSDN在定义数据结构时,便定义一个数据结构的指针,这样就为程序猿的操作提供了便利。
便利之处在于:
1)定义指针变量如同定义一个常用变量一样简单
ex:
LIST_ENTRY * pentry;
PLIST_ENTRY pentry;
两者是等价的。
2)在形参中可以用* 或者& 来明确的指出传递的是地址还是变量的拷贝
地址传递:传递的可以是变量的地址,也可以是保存指针变量的地址,而且函数中对这些变量的修改会影响到原来的
传指针:
void foo(LIST_ENTRY * pentry); //传递的是一个变量的地址
void foo(PLIST_ENTRY *
pentry); //传递的是一个指针变量的地址,可以对指针的值进行修改
传引用:
void foo(LIST_ENTRY & pentry); //传递的是一个变量的引用
void foo(PLIST_ENTRY
& pentry); //传递的是一个指针变量的引用,可以对指针的值进行修改
--------------------------------------------------------------------------
值传递:传递的可以是变量,也可以是指针,但是函数中对这些变量的修改不会影响到原来的
传变量:
void foo(LIST_ENTRY
pentry); //传递一个变量,但函数中知识对改变了的拷贝
void foo(PLIST_ENTRY pentry);
//传递一个指针变量,但函数中只是对该变量的拷贝
从上述可以看出,无需再显示声明指针,只需直接调用指针变量的结构声明。而,*和&则表明可以修改这些传入的参数,不加&和*则表明仅仅是变量,无法修改他们自身。这样,利用&和*便清晰明白的将值传递和地址传递解释清楚了。
typedef struct _Node{ int number; char name[12]; int age; } Node; // this is just a example typedef struct _Link{ Node node; struct _Link * Next; } Link; //add a node( current may be a head pointer template<typename type> void AddLinkNode(type * current, type * newNode); //delete a node by idnumber template<typename type, typename typeT> void DeleteLinkNode(type* & head, typeT idNumber); //iterator the link template<typename type> void Listview(type * head); //add a node( current may be a head pointer template<typename type> void AddLinkNode(type * current, type * newNode) { if (current == NULL) // the current is the head pointer current = newNode; else // non head pointer current->Next = newNode; } //iterator the link template<typename type> void Listview(type * head) { type * p; for (p=head; p!=NULL; p = p->Next) { /*printf("%d %s %d", p->node.number, p->node.name, p->node.age);*/ printf("%d ", p->node.number); } } template<typename type, typename typeT> void DeleteLinkNode(type* & head, typeT idNumber) { type * p = head; while (p!=NULL) { if (p->node.number == idNumber) { if (p==head) //the head pointer { head = p->Next; //printf("clean node----%d %s %d", head->node.number, head->node.name, head->node.age); free(p); //clean the heap resource p = head; //make the p pointer to the next } else // non head pointer { //find the pre-pointer of p type * temp = head; while (temp->Next != p) temp =temp->Next; temp->Next = p->Next; free(p); //clean the heap resource p = temp->Next; //make the p pointer to the next } //printf("delete node ---- %d ", p->node.number); //free(p); //break; } else p = p->Next; //put the pointer to the next } }2. 错误代码示例及分析
-----------------------------------------------this is the wrong code--------------------------------- //delete a node by idnumber void DeleteLinkNode(Link * head, int idNumber) // wrong here { Link * p; for (p = head; p!=NULL; p = p->Next) { if (p->node.number == idNumber) { if (p==head) //the head pointer { head = p->Next; } else // non head pointer { //find the pre-pointer of p Link * temp = head; while (temp->Next != p) temp =temp->Next; temp->Next = p->Next; } //printf("delete node ---- %d ", p->node.number); free(p); break; } } } -------------------------------------------this is the wrong code-------------------------------------------
解释:
void DeleteLinkNode(Link
* head, int idNumber) -----------------(1)
与
template<typename type, typename typeT>
void DeleteLinkNode(type* & head, typeT idNumber) ------------------(2)
现象描述:
当使用(1)时,虽然在函数中改变了头指针,但是,在调用函数中head指针并未发生变化。
原因:
在(1)中,函数声明为一个指向link的指针,此时传入的是头指针head,这个head本身是一个指针。因此,在传输的过程中,head实际是按值拷贝,拷贝的是地址。因此,被调用函数中,head仅仅是调用函数中head的拷贝。
在(2)中,head是type*的一个引用,因此,head实际就是调用函数中的实际值,这实际上是引用拷贝。
通常来讲,出现这种错误的几率很小,因为void
DeleteLinkNode(Link * head, int
idNumber) 在使用过程中常常如下:
Link
link;
DeleteLinkNode(&link,19);
此时,传入的是link的地址。在调用函数中,能够修改link
但本题中,
Link
* head;
DeleteLinkNode(head,19);
此时,head是作为一个link * 的实参传入的,并不是一个link * 指针的地址或者引用。因此,会发生以上错误。
3. 总结
在处理这种问题时,应把握两点:
1)值拷贝和地址拷贝
值拷贝不能修改原来的值。如果传入的只是某种变量类型,如Link, Link *(注意传入指针变量),并不是对这些变量的取地址,那么仍旧是值拷贝;
地址拷贝能改变原来的值,但是地址拷贝要求传入某种变量的地址或者引用。变量可以分为两种,一中是常用变量,一种是指针变量,。对于常用变量,如int ,传入的是( int *)
或者& (int);如果是指针变量,想要改变指针的值,则必须传入该指针变量的地址或者引用,如(int* *)或者 &(int
*)。
其中,千万不要把传入的指针变量看作是可以修改的。如果形参中,没有对指针变量进行取地址操作,那么传入的指针变量仅仅是一个值拷贝。
2)MSDN中的数据结构定义总是定义一个变量和指针变量?
因为,当传入的变量是一个指针变量时,实际仅仅是对指针变量的值拷贝,并不能达到修改指针变量值得效果。而程序猿有时会混淆这种指针变量的传递,错误的以为传入的就是指针变量的地址,实际上传递的仅仅是变量,而不是地址。因此,MSDN在定义数据结构时,便定义一个数据结构的指针,这样就为程序猿的操作提供了便利。
便利之处在于:
1)定义指针变量如同定义一个常用变量一样简单
ex:
LIST_ENTRY * pentry;
PLIST_ENTRY pentry;
两者是等价的。
2)在形参中可以用* 或者& 来明确的指出传递的是地址还是变量的拷贝
地址传递:传递的可以是变量的地址,也可以是保存指针变量的地址,而且函数中对这些变量的修改会影响到原来的
传指针:
void foo(LIST_ENTRY * pentry); //传递的是一个变量的地址
void foo(PLIST_ENTRY *
pentry); //传递的是一个指针变量的地址,可以对指针的值进行修改
传引用:
void foo(LIST_ENTRY & pentry); //传递的是一个变量的引用
void foo(PLIST_ENTRY
& pentry); //传递的是一个指针变量的引用,可以对指针的值进行修改
--------------------------------------------------------------------------
值传递:传递的可以是变量,也可以是指针,但是函数中对这些变量的修改不会影响到原来的
传变量:
void foo(LIST_ENTRY
pentry); //传递一个变量,但函数中知识对改变了的拷贝
void foo(PLIST_ENTRY pentry);
//传递一个指针变量,但函数中只是对该变量的拷贝
从上述可以看出,无需再显示声明指针,只需直接调用指针变量的结构声明。而,*和&则表明可以修改这些传入的参数,不加&和*则表明仅仅是变量,无法修改他们自身。这样,利用&和*便清晰明白的将值传递和地址传递解释清楚了。
相关文章推荐
- mybatis基础与核心类
- 深(浅)复制与retain
- 短信的自动拦截
- 2015第52周日
- 张国祥老师应邀在上海交大讲授流程优化与建设方法课程
- [javase学习笔记]-6.7 封装
- ubuntu从tty终端模式返回到图形桌面
- 源码解析Android中View的layout布局过程
- 重载构造函数(相同运算结果,不同性能比较)
- Spring Boot学习笔记-快速示例
- iOS 中的观察者模式, KVO, 通知
- Remove Duplicates from Sorted Array
- CentOS的Linux操作系统图形界面开启
- Sql 工具的使用
- RabbitMQ部署流程
- 如何调用百度的api
- 服务器远程监控管理(二)-系统远程安装部署
- java垃圾回收
- 校OJ 11076 浮点数的分数表达
- EasyUI-----给combobox添加OnSelect事件