文档库 最新最全的文档下载
当前位置:文档库 › C语言中参数传递(精)

C语言中参数传递(精)

C语言中参数传递(精)
C语言中参数传递(精)

二. 参数传递

函数的形参的初始化和变量的初始化一样,如果形参具有非引用类型,则复制实参的值, 如果形参为引用类型,则它是实参的别名。

1. 非引用实参

普通的非引用类型的函数通过复制对应的实参实现初始化。当用实参副本初始化形参时, 函数并没有调用所传递的实参本身,因此不会修改实参的值。

注解:非引用形参表示对应实参的局部副本, 对这类行参的修改仅仅改变了局部副本的值, 一旦函数执行结束,这些局部变量的值也就没有了。

a. 指针形参

指针形参与其他非引用类型的行参一样, 如果将新指针赋给行参, 主调函数使用的实参指针的值没有改变。事实上被复制的指针只影响对指针的赋值。指针形参是 const 类型还是非 const 类型,将影响函数调用所使用的实参。

b. const行参

在调用函数时,如果该函数使用非引用的非 const 形参,则既给该函数传递 const 实参也可传递非 const 的实参 (因为改变形参不影响 const 的实参,所以 const 实参不会被改变。如果将形参定义为非引用的 const 类型,则在函数中,不可以改变实参的局部副本,由于实参是以副本的形式传递,因此传递给函数形参既可是 const 也可是非 const 对象。

注意:尽管函数的形参是 const ,但是编译器却将该行参声明视为普通的 int 型。

void fcn(const int i;

void fcn(int i;

为了兼顾 C 语言,认为这两种定义并不区别。

c. 复制实参的局限性

不适合复制实参的情况包括:

当需要在函数中修改实参的值时

当需要以大型对象作为实参传递时, 对实际的应用而言, 复制对象所付出的时间和存储空间代价往往很大。

但没有办法实习对象的复制时

对于以上几种情况,有效的办法是将形参定义为引用或指针。

2. 引用实参

与所有引用一样, 引用形参直接关联到其所绑定的对象, 而并非这些对象的副本。定义引

用时, 必须用与该引用绑定的对象初始化该引用。引用形参以完全相同的方式工作。每次调用函数时,引用形参被创建并与相应的实参关联。

a. 使用引用形参返回额外的信息

函数只能返回单个值, 但有时候函数有不止一个的内容需要返回。这时候我们可以通过函数传递一个额外的引用实参,用于返回额外的信息。

b. 利用 const 引用避免复制

对于大型对象复制效率太低了, 有些类型甚至无法复制, 利用 const 引用就可以避免复制, 引用形参是引用,所以不复制实参,又因为形参是 const 引用,所以不能使该引用来修改实参。

c. 更灵活的指向 const 的引用

如果函数具有普通的非 const 引用形参,则不能通过 const 对象进行调用,因为函数可以修改传来的参数,但这样就违背了实参的 const 特性。

int incr(int &val

{

return ++val;

}

int main(

{

short v1=0;

const int v2=42;

int v3=incr(v1; //error, v1不是整型

v3=incr(v2; //error, v2使 const 对象

v3=incr(0; //error, 字面值不是左值

v3=incr(v1+v2; //error, 加法不能作为左值

int v4=incr(v3; //ok, v3是一个非 const 的整型值

}

问题的关键是非 const 引用形参只能与完全相同的非 const 对象关联。

最佳实践:应该将不需要修改的引用定义为 const 引用。普通的非 const 引用形参在使用时不太灵活。这样的形参既不能被 const 对象初始化,也不能用字面值或产生右值的表达式初始化。

d. 传递指向指针的引用

实现两个指针的交换:

void ptrswap(int* &v1, int* &v2

{

int* temp=v2;

v2=v1;

v1=temp;

}

行参 int* &val的定义从右向左理解:v1是一个引用,与指向 int 型对象的指针相关联。也就是说, v1只是传递进 ptrswap 函数的任意指针的别名。

3. vector和其他容器类型的行参

最佳实践:通常, 函数不应该有 vector 或其他标准容器库类型的实参。调用含

有普通的非引用 vector 行参的函数将会复制 vector 的每一个元素。从避免复制vector 的角度出发, 应考虑将形参声明为引用类型。

4. 数组形参

a. 数组形参的定义

数组会被自动转换为指针 , 通常,将数组形参直接定义为指针要比数组语法更好,这样就明确的表示,函数操纵是指向数组元素的指针,而不是数组本身。

当编译器检查数组形参关联的实参时, 他只会检查实参是不是指针, 指针的类型和数组元素的类型是否匹配,而不会检查数组的长度。

b. 数组实参

和其他类型一样, 数组形参可定义为引用或非引用类型, 大部分情况下, 数组以普通的非引用类型传递,此时数组会转换为指针。

最佳实践:当不需要修改数组形参的元素时,函数应该将形参的定义为指向 const 对象的指针。

c. 通过引用传递数组

与其他类型一样, 数组形参可以声明为数组的引用, 如果形参是数组的引用, 编译器不会将数组实参转化为指针, 而是传递数组的引用本身, 在这种情况下, 数组的大小成为形参和实参的一部分。编译器检查数组实参的大小与形参的大小是否匹配。

void print(int (&arr[10] ; //形参是一个数组的引用,数组的大小确定

int main(

{

int i=0,j[2]={0,1};

int k[10]={0,1,2,3,4,5,6,7,8,9};

print(&i; //error,参数不是 10个整型元素的数组

print(j; // error,参数不是 10个整型元素的数组

print(k; //ok, 参数是 10个整型元素的数组。

}

注解:&arr两本的括号是必须的,因为下标操作具有更高的优先级

f(int &arr[10] //error,arrs是一个含有 10个引用的数组

f(int (&arr[10] //ok, arr 是一个引用,他和一个含有 10个元素的数组关联

d. 多维数组的传递

C ++没有多维数组,所谓多维数组实际就是指数组的数组。除了第一维以外的所有维的长度都是元素类型的一部分。

5. 传递给函数的数组的处理

任何数组的处理程序都要保证程序停留在数组的边界内。

a. 使用标准库规范, 传递指向数组的第一个元素和最后一个元素的下一个位置的指针。这中技术风格由标准库的技术启发而得。

b. 显式传递表示数组大小的形参

void print(const int ia[], size_t size;

6. main:处理命令行选项

7.含有可变形参的函数

在无法列举出传递给函数的所有实参的类型和数目时, 可以使用省略符形参。省略符暂停了类型检查机制。它们的出现告诉编译器,当调用函数时,可以有 0或多个实参, 而实参的类型未知。

两种省略形参的形式

void foo(param_list, …;

void foo(…;

参数传递方式

引用在函数参数传递中的作用 传递参数有三种方法:1,传递对象本身。2,传递指向对象的指针。3,传递对象的引用。 (1)传值方式 ①传给被调用函数的是整型、长整型、浮点型或双精度型变量。被调用的函数得定义相应的变量为形参。 ②传给被调用函数的是结构变量。被调用函数得定义结构变量为形参。 ③传给被调用函数的是结构变量的成员。被调用函数得定义与该成员同类的变量为形参。 #include "stdio.h" ?#include ?main( ) ?{ ?void swap(int pt1,int pt2); ?int a,b; ?scanf("%d, %d", &a,&b); ?swap(a,b); ?printf("\n%d,%d\n",a,b); ?} ?void swap(int pt1,int pt2) ?{int p; p=pt1; pt1=pt2; pt2=p; } ?

#include "stdio.h" void swapint(); int a,b; void main() { a = 5, b = 10; swapint(); printf("%d\n%d\n",a,b); } void swapint() { int temp; temp=a; a=b; b=temp; } (2)传址方式 ①传给被调用函数的是变量的地址。被调用函数得定义指针变量为形参。 ②传给被调用函数的是数组的地址即数组名。被调用的函数得定义数组或指针变量为形参。 ③传给被调用函数的是函数的地址即函数名称。被调用函数得定义指向函

数的指针变量为形参。④传给被调用函数的是结构的地址。被调用函数得定义结构指针为形参。 #include "stdio.h" ?#include ?main( ) ?{ ?void swap(int *pt1,int *pt2); ?int a,b,*p1,*p2; ?scanf("%d, %d", &a,&b); ?p1=&a;p2=&b; ?swap(p1,p2); ?printf("\n%d,%d\n",a,b); ?} ?void swap(int *pt1,int *pt2) ?{int p; p=*pt1; *pt1=*pt2; *pt2=p; } #include "stdio.h" void swapint(int *a,int *b); void main() { int a = 5, b = 10;

C语言与汇编语言互相调用

浅谈C程序中调用汇编模块的方法 C语言是目前非常流行的一种编程语言,除具有高级语言使用方便灵活、数据处理能力强、编程简单等优点外,还可实现汇编语言的大部分功能,如可直接对硬件进行操作、生成的目标代码质量较高且执行的速度较快等。所以在工程上对硬件处理速度要求不很高的情况下,基本可以用C代替汇编语言,编写接口电路的控制软件。但C也不能完全取代汇编语言,如在一些对速度要求很高的实时控制系统中,以及对硬件的特殊控制方面,C有时也不能完全很好胜任,还需要汇编语言来编写。因为汇编语言目标代码更精练,对硬件直接控制能力更强和执行速度更快,但汇编语言编程烦难、表达能力差也显而易见。比较好的解决办法是C与汇编语言混合编程,即用C编写软件的调度程序、用户界面以及速度要求不高的控制部分,而用汇编语言对速度敏感部分提供最高速度的处理模块,供C调用。这种方法提供了最佳的软件设计方案,做到了兼顾速度效率高和灵活方便。由于本人的毕业设计需要C 程序中调用汇编模块的方法来提高ARM定点指令的执行速度,故对这方面进行了学习。学习心得如下: 对于C和汇编语言的接口主要有两个问题需要解决。 一、调用者与被调用者的参数传递 这种数据传递通过堆栈完成,在执行调用时从调用程序参数表中的最后一个参数开始,自动依次压入堆栈;将所有参数压入堆栈后,再自动将被调用程序执行结束后的返回地址(断点)压入堆栈,以使被调程序结束后能返回主调程序的正确位置而继续执行。例如一调用名为add汇编程序模块的主函数:main( ){...... add(dest,op1,op2,flages);......}。在此例中对主函数进行反汇编,主函数在调用add函数前自动组织的堆栈。 . . . lea 0xfffffffe8(%ebp),%eax #flages数组的首地址入栈 push %eax pushl 0xfffffff8(%ebp) #OP2入栈 pushl 0xfffffffc(%ebp) #OP1 入栈 pushl 0xfffffff0(%ebp) #dest地址入栈 call 0x80483f0 #调用add函数 . . 执行完add调用语句后,栈内数据结果如图一所示。 进入汇编子程序后,为了能正确获取主调程序并存入堆栈中的数据,被调的汇编子程序先后要做如下一些工作: 1、保存esp的副本 进入汇编子程序后,子程序中免不了要有压栈和出栈的操作,故ESP时刻在变化。为了能用ESP访问堆栈中的参数,安全办法是一进入子程序后,先为ESP制副本,以后对传递参数的访问都用副本进行。一般可用EBP保存ESP,如: push %ebp mov %ebp,%esp

C#中方法的参数有四种类型

C#中方法的参数有四种类型 1. 值参数(不加任何修饰符,是默认的类型) 2. 引用型参数(以ref 修饰符声明) 3. 输出参数(以out 修饰符声明) 4. 数组型参数(以params 修饰符声明) 1. 值传递: 值类型是方法默认的参数类型,采用的是值拷贝的方式。也就是说,如果使用的是值类型,则可以在方法中更改该值,但当控制传递回调用过程时,不会保留更改的值。 使用值类型的例子如:(下面的Swap()未能实现交换的功能,因为控制传递回调用方时不保留更改的值) using System; class Test { static void Swap(int x, int y) { int temp = x; x = y; y = temp; } static void Main() { int i = 1, j = 2; Swap(i, j); Console.WriteLine("i = {0}, j = {1}", i, j); } } /* * 输出结果为: i=1, j=2 * 未能实现Swap()计划的功能 */ 2. 引用传递(ref类型) ref关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。 2.1. 若要使用ref 参数,则方法定义和调用方法都必须显式使用ref关键字。 2.2. 传递到ref 参数的参数必须最先初始化。这与out 不同,out 的参数在传递之前不需要显式初始化。 2.3. 如果一个方法采用ref 或out 参数,而另一个方法不采用这两类参数,则可以进行重载。

相关实例如下: using System; class Test { static void Swap(ref int x, ref int y) { int temp = x; x = y; y = temp; } static void Main() { int i = 1, j = 2; Swap(ref i, ref j); Console.WriteLine("i = {0}, j = {1}", i, j); } } /* * 引用类型实现了Swap()计划的功能: * 输出为: * i = 2, j =1 */ 3. 输出类型(out类型) out 关键字会导致参数通过引用来传递。这与ref 关键字类似。 与ref 的不同之处: 3.1. ref 要求变量必须在传递之前进行初始化,out 参数传递的变量不需要在传递之前进行初始化。 3.2. 尽管作为out 参数传递的变量不需要在传递之前进行初始化,但需要在调用方法初始化以便在方法返回之前赋值。 示例如下: using System; class Test { static void Swap(out int x, out int y) { //在这里进行了i和j的初始化

《c语言程序设计》--4种“交换算法”介绍。

第 1 页 共 2 页 算法 交换 在很多问题的解决中都需要使用到交换这个方法,比如排序时,需要将两个变量的值互换等等。交换是指将两个变量的值进行互换。假设有整型变量a 和b ,分别存储整数2和6,如图01-01所示。要将变量a 和b 交换就意味着交换变量a 和变量b 中的值,使得变量a 存放变量b 交换前的值,而变量b 存放变量a 交换前的值,如图01-02所示。 图01-01 图01-02 语句“a=b; b=a;”是不能实现变量a 、b 交换的,只可能使得a 、b 最终都存放变量b 的值(大家可以编程试一试)。其原因是赋值操作具有覆盖性,执行a=b ;语句后,a 原来的值已经被覆盖了,此时a 最新的值就是b 的值,再实现b=a ;时,b 的值就是a 最新的值,也就是b 的值。 一、 中间变量法 要实现交换,最基本、最通用的方法是中间变量法。该方法的基本思路是定义第三个变量t ,用于暂时保存两个变量中的某一个变量的原值。具体实现代码如下: t = a; a = b; b = t; 交换过程请大家自己仿照图01-01自己给出。注意每一个变量画一个方框, 每执行一步后,改变被赋值变量的值。 【注意事项】 此处,中间变量t 可以暂存变量 a 的值也可以暂存变量 b 的值,不过一旦对变量t 的赋值语句确定后,后面两个赋值语句的顺序不是任意的。赋值顺序的记忆可总结为“t 中暂存的变量先被赋值”。即t = a; a = b; b = t;或者t = b; b = a; a = t;。

二、算术加减法 对于数值型数据还可以采用算术加减法来实现交换,其基本思想是以a获得b的值,以b获得a的值作为目标,进行加减运算,从而完成交换。具体实现可用如下代码: a = a+b; b = a-b; a = a-b; 三、思考与练习 1. 请编写程序验证“交换”算法。 2. 请编写程序验证“交换”算法,要求“交换”算法使用函数来实现。 3. 请大家思考一下,使用算术加减法实现的“交换”算法有什么限制? 4. 请大家思考一下,我们能不能使用乘除法来实现“交换”算法?如果可 以,那么具体代码如何来编写呢?使用乘除法来实现“交换”算法,有 什么限制呢? 5. 拓展 两个变量(一般为整型或字符型)的交换还可以使用“异或”运算符。 具体步骤如下: int a,b; a=a^b; b=a^b; a=a^b;

两个变量交换值

不使用第三方变量交换两个变量的值(c#)2009-07-22 16:47这需要进行位操作,必较麻烦的, 在学习程序语言和进行程序设计的时候,交换两个变量的值是经常要使用的。通常我们的做法是(尤其是在学习阶段):定义一个新的变量,借助它完成交换。代码如下: int a,b; a=10; b=15; int t; t=a; a=b; b=t; 这种算法易于理解,特别适合帮助初学者了解计算机程序的特点,是赋值语句的经典应用。在实际软件开发当中,此算法简单明了,不会产生歧义,便于程序员之间的交流,一般情况下碰到交换变量值的问题,都应采用此算法(以下称为标准算法)。 上面的算法最大的缺点就是需要借助一个临时变量。那么不借助临时变量可以实现交换吗?答案是肯定的!这里我们可以用三种算法来实现:1)算术运算;2)指针地址操作;3)位运算。 1)算术运算 简单来说,就是通过普通的+和-运算来实现。代码如下: int a,b; a=10;b=12; a=b-a; //a=2;b=12 b=b-a; //a=2;b=10 a=b+a; //a=10;b=10 通过以上运算,a和b中的值就进行了交换。表面上看起来很简单,但是不容易想到,尤其是在习惯标准算法之后。 它的原理是:把a、b看做数轴上的点,围绕两点间的距离来进行计算。 具体过程:第一句“a=b-a”求出ab两点的距离,并且将其保存在a中;第二句“b=b-a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a=b+a”求出b到原点的距离(a到原点距离与ab两点距离之和),并且将其保存在a中。完成交换。此算法与标准算法相比,多了三个计算的过程,但是没有借助临时变量。(以下称为算术算法) 2)指针地址操作 因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“a+10”表示以a为基地址的在a后10个a类数据单元的地址。所以理论上可以通过和算术算法类似的运算来完成地址的交换,从而达到交换变量的目的。即: int *a,*b; //假设 *a=new int(10); *b=new int(20); //&a=0x00001000h,&b=0x00001200h a=(int*)(b-a); //&a=0x00000200h,&b=0x00001200h b=(int*)(b-a); //&a=0x00000200h,&b=0x00001000h a=(int*)(b+int(a)); //&a=0x00001200h,&b=0x00001000h 通过以上运算a、b的地址真的已经完成了交换,且a指向了原先b指向的值,b指向原先a 指向的值了吗?上面的代码可以通过编译,但是执行结果却令人匪夷所思!原因何在? 首先必须了解,操作系统把内存分为几个区域:系统代码/数据区、应用程序代码/数据区、

运筹学题(交二)

第一章 1,(决策变量)(目标函数)及(约束条件)构成。称为三个要素, 2解决问题的目标函数是多个决策变量的线性函数,通常是求(最大值)或(最小值) 3一般地,假设线性规划数学模型中,有m个约束,有n个决策变量xj, j=1,2…,n,目标函数的变量系数用cj表示, cj称为(价值系数)。 约束条件的变量系数用aij表示,aij称为(工艺系数)。约束条件右端的常数用bi表示, bi称为(资源限量)。 4线性规划的解的四种形式:(有唯一最优解),(有无界解),(有多重解),(无可行解)。 5线性规划问题的标准型的形式,下列选项表述不正确的是(C)A.目标函数求最大值(有时求最小值) B.约束条件都为等式方程; C.变量xj为正数。 D.常数bi都大于或等于零; 6凸集的几何特征:(连接凸集中任意两点的线段仍在此集合内)。7.单纯形法求解时一定要将数学模型化为(标准型)。 8.当确定某一矩阵为基矩阵时,则基矩阵对应的列向量称为(基向量),其余列向量称为(非基向量) 9.对某一确定的基B,令非基变量等于零,利用式AX=b 解出基变量,则这组解称为基B的(基本解)

10.若线性规划可行解K非空,则K是(凸集). 11.线性规划的可行解集合K的点X是极点的充要条件为(X是基本可行解). 12.在单纯形方法中,求初始基可行解,列出初始单纯形表,求出检验数。其中(基变量)的检验数必为零; 13.在用单纯形法计算过程中,若存在一个σk >0,σk所对应的变量xk的系数列向量Pk 0,则该线性规划问题(没有有限最优解)。 14.单纯形计算方法中,是先找换出变量,还是先找换入变量? 答,先找换入变量。 15.进行旋转运算是指:在确定了换入变量和换出变量后,要把换入变量所对应的系数列向量变成(单位向量) 第二章 1.在互为对偶的一对原问题与对偶问题中,不管原问题是求极大或极小,原问题可行解目标函数值一定不超过其对偶问题尅星界的目标函数值。(错) 2.任何线性规划问题具有唯一的对偶问题(对) 3.若原问题可行且另一个问题不可行,则原问题(A) A.有无界解 B.有可行解 C.可能有可行解也可能没有 4.简述单纯形法与对偶单纯形法的区别 5.简述求原问题的对偶问题的方法 6.两个线性规划互为对偶式时,则原问题的目标值不超过对偶问题的

汇编语言的过程调用与c语言的函数调用

姓名:孙贵森 学号: 汇编语言地过程调用,如果需要传递参数,一般有种方法,通过寄存器来“传递”,或是通过参数来传递.(还有将所有参数制成参数列表并压栈地传递方法,但较少用.)通过寄存器来“传递”,不是真正意义上地传递,其只不过是事先在几个有限地寄存器中设置相应地值后,再调用过程,过程再直接读取这些寄存器地内容.可想而知,此法犹如语言中地全局变量,极易感染.而如果通过参数来传递,又不得不面临手工维护堆栈框架( )地重担.堆栈框架动态地存放着参数、调用过程地返回地址、过程局部变量、过程内地压栈等内容,也是不好对付地.一般情况下,一个普通地过程可能如下编写:文档来自于网络搜索 , ..... 作为遵从调用约定()调用者,则需这样调用上述过程: ; ; ; , * ; 而如果遵从调用约定,则: , ...... , [ ] ; , [ ]; ...... * ; , , ; ...... , [ ]; , [ ]; , [ ; , [ ]; ...... , ; * ;

在被调用地过程内,分为种情况: . 无参数,也无局部变量 . 有参数 . 有局部变量 当无参数且无局部变量时,堆栈中只是保存语句地下一条语句地地址,可以很安全地返回.而当有参数,使用伪指令地接收参数地形式,则会自动生成正确地返回代码.而当有局部变量,使用伪指令来定义局部变量,也会自动地生成正确地返回代码.在将参数压栈时,仍需将其打包为位地,文档来自于网络搜索 ; , ; ; 另一选择是,将用作地变量声明为. ; ; 还有另一种方法,即,总是传递指针. ; (, ) , ; , , , , , [] , , [] 这种方法在保留了我们可以声明仅需地变量类型地同时,也确保位地方法正确压栈.语言中地每一个函数都是一个独立地代码块.一个函数地代码块是隐藏于函数内部地,不能被任何其它函数中地任何语句(除调用它地语句之外)所访问(例如,用语句跳转到另一个函数内部是不可能地).构成一个函数体地代码对程序地其它部分来说是隐蔽地,它既不能影响程序其它部分,也不受其它部分地影响.换言之,由于两个函数有不同地作用域,定义在

变量交换的几种常见方法

变量交换的几种常见方法 前几天发现了一个问题:有人告诉我,要进行变量交换,就必须引入第三变量! 假设我们要交换a和b变量的值,如果写成 int a=5,b=10; a=b; b=a; 那么结果就是两个都是10,理由不言而喻。 所以就应该引入第三变量,在a的值被覆盖之前就把a的值保留好。int a=5,b=10,tmp; tmp=a; a=b; b=tmp; 这样,就要引入了第三个变量,然而,我们能不能不引入第三变量来实现变量交换呢? 答案自然是肯定的,首先我们可以这样设想,如果a的值被覆盖了,那么就没法知道b应该放什么值了, 所以,我们要保留a的值,因此我们可以把a和b的值合起来,放在a里,再把合起来的值分开,分别放到b和a中:

int a=5,b=10; a=a+b; //a=15,b=10 b=a-b; //a=15,b=5 a=a-b; //a=10,b=5 但是这样做有一个缺陷,假设它运行在vc6环境中,那么int的大小是4 Bytes,所以int变量所存放的最大值是2^31-1即2147483647,如果我们令a的值为2147483000,b的值为1000000000,那么a和b 相加就越界了。 事实上,从实际的运行统计上看,我们发现要交换的两个变量,是同号的概率很大,而且,他们之间相减,越界的情况也很少,因此我们可以把上面的加减法互换,这样使得程序出错的概率减少: int a=5,b=10; a-=b; //a=-5,b=10 b+=a; //a=15,b=5 a+=b; //a=10,b=5 通过以上运算,a和b中的值就进行了交换。表面上看起来很简单,但是不容易想到,尤其是在习惯引入第三变量的算法之后。 它的原理是:把a、b看做数轴上的点,围绕两点间的距离来进行计算。 具体过程:第一句“a-=b”求出ab两点的距离,并且将其保存在a 中;第二句“b+=a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a+=b”求出b到原点

交换两个变量值

//【习3.1】交换两个变量值问题讨论。 public class Swap { // ①不能实现交换两个变量值的方法 public static void swap(int x, int y) { int temp = x; x = y; y = temp; } public static void swap(Object x, Object y) //不行 { Object temp = x; //两个对象之间的赋值是引用赋值,传递的是引用,即变量的地址 x = y; //改变形式参数x的引用,而未能改变实际参数的值, y = temp; //相当于改变了指针的值,而未改变通过指针指向的变量值 } //交换了,但改变的值没有带回 // ②能够交换两个数组元素值 public static void swap(int[] table, int i, int j) // 交换数组中下标为i、j的元素 { if (table != null && i >= 0 && i < table.length && j >= 0 && j < table.length && i != j) // 判断i、j是否越界 { int temp = table[j]; table[j] = table[i]; table[i] = temp; } } public static void swap(Object[] table, int i, int j) //交换数组中下标为i、j的元素 { if (table != null && i >= 0 && i < table.length && j >= 0 && j < table.length && i != j) //判断i、j是否越界 {

C++中函数调用时的三种参数传递方式

在C++中,参数传递的方式是“实虚结合”。 ?按值传递(pass by value) ?地址传递(pass by pointer) ?引用传递(pass by reference) 按值传递的过程为:首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型的,然后把以求出的实参表达式的值一一存入到形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用。这种传递是把实参表达式的值传送给对应的形参变量,故称这种传递方式为“按值传递”。 使用这种方式,调用函数本省不对实参进行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也完全不会受到影响,仍为调用前的值。 [cpp]view plaincopy 1./* 2. pass By value 3.*/ 4.#include https://www.wendangku.net/doc/a115734001.html,ing namespace std; 6.void swap(int,int); 7.int main() 8.{ 9.int a = 3, b = 4; 10. cout << "a = " << a << ", b = " 11. << b << endl; 12. swap(a,b); 13. cout << "a = " << a << ", b = " 14. << b << endl; 15.return 0; 16.} 17.void swap(int x, int y) 18.{ 19.int t = x; 20. x = y; 21. y = t; 22.}

如果在函数定义时将形参说明成指针,对这样的函数进行调用时就需要指定地址值形式的实参。这时的参数传递方式就是地址传递方式。 地址传递与按值传递的不同在于,它把实参的存储地址传送给对应的形参,从而使得形参指针和实参指针指向同一个地址。因此,被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。 [cpp]view plaincopy 1.#include https://www.wendangku.net/doc/a115734001.html,ing namespace std; 3.void swap(int*,int*); 4.int main() 5.{ 6.int a = 3, b = 4; 7. cout << "a = " << a << ", b = " 8. << b << endl; 9. swap(&a,&b); 10. cout << "a = " << a << ", b = " 11. << b << endl; 12. system("pause"); 13.return 0; 14.} 15.void swap(int *x,int *y) 16.{ 17.int t = *x; 18. *x = *y; 19. *y = t; 20.} 按值传递方式容易理解,但形参值的改变不能对实参产生影响。 地址传递方式虽然可以使得形参的改变对相应的实参有效,但如果在函数中反复利用指针进行间接访问,会使程序容易产生错误且难以阅读。

复习题2(算法部份)

第1章计算机和算法 1.使用计算机解题的步骤,以下描述正确的是:_____。 A.正确理解题意→设计正确算法→寻找解题方法→编写程序→调试运行 B.正确理解题意→寻找解题方法→设计正确算法→编写程序→调试运行 C.正确理解题意→寻找解题方法→设计正确算法→调试运行→编写程序 D.正确理解题意→寻找解题方法→设计正确算法→编写程序→调试运行 答案:B 2.计算机是一种按照设计好的程序,快速、自动地进行计算的电子设备,计算机开始计算之前,必须把解决某个问题的程序存贮在计算机的_____中。 A.硬盘B.软盘C.内存D.CPU 答案:C 3.计算机程序由以下两部分即:_____组成。 A.执行部分和数据部分 B.数据部分和程序部分 C.指令部分和数据部分 D.程序部分和指令部分 答案:C 4.计算机程序由一系列指令构成,每条指令要求计算机执行_____动作。 A.一组B.二个C.一个D.一个以上 答案:C 5.计算机程序由指令部分和数据部分组成,其中数据部分用来存储_____。 A.计算所需的原始数据和计算的中间结果,不能存储计算的最终结果 B.计算所需的原始数据,不能存储计算的中间结果和计算的最终结果 C.计算的中间结果和计算的最终结果,不能存储计算所需的原始数据 D.计算所需的原始数据、计算的中间结果或最终结果 答案:D 6.人们在设计计算机程序时,_____。 A.只要考虑“数据的存贮”而不要考虑“计算的过程” B.不要考虑“数据的存贮”而只要考虑“计算的过程” C.必须同时考虑“数据的存贮”和“计算的过程” D.以上答案都错 答案:C 7.设计计算机程序时,要考虑“计算的过程”,其含义是在对解决问题的方法进行步骤化时,_____。 A.只要指出“动作”而不必指出“动作的次序” B.不必指出“动作”而只要指出“动作的次序” C.必须同时指出“动作”和“动作的次序” D.以上说法都正确 答案:C 8.算法的特征是:有穷性、_____、能行性、有0个或多个输入和有一个或多个输出。 A.稳定性B.确定性C.正常性D.快速性 答案:B

交换两个变量的值,不使用第三个变量的方法及实现

交换两个变量的值,不使用第三个变量的方法及实现: 附录中有C/C++代码: 通常我们的做法是(尤其是在学习阶段):定义一个新的变量,借助它完成交换。代码如下: int a,b; a=10; b=15; int t; t=a; a=b; b=t; 这种算法易于理解,特别适合帮助初学者了解计算机程序的特点,是赋值语句的经典应用。在实际软件开发当中,此算法简单明了,不会产生歧义,便于程序员之间的交流,一般情况下碰到交换变量值的问题,都应采用此算法(以下称为标准算法)。 上面的算法最大的缺点就是需要借助一个临时变量。那么不借助临时变量可以实现交换吗?答案是肯定的!这里我们可以用以下几种算法来实现:1)算术运算;2)指针地址操作;3)位运算;4)栈实现。 1)算术运算 int a,b; a=10;b=12; a=b-a; //a=2;b=12 b=b-a; //a=2;b=10 a=b+a; //a=12;b=10 它的原理是:把a、b看做数轴上的点,围绕两点间的距离来进行计算。 具体过程:第一句“a=b-a”求出ab两点的距离,并且将其保存在a中;第二句“b=b-a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a=b+a”求出b到原点的距离(a 到原点距离与ab两点距离之和),并且将其保存在a中。完成交换。 此算法与标准算法相比,多了三个计算的过程,但是没有借助临时变量。(以下称为算术算法)除了使用加、减法外,还可以使用乘、除法实现,实现代码如下: //if a=10;b=12; a=a*b; //a=120;b=12 b=a/b; //a=120;b=10 a=a/b; //a=12;b=10 缺点:是只能用于数字类型,字符串之类的就不可以了。a+b有可能溢出(超出int的范围),溢出是相对的,+了溢出了,-回来不就好了,所以溢出不溢出没关系,就是不安全。 2)指针地址操作 因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“a+10”表示以a为基地址的在a后10个a类数据单 元的地址。所以理论上可以通过和算术算法类似的运算来完成地址的交换,从而达到交换变量的目的。即:int *a,*b; //假设 *a=new int(10); *b=new int(20); //&a=0x00001000h,&b=0x00001200h a=(int*)(b-a); //&a=0x00000200h,&b=0x00001200h

函数调用参数传递类型(java)的用法介绍.

函数调用参数传递类型(java)的用法介绍. java方法中传值和传引用的问题是个基本问题,但是也有很多人一时弄不清。 (一)基本数据类型:传值,方法不会改变实参的值。 public class TestFun { public static void testInt(int i){ i=5; } public static void main(String[] args) { int a=0 ; TestFun.testInt(a); System.out.println("a="+a); } } 程序执行结果:a=0 。 (二)对象类型参数:传引用,方法体内改变形参引用,不会改变实参的引用,但有可能改变实参对象的属性值。 举两个例子: (1)方法体内改变形参引用,但不会改变实参引用,实参值不变。 public class TestFun2 { public static void testStr(String str){ str="hello";//型参指向字符串“hello” } public static void main(String[] args) { String s="1" ;

TestFun2.testStr(s); System.out.println("s="+s); //实参s引用没变,值也不变 } } 执行结果打印:s=1 (2)方法体内,通过引用改变了实际参数对象的内容,注意是“内容”,引用还是不变的。 import java.util.HashMap; import java.util.Map; public class TestFun3 { public static void testMap(Map map){ map.put("key2","value2");//通过引用,改变了实参的内容 } public static void main(String[] args) { Map map = new HashMap(); map.put("key1", "value1"); new TestFun3().testMap(map); System.out.println("map size:"+map.size()); //map内容变化了 } } 执行结果,打印:map size:2 。可见在方法testMap()内改变了实参的内容。 (3)第二个例子是拿map举例的,还有经常涉及的是 StringBuffer : public class TestFun4 {

汇编语言编程规范

软件设计更多地是一种工程,而不是一种个人艺术。如果不统一编程规范,最终写出的程序,其可读性将较差,这不仅给代码的理解带来障碍,增加维护阶段的工作量,同时不规范的代码隐含错误的可能性也比较大。 分析表明,编码阶段产生的错误当中,语法错误大概占20%左右,而由于未严格检查软件逻辑导致的错误、函数(模块)之间接口错误及由于代码可理解度低导致优化维护阶段对代码的错误修改引起的错误则占了一半以上。 可见,提高软件质量必须降低编码阶段的错误率。如何有效降低编码阶段的错误呢?这需要制定详细的软件编程规范,并培训每一位程序员,最终的结果可以把编码阶段的错误降至10%左右,同时也降低了程序的测试费用,效果相当显著。 本文从代码的可维护性(可读性、可理解性、可修改性)、代码逻辑与效率、函数(模块)接口、可测试性四个方面阐述了软件编程规范,规范分成规则和建议两种,其中规则部分为强制执行项目,而建议部分则不作强制,可根据习惯取舍。 1.排版 规则1 程序块使用缩进方式,函数和标号使用空格缩进,程序段混合使用TAB和空格缩进。缩进的目的是使程序结构清晰,便于阅读和理解。 默认宽度应为8个空格,由于Word中为4个空格,为示范清晰,此处用2个代替(下同)。 例如: MOV R1, #00H MOV R2, #00H MOV PMR, #PMRNORMAL MOV DPS, #FLAGDPTR MOV DPTR, #ADDREEPROM read1kloop: read1kpage: INC R1

MOVX A, @DPTR MOV SBUF, A JNB TI, $ CLR TI INC DPTR CJNE R1, #20H, read1kpage INC R2 MOV R1, #00H CPL WDI CJNE R2, #20H, read1kloop ;END OF EEPROM 规则2 在指令的操作数之间的,使用空格进行间隔,采用这种松散方式编写代码的目的是使代码更加清晰。 例如: CJNE R2, #20H, read1kloop ;END OF EEPROM 规则3 一行最多写一条语句。 规则4 变量定义时,保持对齐。便于阅读和检查内存的使用情况。 例如: RegLEDLOSS EQU 30H ; VARIABLE ; TESTLED==RegLEDLOSS.0 RegLEDRA EQU 31H ; VARIABLE

arm汇编语言调用C函数之参数传递

arm汇编语言调用C函数之参数传递 于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure Call Standard),ATPCS 主要是定义了函数呼叫时参数的传递规则以及如何从函数返回,关于ATPCS的详细内容可以查看ADS1.2 Online Books ——Developer Guide的2.1节。这篇文档要讲的是汇编代码中对C函数调用时如何进行参数的传递以及如何从C函数正确返回。 不同于x86的参数传递规则,ATPCS建议函数的形参不超过4个,如果形参个数少于或等于4,则形参由R0,R1,R2,R3四个寄存器进行传递;若形参个数大于4,大于4的部分必须通过堆栈进行传递。 我们先讨论一下形参个数为4的情况. 实例1: test_asm_args.asm //-------------------------------------------------------------------------------- IMPORT test_c_args ;声明test_c_args函数 AREA TEST_ASM, CODE, READONLY EXPORT test_asm_args test_asm_args STR lr, [sp, #-4]! ;保存当前lr ldr r0,=0x10 ;参数 1 ldr r1,=0x20 ;参数 2

ldr r2,=0x30 ;参数 3 ldr r3,=0x40 ;参数 4 bl test_c_args ;调用C函数 LDR pc, [sp], #4 ;将lr装进pc(返回main函数) END test_c_args.c //-------------------------------------------------------------------------------- void test_c_args(int a,int b,int c,int d) { printk("test_c_args:\n"); printk("%0x %0x %0x %0x\n",a,b,c,d); } main.c //-------------------------------------------------------------------------------- int main() { test_asm_args(); for(;;); } 程序从main函数开始执行,main调用了test_asm_args,test_asm_args 调用了test_c_args,最后从test_asm_args返回main。代码分别使用了

c 语言 交换两个变量的值

1. 交换两个变量的值:用两种方法: 1) main () (3-5-1a(3-5-1b) printf(“a,b=?”“a,b=?”); scanf(“%d,%d”“%d,%d”,&a,&b); pringf(“a=%d\tb=%d\n”“a=%d\tb=%d\n”,a,b) ; t=a;a=b;b=t; a=a+b;b=a-b;a=a-b; pringf(“a=%d\tb=%d\n”,a,b); pringf(“a=%d\tb=%d\n”,a,b); } /*利用第三变量*/ } /*利用自身*/ 3) 利用全局变量交换两个变量的值: int a=3,b=7; Qj-swap2 main() { swap () printf("%d,%d\n",x,y); } swap() { a=a+b;b=a-b;a=a-b} 4)利用指针变量交换两个变量的值: main () { int a=3,b=10,*pa=&a,*pb=&b; clrscr(); printf("a=%d\tb=%d\n",a,b); swap (pa,pb); printf("a=%d\tb=%d\n",*pa,*pb); } swap (int *x,int *y) { int *t; t=*x;*x=*y;*y=t; } 4)下列程序运行的结果: (1)int x=1,y=2; Qj-swap1 main () { int a=3,b=4; move(x,y);move(a,b); printf("%d, %d, %d, %d",x,y,a,b); } move(int p,int q) { int k ; k=p;p=q;q=k; }

算法设计与分析习题答案1-6章

习题1 1. 图论诞生于七桥问题。出生于瑞士的伟大数学家欧拉(Leonhard Euler ,1707—1783)提出并解决了该问题。七桥问题是这样描述的:一个人是否能在一次步行中穿越哥尼斯堡(现 在叫加里宁格勒,在波罗的海南岸)城中全部的七座桥后回到起点,且每座桥只经过一次, 图 1.7是这条河以及河上的两个岛和七座桥的 草图。请将该问题的数据模型抽象出来,并判断此问题是否有解。 七桥问题属于一笔画问题。 输入:一个起点 输出:相同的点 1, 一次步行 2, 经过七座桥,且每次只经历过一次 3, 回到起点 该问题无解:能一笔画的图形只有两类:一类是所有的点都是偶点。另一类是只有二个奇点的图形。 2.在欧几里德提出的欧几里德算法中(即最初的欧几里德算法)用的不是除法而是减法。请用伪代码描述这个版本的欧几里德算法 1.r=m-n 2.循环直到r=0 2.1 m=n 2.2 n=r 2.3 r=m-n 3 输出m 3.设计算法求数组中相差最小的两个元素(称为最接近数)的差。要求分别给出伪代码和C ++描述。 //采用分治法 //对数组先进行快速排序 //在依次比较相邻的差 #include using namespace std; int partions(int b[],int low,int high) { 图1.7 七桥问题

int prvotkey=b[low]; b[0]=b[low]; while (low=prvotkey) --high; b[low]=b[high]; while (low

深入了解C语言(函数的参数传递和函数使用参数的方法)

深入了解C语言(函数的参数传递和函数使用参数的方法) C语言生成的代码在执行效率上比其它高级语言都高.现在让我们来看看C语言生成的代码具体是什么样子的.当你看完本文对于C语言的了解一定会更深一步了. 本文通过一个个实际案例程序来讲解C语言. 研究案例一 工具: Turboc C v2.0,Debug,MASM v5.0,NASM 实例C程序: /* example1.c */ char ch; int e_main() { e_putchar(ch); } 目标内容:C语言调用函数的方法与细节 我们使用的C编译器是16位的Turboc C v2.0,它生成的是16位的代码,比较简单,方便我们来研究.同时我们也需要用到DOS下的DEBUG来进行反汇编.由于我们很多案例中的程序并不是完整的C程序,所以Turboc下的Tlink并不能为我们生成目标程序,所以我将使用MASM 中的link.exe,同时里面的https://www.wendangku.net/doc/a115734001.html,也可以为我们把exe文件转换成bin文件. 这个程序没有main函数,我们用e_main来代替main函数.这样我们能避开C语言对main函数进行一系列处理的代码.同样,我们也用e_putchar()来代替我们平常使用的putchar().这里"e"的意思就是"example". 没有了main函数,我们的C程序就没有了入口,所以在开始编译这段C代码之前,我还得写几行简单的汇编代码,通过它来作为我们程序的入口. ; C程序的入口start.asm [BITS 16] [global start] [extern _e_main] start: call _e_main 按照C语言的习惯,所以C总的名词都要自动在前面加一个"_"下划线.所以,我们在C中的e_main函数,如果要在汇编中调用,就变成了_e_main函数.这段汇编代码只有一句:call _e_main,就是调用我们在C中的e_main函数

相关文档
相关文档 最新文档