热度 11
2014-2-14 10:00
2547 次阅读|
1 个评论
五.函数 1.数值传递与地址传递 参数按数值传递和按地址传递(Arguments passed by value and byreference)到目前为止,我们看到的所有函数中,传递到函数中的参数全部是按数值传递的(byvalue)。也就是说,当我们调用一个带有参数的函数时,我们传递到函数中的是变量的数值而不是变量本身。例如,假设我们用下面的代码调用我们的第一个函数 addition : int x=5, y=3, z; z = addition ( x , y ); 在这个例子里我们调用函数 addition 同时将 x 和 y 的值传给它,即分别为 5 和 3,而不是两个变量:这样,当函数addition被调用时,它的变量a和b的 值分别变为5和3,但在函数addition内对变量 a 或 b 所做的任何修改不会影响变量他外面的变量 x 和 y 的值,因为变量 x和 y 并没有把它们自己传递给函数,而只是传递了他们的数值。 但在某些情况下你可能需要在一个函数内控制一个函数以外的变量。要实现这种操作, 我们必须使用按地址传递的参数(arguments passed by reference),就象下面例子中 的函数 duplicate: // passing parameters by reference #include void duplicate (int a, int b, int c)//采用按地址传递的方式传入参数 { a*=2; b*=2; c*=2; } int main () { int x=1, y=3, z=7; duplicate (x, y, z); x=2, y=6, z=14 cout "x=" x ", y=" y ", z=" z; return 0; } 第一个应该注意的事项是在函数 duplicate 的声明(declaration)中,每一个变量的类型后面跟了一个地址符 ampersand sign (),它的作用是指明变量是按地址传递的(byreference),而不是像通常一样按数值传递的(by value) 按地址传递(Passing by reference)是一个使函数返回多个值的有效方法。例如,下面是一个函数,它可以返回第一个输入参数的前一个和后一个数值。 参数的默认值(Default values n n n in arguments) 当声明一个函数的时候我们可以给每一个参数指定一个默认值。如果当函数被调用时没有给出该参数的值,那么这个默认值将被使用。指定参数默认值只需要在函数声明时把一个数值赋给参数。如果函数被调用时没有数值传递给该参数,那么默认值将被使用。但如果有指定的数值传递给参数,那么默认值将被指定的数值取代。例如: // default values in functions #include int divide (int a, int b=2) { int r; r=a/b; return (r); } int main () { cout divide (12); cout endl; cout divide (20,4); return 0; } 6 5 我们可以看到在程序中有两次调用函数 divide。第一次调用: divide (12) 只有一个参数被指明,但函数 divide 允许有两个参数。因此函数 divide 假设第二个参数的值为2,因为我们已经定义了它为该参数缺省的默认值(注意函数声明中的int b=2)。因此这次函数调用的结果是 6 (12/2)。 在第二次调用中:divide (20,4)这里有两个参数,所以默认值 (int b=2) 被传入的参数值 4 所取代,使得最后结果为 5(20/4). 函数重载(Overloaded functions) 两个不同的函数可以用同样的名字,只要它们的参量(arguments)的原型(prototype)不同,也就是说你可以把同一个名字给多个函数,如果它们用不同数量的参数,或不同类型的参数。例如: // overloaded function即当存在两个相同的函数时,编译器会自动选择匹配的函数。 #include int divide (int a, int b) { return (a/b); } float divide (float a, float b) { return (a/b); } int main () { int x=5,y=2; float n=5.0,m=2.0; cout divide (x,y); cout "\n"; cout divide (n,m); cout "\n"; return 0; } 2 2.5 在这个例子里,我们用同一个名字定义了两个不同函数,当它们其中一个接受两个整型(int)参数,另一个则接受两个浮点型(float)参数。编译器 (compiler)通过检查传入的参数的类型来确定是哪一个函数被调用。如果调用传入的是两个整数参数,那么是原型定义中有两个整型(int)参量的函数被调用,如果传入的是两个浮点数,那么是原型定义中有两个浮点型(float)参量的函数被调用。为了简单起见,这里我们用的两个函数的代码相同,但这并不是必须的。你可以让两个函数用同一个名字同时完成完全不同的操作。 Inline 函数(inline functions) inline 指令可以被放在函数声明之前,要求该函数必须在被调用的地方以代码形式被编译。这相当于一个宏定义(macro)。它的好处只对短小的函数有效,这种情况下因为避免了调用函数的一些常规操作的时间(overhead),如参数堆栈操作的时间,所以编译结果的运行代码会更快一些。 它的声明形式是: inline type name ( arguments ... ) { instructions ... } 它的调用和其他的函数调用一样。调用函数的时候并不需要写关键字 inline ,只有在函数声明前需要写 六.数组 注意:同时给数组赋多个值只有在数组初始化时,也就是在声明数组时,才是合法的。 象下面代码现实的表达式都是错误的: mystring = "Hello"; mystring = "Hello"; mystring = { 'H', 'e', 'l', 'l', 'o', '\0' } 给字符数组的赋值 因为赋值运算的 lvalue 只能是数组的一个元素,而不能使整个数组,所以,用以下方 式将一个字符串赋给一个字符数组是合法的: mystring = 'H'; mystring = 'e'; mystring = 'l'; mystring = 'l'; mystring = 'o'; mystring = '\0'; 但正如你可能想到的,这并不是一个实用的方法。通常给数组赋值,或更具体些,给字符序列赋值的方法是使用一些函数,例如 strcpy。strcpy (string copy) 在函数库 cstring (string.h) 中被定义,可以用以下方式被调用: strcpy (string1, string2); 这个函数将 string2 中的内容拷贝给 string1。string2 可以是一个数组,一个指针, 或一个字符串常量 constant string。因此用下面的代码可以将字符串常量"Hello"赋给mystring: strcpy (mystring, "Hello"); 例如: // setting value to string #include #include int main () { char szMyName ; strcpy (szMyName,"J. Soulie");//给数组元素赋值 cout szMyName; return 0; } J. Soulie 注意:我们需要包括头文件才能够使用函数 strcpy。 虽然我们通常可以写一个像下面 setstring 一样的简单程序来完成与 cstring 中 strcpy 同样的操作: // setting value to string #include void setstring (char szOut , char szIn )//作用等同于strcpy函数 { int n=0; do { szOut = szIn ; } while (szIn != '\0'); } int main () { char szMyName ; setstring (szMyName,"J. Soulie"); cout szMyName; return 0; } 另一个给数组赋值的常用方法是直接使用输入流(cin)。在这种情况下,字符序列的值是在程序运行时由用户输入的。 当 cin 被用来输入字符序列值时,它通常与函数 getline 一起使用,方法如下: cin.getline ( char buffer ; cout "What's your name? "; cin.getline (mybuffer,100); cout "Hello " mybuffer ".\n"; cout "Which is your favourite team? "; cin.getline (mybuffer,100);//给数组元素赋值 What's your name? Juan Hello Juan. Which is your favourite team? Inter Milan I like Inter Milan too. cout "I like " mybuffer " too.\n"; return 0; } 注意上面例子中两次调用 cin.getline 时我们都使用了同一个字符串标识 (mybuffer)。程序在第二次调用时将新输入的内容直接覆盖到第一次输入到 buffer 中 的内容。 你可能还记得,在以前与控制台(console)交互的程序中,我们使用 extraction operator() 来直接从标准输入设备接收数据。这个方法也同样可以被用来输入字符串,例如, 在上面的例子中我们也可以用以下代码来读取用户输入: cin mybuffer; 这种方法也可以工作,但它有以下局限性是 cin.getline 所没有的: • 它只能接收单独的词(而不能是完整的句子),因为这种方法以任何空白符为分隔 符,包括空格 spaces,跳跃符 tabulators,换行符 newlines 和回车符 arriage returns。 • 它不能给 buffer 指定容量,这使得程序不稳定,如果用户输入超出数组长度,输入信息会被丢失。 因此,建议在需要用 cin 来输入字符串时,使用 cin.getline 来代替 cin 。 字符串和其它数据类型的转换(Converting strings to other types) 鉴于字符串可能包含其他数据类型的内容,例如数字,将字符串内容转换成数字型变量的功能会有用处。例如一个字符串的内容可能是"1977",但这一个 5 个字符组成序列,并不容易转换为一个单独的整数。因此,函数库 cstdlib (stdlib.h) 提供了 3 个有用 的函数: • atoi: 将字符串 string 转换为整型 int • atol: 将字符串 string 转换为长整型 long • atof: 将字符串 string 转换为浮点型 float 所有这些函数接受一个参数,返回一个指定类型的数据(int, long 或 float)。这三个函数与 cin.getline 一起使用来获得用户输入的数值,比传统的 cin 方法更可靠: // cin and ato* functions Enter price: 2.75 #include #include int main () { char mybuffer ; float price; int quantity; cout "Enter price: "; cin.getline (mybuffer,100); price = atof (mybuffer); cout "Enter quantity: "; cin.getline (mybuffer,100); quantity = atoi (mybuffer); cout "Total price: " price*quantity; return 0; } 字符串操作函数(Functions to manipulate strings) 函数库 cstring (string.h) 定义了许多可以像 C 语言类似的处理字符串的函数 (如前 面已经解释过的函数 strcpy)。这里再简单列举一些最常用的: • strcat: char* strcat (char* dest, const char* src); //将字符串 src 附加到字符串 dest 的末尾,返回 dest。 • strcmp: int strcmp (const char* string1, const char* string2); //比较两个字符串 string1 和 string2。如果两个字符串相等,返回 0。 • strcpy: char* strcpy (char* dest, const char* src); //将字符串 src 的内 容拷贝给 dest,返回 dest 。 • strlen: size_t strlen (const char* string); //返回字符串的长度。 注意:char* 与 char[] 相同。