/请完成下面程序中用于swap交换分区两个整数值的swap()函数的定义

重审C中老生常谈的swap函数交换数值 - 简书
重审C中老生常谈的swap函数交换数值
本文内容是关于C语言参数传值,以及x86底层实现的计算机科学。
包含了原理速览以及代码示例。
如果你学习过C,可能会对经典的swap函数问题记忆深刻。简单的参数传值并不能在函数外部完成两个数的交换,而要用指针传地址。
对此的解释一般为:C语言是以传值的方式将参数传递给函数。因此传递进去的是参数的副本,纵使万千改动也无法触及本源丝毫。故有使用指针一说,以切实地修改两个参数地址处的值。
但对于单纯的传值与传指针(亦地址,引用)的区别是什么,能够道出原委的人可能并不多。因此笔者想通过本文进入更底层的汇编领域,向大家更加清晰地阐述在底层究竟发生了什么。
基本必需配置
任意文本编辑器(可以用来copy文中出现的代码)
GCC(我们需要用GCC来编译C源代码,并以GCC的规则来讲解,其它编译器产生的结果可能会不同)
额外建议配置
类UNIX的环境(Linux与Mac等皆可,笔者是Mac)
我们拥有swapValue.c与swapAddr.c两份源代码,作为研究swap原理的基础,内容分别如下:
// swapValue.c
void swapValue(int a, int b)
void fun()
int a = 2;
int b = 3;
swapValue(a, b);
// swapAddr.c
void swapAddr(int *a, int *b)
int tmp = *a;
void fun()
int a = 2;
int b = 3;
swapAddr(&a, &b);
代码内容很简单,分别是用传值和传地址两种方式实现swap,并都在fun函数中调用swap。
使用汇编器
启动命令行窗口,针对上述两份源代码进行汇编,输入如下命令:
-S swapValue.c
-S -O1 swapAddr.c
第二行多了一个-O1参数是为了让汇编代码更加便于阅读。之后得到swapValue.s与swapAddr.s两份汇编代码。
分析汇编代码
swapValue.s
我们首先分析swapValue.s,撇去次要部分后,我们关注如下内容:
_swapValue:
## @swapValue
%edi, -4(%rbp)
%esi, -8(%rbp)
-4(%rbp), %esi
%esi, -12(%rbp)
-8(%rbp), %esi
%esi, -4(%rbp)
-12(%rbp), %esi
%esi, -8(%rbp)
$2, -4(%rbp)
$3, -8(%rbp)
-4(%rbp), %edi
-8(%rbp), %esi
_swapValue
大家不必去理解汇编代码的含义,只需要理解笔者的讲解即可。可以看到汇编代码分为_fun和_swapValue两个部分,与C源码中两个函数是对应的。
注意:在汇编中我们把函数改用过程来称呼。
对于_fun过程,我们可以看到参数2和参数3被最终分别传递到了寄存器%edi和%esi中。随后调用了_swapValue子过程。
简而言之就是_fun过程将两个实参存放在两个寄存器中,然后调用_swapValue子过程。
在x86架构中,上述两个寄存器是专门用来向函数传递参数的,%edi负责传递第一个参数,%esi负责传递第二个参数。
_swapValue过程
可能是GCC优化问题,汇编代码拐弯抹角地实现了一个实际上很简单的操作。
上文有提到:两个参数存放在寄存器%edi和%esi中。这段代码首先把两个参数分别复制到函数的栈内存中,即把%edi复制到-4(%rbp)中,把%esi复制到-8(%rbp)中,通过栈内存来存放局部变量。
随后拐弯抹角地交换了-4(%rbp)与-8(%rbp)内部的值。可以看到:由于两个参数一开始就被复制,函数操作的一直都是这份副本。于是,这就是传值操作无法切实修改参数值的原因。
swapAddr.s
再来看看swapAddr.s,其中_fun过程没有特别的变化,区别集中在_swapAddr过程。
_swapAddr:
## @swapAddr
(%rdi), %eax
(%rsi), %ecx
%ecx, (%rdi)
%eax, (%rsi)
$2, -4(%rbp)
$3, -8(%rbp)
-4(%rbp), %rdi
-8(%rbp), %rsi
从外观上,可以看到_swapAddr中寄存器的操作,相比之前多了一对圆括号。(%rdi)与(%rsi)互相交换内容。
这对圆括号就是传地址的奥秘所在,该操作统称为间接寻址。
之前寄存器中存放的就是真实的数据,操作时直接取出寄存器中的内容即可。而这里,寄存器中存放的数据不能直接使用,它是一个索引(地址),先取出这个索引,然后去内存中与该索引相对应的位置处取出数据。有点像图书馆中根据书籍的编号去找书。
再仔细想想,这个理念与C语言中的指针是不是很像?没错,指针的底层实现就是它!
因此,由于内存中的地址是唯一对应的,因此在_swapAddr中我们就直接修改了两个参数地址处的值,于是两个参数也就完成了数据交换。
以上就是对于传值与传地址的讲解。普通的变量就是保存一个数值而已,而指针是一种保存变量地址的变量,它的第一层含义是地址,第二层含义是根据该地址去取值。
指针常常是表达某个计算的唯一途径,而且可以生成更加高效紧凑的代码。例如字符串复制函数,关键代码若用指针只需如下:
char * strcpy(char *dest, char *src)
char *ret =
while ((*dest++ = *src++))
正是有了指针,很多高级的操作才成为了可能,宏伟的程序才得以构建。
希望本文对大家有所帮助,感谢阅读,欢迎分享~
Access诚可贵,Trans价更高,若为NATURE故,二者皆可抛。交换x和*this之间的所有内部成员,除了指向相关联的流缓冲区的指针:rdbuf将在调用之前在两个对象中返回相同的值。
派生类可以调用此函数来实现自定义交换函数。
声明下面是ios::swap函数的声明。
void swap (ios& x)
x - 另一个相同类型的流对象。
本站代码下载:新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
白手起家, 积分 167, 距离下一级还需 33 积分
论坛徽章:0
我是这样定义我的宏的:
#define SWAP(a,b) (a = a^b, b = a^b, a = a^b)
复制代码
不过这个方法在a==b的时候不可以,不过要想把SWAP定义成函数那样利用一个中间值实习交换就不知道怎么写了,大家给个方法,多多谢谢啦!!!
&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp
丰衣足食, 积分 657, 距离下一级还需 343 积分
论坛徽章:0
如果要用中间值的话, 要定义它, 则事先需要知道a,b的类型, 宏好像没有办法取类型吧. 除非你给宏多加一个参数, 就像SWAP(a, b, int).
#define SWAP(a, b, type) { c=(a); (a)=(b); (b)=c; }
在C++里可以用模板, 不过我不太清楚模板函数是否可以inline.
白手起家, 积分 167, 距离下一级还需 33 积分
论坛徽章:0
白手起家, 积分 167, 距离下一级还需 33 积分
论坛徽章:0
.cpp文件如下:
template&class T, class Cmp& Sort::Sort&T,Cmp&::inssort(T a[], int n)
{
& & & & for(int i = 1 ; i & i++)
& & & & & & & & for(int j = (j & 0) && a[j] & a[j-1] ; j--)
& & & & & & & & & & & & SWAP(a[j],a[j-1],T);
}
复制代码
.h文件如下:
#define SWAP(a,b,type) { c = (a); (a) = (b); (b) =}
namespace Sort {
& & & & template &class Type, class Cmp&
& & & & public class Sort
& & & & {
& & & & public:
& & & & & & & & void inssort(Type a[], int n);
& & & & & & & & void myqsort(Type a[], int left, int right);
& & & & };
}
复制代码
错误提示:
*************************************************************************
错误& & & & 1& & & & error C4430: missing type specifier - int assumed. Note: C++ does not support default-int& & & & d:\Project\C\Sort\Sort\Sort.cpp& & & & 12& & & &
*************************************************************************
请问这个错误怎么处理啊?我还是想用宏。
丰衣足食, 积分 796, 距离下一级还需 204 积分
论坛徽章:0
原帖由 feiyang21687 于
23:42 发表
不过这个方法在a==b的时候不可以,
为什么不可以?
白手起家, 积分 167, 距离下一级还需 33 积分
论坛徽章:0
a = a^b,a就得0了。那最后a,b都得0了。
小富即安, 积分 4823, 距离下一级还需 177 积分
论坛徽章:2
原帖由 feiyang21687 于
16:18 发表
a = a^b,a就得0了。那最后a,b都得0了。
b不0,最后a=b
白手起家, 积分 167, 距离下一级还需 33 积分
论坛徽章:0
哦,Sorry,你说的对,是我理解错了。是可以。
白手起家, 积分 167, 距离下一级还需 33 积分
论坛徽章:0
能不能帮我解决一下3楼的问题 ?
ivygg 该用户已被删除
提示: 作者被禁止或删除 内容自动屏蔽
北京皓辰网域网络信息技术有限公司. 版权所有 京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:
广播电视节目制作经营许可证(京) 字第1234号
中国互联网协会会员&&联系我们:
感谢所有关心和支持过ChinaUnix的朋友们
转载本站内容请注明原作者名及出处有关Java中两个整数的交换问题
& 在的过程,要交换两个变量的内容,是一种比较常见的事情。在排序算法中,就有一种就叫做&交换排序法&。在所有的排序算法,交换要排序的集合中的两个元素,几乎是必须的过程。在中交换两个元素的内容,如果你是程序员新手,你可能碰到意想不到的问题。
众所周知,java和C、C++中都不能通过值传递的方式实现两个整数的交换。
即下面的函数是不能成功交换两个整数的,
&public void swap1(int a,int b){ //值参数传递不能实现交换两个整数
在C++,可以通过引用或者指针来实现两个整数的交换,实质上是通过地址传递来实现两个整数的交换的。
void swap2(int &a,int &b)//引用传递
还可以通过指针来实现两个整数的交换
void swap2(int *a,int *b)//指针,地址传递
&temp = *a;
那么java中又是如何实现两个整数的交换呢?
通过数组方式交换:
如果一定要通过一个&& method&& 来实现,下面的形式也许可以:
void&& swap(int[]&& a)&& {
&&&&&&& if&& (a&& ==&& null&& ||&& a.length&& !=&& 2)
&&&&&&&&&&&&&&& throw&& new&& IllegalArgumentException();
&&&&&&& int&& temp&& =&& a[0];
&&&&&&& a[0]&& =&& a[1];
&&&&&&& a[1]&& =&&
代码实例如下:
//SwapInteger.java
//实现个整数的交换&
public class SwapInteger {&
public static void swap(int a[]){&&&&&
//数组传递实现交换两个整数&
&&& t = a[0];&
&&& a[0] = a[1];&
&&& a[1] =&
&&&&&&&&&&
public static void main(String args[]){&
&&&& int []a = new int[2];&
&&&& a[0] = 3;&
&&&& a[1] = 4;&
&&&& swap(a);&
&&&& System.out.println(a[0] + &/t& + a[1]);&
构造对象,将a,b作为对象的属性,然后操作对象,最后获得对应的属性。
有人说可以用Integer类来实现,这是错误的说法。
理由如下:
Integer不行,
1、Integer本身是值对象(value&& object),不能修改它的内容(找找哪个方法能修改它的内容?)。实际上,串对象String都不能改变;
2、就算Integer本身可以修改,自动装箱、拆箱也不灵:
void&& exchange(&& Integer&& ao,&& Integer&& bo&& )&& {&& 交换ao和bo中的实际数据&& }
int&& a,&&
exchange(&& a,&& b&& );&& //&& 自动装箱机制生成了两个临时对象,不过调用返回时不能传回a和b。
最多只能这样:
Integer&& ao=a;
Integer&& bo=b;
exchange(&& ao,&& bo&& );
例题:交换JAVA数组中两数
该代码实现功能:
1.接受用户输入10个整数,并存入Array
2.将Array中的最大值与最小值交换位置
java程序如下:
//SwapNumber.java
import java.util.S&&&&
public class SwapNumber {&&&&
&&&&&&& public static void main(String[] ar) {&&&&
&&&&&& Scanner input = new Scanner(System.in);&&&&
&&&&&&&&&& int maxIndex = 0;&&&& //标记最大值索引&&&&
&&&&&&&&&&& int minIndex = 0;&&&& //标记最小值索引&&&&
&&&&&& int numbers[] = new int[10];& //声明数组接受用户输入&&&&
&&&&&&&&&& System.out.println(&请输入十个数字:&);&&&&
&&&&&&& //循环接收&&&&
&&&&&&&&&& for (int i = 0; i & numbers. i++) {&&&&
&&&&&&&&&&&&&&& numbers[i] = input.nextInt();&&&&
&&&&&&&&&& }&&&&
&&&&&&& int temp = 0;&&&& //临时变量&&&&
&&&&&&&&&& int max = numbers[0];&&& //标记最大值&&&&
&&&&&&&&&& int min = numbers[0];&&& //标记最小值&&&&
&&&&&&&&&& //查找最大,最小索引&&&&
&&&&&&&&&& for (int i = 1; i & numbers. i++) {&&&&
&&&&&&&&&&&&&& if (numbers[i] & max) {&&&&
&&&&&&&&&&&&&&&&& max = numbers[i];&& //一定要将该值赋给max!!!!!&&&&
&&&&&&&&&&&&&&&&&&& maxIndex =&&&&
&&&&&&&&&& }&&&&
&&&&&&&&&&&&&& if (numbers[i] & min) {&&&&
&&&&&&&&&&&&&&&&&& min = numbers[i];&&&&
&&&&&&&&&&&&&&&&&&& minIndex =&&&&
&&&&&&&&&& }&&&&
&&&&&& }&&&&
&&&&&& //输出排序后效果&&&&
&&&&&& for (int a : numbers) {&&&&
&&&&&&&&&& System.out.print(a + &/t&);&&&&
&&&&&& }&&&&
&&&&&& //进行交换操作&&&&
&&&&&&& temp = numbers[maxIndex];&&&&
&&&&&& numbers[maxIndex] = numbers[minIndex];&&&&
&&&&&& numbers[minIndex] =&&&&
&&&&&&&&&&&&
&&&&&& //输出排序后效果&&&&
&&&&&&&&&&& System.out.println(&排序后,输出:&);&&&&
&&&&&& for (int i = 0; i & numbers. i++) {&&&&
&&&&&&&&&&&&&&& System.out.print(numbers[i] + &/t&);&&&&
&&&&&&&&&&& }&&&&

我要回帖

更多关于 pads 交换引脚 swap 的文章

 

随机推荐