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/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

http://www.cnblogs.com/luxiaoxun/p/3999583.html

时间: 2025-01-21 17:12:22

Swap in C C++ C# Java的相关文章

使用java.util.Calendar返回间隔天数

calendar 使用SimpleDateFormat,规定好格式,parser出错即为非法/** * Calculates the number of days between two calendar days in a manner * which is independent of the Calendar type used. * * @param d1    The first date. * @param d2    The second date. * * @return    

JAVA CAS原理深度分析(转)

看了一堆文章,终于把JAVA CAS的原理深入分析清楚了. 感谢GOOGLE强大的搜索,借此挖苦下百度,依靠百度什么都学习不到!   参考文档: http://www.blogjava.net/xylz/archive/2010/07/04/325206.html http://blog.hesey.net/2011/09/resolve-aba-by-atomicstampedreference.html http://www.searchsoa.com.cn/showcontent_6923

从excel导入1000多条数据到oracle数据库时,java内存溢出,tomcat报错

问题描述 tomcat错误日志如下:## An unexpected error has been detected by HotSpot Virtual Machine:## EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x7c930a19, pid=1168, tid=1936## Java VM: Java HotSpot(TM) Client VM (1.5.0_16-b02 mixed mode)# Problematic frame:#

An unexpected error has been detected by Java Runtime Environment

最近团队内部遇到一个非常奇怪的问题.网上有人说是sun公司的bug,我在这里贴一下,有兴趣的同志可以研究一下.据说,换一个java版本就好了,团队内部正在进行升级java版本.sun公司官网解释:https://www.java.net/node/670924程序异常error如下: # # An unexpected error has been detected by Java Runtime Environment: # # EXCEPTION_ACCESS_VIOLATION (0xc0

Java程序员也应该知道的系统知识系列之内存

作者:林昊 上篇说到了Java程序和CPU的关系,对于多数实现的较好的Java应用程序而言,基本上随着CPU的核数增加或能力提升,系统能够支撑的并发量就可以稳步上升,但对于内存而言,是否也是这样呢,这篇我们就来看看Java程序和内存的关系.   和CPU一样,我们首先要知道机器上的内存的硬件状况,在linux下,可以通过dmidecode | grep -A16 "Memory Device$"命令来查看机器插了多少根内存条,以及每根内存条的具体型号,内存条的具体型号对Java应用的运

Java方法参数是引用调用还是值调用?_java

方法调用(call by) 是一个标准的计算机科学术语.方法调用根据参数传递的情况又分为值调用( call by reference ) 和引用调用( call by value ) .江湖上有很多关于这两种调用的定义 ,最通常的说法是传递值的是值调用,传递地址的是引用调用.这其实很不恰当,这种 这些说法很容易让我们联想到Java的对象参数传递是引用调用,实际上,Java的对象参数传递仍然是值调用 . 我们首先用一段代码来证实一下为什么Java的对象参数传递是值调用. public class

磁盘管理 之 parted命令添加swap,文件系统

第1章 磁盘管理 1.1 必须要了解的. 1.1.1 ps aux 命令中 RSS 与VSZ的含义 rss 进程占用的物理内存的大小 单位:kb :    vsz 进程占用的虚拟的内存大小(物理内存+swap) 1.1.2 top命令的参数        M   按照内存使用率排序        P   按照cpu的使用率排序 1.1.3 htop 命令的安装方法        要配置 epel源        http://mirrors.aliyun.com 1.2 磁盘分区之parted

内存溢出-tomcat7运行一段时间总是死掉

问题描述 tomcat7运行一段时间总是死掉 这是打印的错误日志: # A fatal error has been detected by the Java Runtime Environment: # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006d9d6262, pid=4864, tid=3628 # JRE version: 6.0_27-b07 Java VM: Java HotSpot(TM) 64-Bit Ser

jvm-swt中打开浏览器后,JVM崩溃

问题描述 swt中打开浏览器后,JVM崩溃 我这是swt程序,一个功能是调用浏览器访问百度地图获取坐标,以前一直都没有问题,可现在一打开这个功能JVM就挂了,下面贴出日志信息,望高手分析指点下,谢谢! # A fatal error has been detected by the Java Runtime Environment: EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x67164778, pid=2728, tid=4680 JRE v