Swap in C C++ C# Java

简介:

写一个函数交换两个变量的值。

C:

错误的实现:

复制代码
void swap(int i, int j) 
{
   int t = i;
   i = j;
   j = t;
}
复制代码

因为C语言的函数参数是以值来传递的(pass by value),参数传递时被copy了,所以函数中交换的是复制后的值。

正确的实现:

指针版:

复制代码
void swap(int *i, int *j) 
{
   int t = *i;
   *i = *j;
   *j = t;
}
复制代码

函数使用时候传递的是变量的地址,如 swap(&a,&b),函数交换的是两个指针指向的值,就是两个变量的值,所以交换成功。

预处理版:

#define swap(type, i, j) {type t = i; i = j; j = t;}

预处理的实质是文本替换(textual substitution)。

如下代码:

复制代码
#define swap(type, i, j) {type t = i; i = j; j = t;}

int main() 
{
    int a = 23, b = 47;
    printf("Before swap. a: %d, b: %d\n", a, b);
    swap(int, a, b)
    printf("After swap.  a: %d, b: %d\n", a, b);
    return 0;
}
复制代码

预处理之后的代码就是:

复制代码
int main() 
{
    int a = 23, b = 47;
    printf("Before swap. a: %d, b: %d\n", a, b);
     { int t = a ; a = b ; b = t ; }
    printf("After swap.  a: %d, b: %d\n", a, b);
    return 0;
}
复制代码

所以可以正确的交换两个变量的值。

C++:

方式一:如同C语言使用指针。
方式二:使用“引用”(&)

复制代码
void swap(int& i, int& j) 
{
    int t = i;
    i = j;
    j = t;
}
复制代码

C++的函数参数使用引用(&),值通过引用传递(pass by reference),函数中的参数不被 copy(如果传的是类就不会调用拷贝构造函数),所以在函数中能正确交换两个变量的值。

C#:

复制代码
static void Swap<T>(ref T lhs, ref T rhs)
{
    T temp;
    temp = lhs;
    lhs = rhs;
    rhs = temp;
}
复制代码

不要忘了ref关键字,如果没有是不能正确交换的!

Java:

java.util.Collections;
public static void swap(List<?> list,int i,int j)

使用集合中的static方法。

如果不使用数组集合,Java中没有一个简单的函数来交换两个变量的值。除非自己封装一下:

复制代码
// MyInteger: similar to Integer, but can change value
class MyInteger {
   private int x;                   // single data member
   public MyInteger(int xIn) { x = xIn; } // constructor
   public int getValue() { return x; }  // retrieve value
   public void insertValue(int xIn) { x = xIn;} // insert
}

public class Swapping {
   // swap: pass references to objects
   static void swap(MyInteger rWrap, MyInteger sWrap) {
      // interchange values inside objects
      int t = rWrap.getValue();
      rWrap.insertValue(sWrap.getValue());
      sWrap.insertValue(t);
   }

   public static void main(String[] args) {
      int a = 23, b = 47;
      System.out.println("Before. a:" + a + ", b: " + b);
      MyInteger aWrap = new MyInteger(a);
      MyInteger bWrap = new MyInteger(b);
      swap(aWrap, bWrap);
      a = aWrap.getValue();
      b = bWrap.getValue();
      System.out.println("After.  a:" + a + ", b: " + b);
   }
}
复制代码

C#这点和Java是一样的,C#版的交换如果不使用ref关键字,swap函数也没法正确工作。

虽然C#、java通过函数参数可以修改参数的值,但是这点和C++的引用有很大的区别。

看看如下函数:

复制代码
public void tricky(Point arg1, Point arg2)
{
    arg1.x = 100;
    arg1.y = 100;
    Point temp = arg1;
    arg1 = arg2;
    arg2 = temp;
}
 
public static void main(String [] args)
{
    Point pnt1 = new Point(0,0);
    Point pnt2 = new Point(0,0);
    System.out.println("X: " + pnt1.x + " Y: " +pnt1.y);
    System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
    System.out.println(" ");
    tricky(pnt1,pnt2);
    System.out.println("X: " + pnt1.x + " Y:" + pnt1.y);
    System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
}
复制代码

执行这个函数,将得到以下输出:

———————————————————-
X: 0 Y: 0
X: 0 Y: 0

X: 100 Y: 100
X: 0 Y: 0
———————————————————-

当Java传递对象给函数之后,两个引用指向了同一对象:

当被传递给函数之后,一个对象至少存在两个引用

Java复制并传递了“引用”的值,而不是对象。因此,方法中对对象的计算是会起作用的,因为引用指向了原来的对象。但是因为方法中对象的引用是“副本”,所以对象交换就没起作用。如下图所示,交换动作只对方法中的引用副本起作用了,不影响方法外的引用。所以不好意思,方法被调用后,改变不了方法外的对象的引用。如果要对方法外的对象引用做交换,我们应该交换原始的引用,而不是它的副本。

只有传入函数的引用交换了,原始引用则没有。

 

参考: 

http://www.cs.utsa.edu/~wagner/CS2213/swap/swap.html
http://stackoverflow.com/questions/1363186/is-it-possible-to-write-swap-method-in-java
http://www.importnew.com/3559.html

 


    本文转自阿凡卢博客园博客,原文链接:http://www.cnblogs.com/luxiaoxun/p/3999583.html,如需转载请自行联系原作者

相关文章
|
10月前
|
监控 搜索推荐 数据挖掘
销售全流程管理:CRM 行业的线索到商机转化秘籍
在当今竞争激烈的商业环境中,CRM行业正经历深刻变革。企业要脱颖而出,需提升销售全流程管理效率,尤其是从线索到商机的全流程管理和数字化运营。通过线索评估、重点跟进和商机转化等环节精细化管理,结合自动化线索分配、实时数据监控及数据分析预测等数字化工具,企业能显著提高销售效率与业绩,实现持续增长,在市场中立于不败之地。
|
9月前
|
消息中间件 存储 Kafka
Fluss: First Impression
Fluss: First Impression
204 0
|
12月前
|
弹性计算 运维 安全
阿里云轻量应用服务器与ECS的区别及选择指南
轻量应用服务器和云服务器ECS(Elastic Compute Service)是两款颇受欢迎的产品。本文将对这两者进行详细的对比,帮助用户更好地理解它们之间的区别,并根据自身需求做出明智的选择。
|
存储 安全 物联网
未来技术潮流之巅:区块链、物联网与虚拟现实的融合应用
【8月更文挑战第31天】在数字化浪潮不断推进的当下,新技术如区块链、物联网(IoT)和虚拟现实(VR)正逐步渗透到我们生活的各个角落。本文旨在探索这些技术的发展趋势和它们在实际应用中如何相互促进,共同塑造未来。我们将从基础概念出发,通过案例分析,深入讨论这些技术如何影响现代商业、教育和娱乐等领域,并展示一些简单的代码示例来揭示它们是如何工作的。文章最终将提供对这些技术未来发展的展望。
|
存储 Web App开发 Ubuntu
整理16款适用于较旧低配置电脑的最佳Linux发行版
在本指南中,趣云笔记(https://www.ecscoupon.com/)介绍了一些最好的Linux发行版,你可以将它们安装在旧PC上并为其注入新的活力。
23015 0
|
存储 Linux
【linux进程信号(二)】信号的保存,处理以及捕捉
【linux进程信号(二)】信号的保存,处理以及捕捉
|
弹性计算 虚拟化 异构计算
阿里云GPU服务器NVIDIA A100 GPU卡租用价格表
阿里云GPU服务器NVIDIA A100 GPU卡租用价格表,阿里云GPU服务器租用价格表包括包年包月价格、一个小时收费以及学生GPU服务器租用费用,阿里云GPU计算卡包括NVIDIA V100计算卡、T4计算卡、A10计算卡和A100计算卡,GPU云服务器gn6i可享受3折优惠,阿里云百科分享阿里云GPU服务器租用价格表、GPU一个小时多少钱以及学生GPU服务器收费价格表
15287 0
阿里云GPU服务器NVIDIA A100 GPU卡租用价格表
|
编解码
猪笼草表面连续定向输水Continuous directional water transport on the peristome surface of Nepenthes alata-2016-阅读笔记
打破了传统水往下流的思路,仿生猪笼草表面结构,提出定向水传输结构。
|
关系型数据库 MySQL 数据库
通过Docker快速搭建Mysql测试开发环境
通过Docker快速搭建Mysql测试开发环境
537 0
通过Docker快速搭建Mysql测试开发环境
|
Linux 开发工具 Android开发
RTL8703/RTL8723/RTL8761/RTL8821/RTL8822系列蓝牙定频测试说明
Realtek系列蓝牙方案RTL8703/RTL8723/RTL8761/RTL8821/RTL8822/RTL8852蓝牙定频测试说明
1169 0