logo资料库

《C++ Primer Plus第6版中文版》学习笔记(第七章).doc

第1页 / 共79页
第2页 / 共79页
第3页 / 共79页
第4页 / 共79页
第5页 / 共79页
第6页 / 共79页
第7页 / 共79页
第8页 / 共79页
资料共79页,剩余部分请下载后查看
(九十二)函数 函数的分类: ①有返回值的; ②无返回值的。 无返回值函数: 被称为 void 函数,其通用格式如下: //可以不传递变量 void 函数名(传递的变量) { } 函数内部的代码; return; //可有可无 例如: void abc(int a) { using namespace std; //如果函数外面没有全局的 std,那么可以加上,或者用其替代版 for (int i = 0;i < a;i++) cout << i << endl; } 效果是输出 i,一直到 i 比传递的变量 a 小为止。 int a 表示在调用函数 abc 时,应传递一个参数给这个函数。比如 abc(5);就是让函 数在执行的时候 a=5。 有返回值的函数: 通用格式类似 void 函数,只不过 return 是必须的,并且需要返回一个函数值, 格式如: 类型名 函数名(传递的变量) //可以不传递变量 { 函数内部的代码; return 值; //必须有 } return 返回的值是根据类型名决定的。例如返回 5.1,假如类型名为 int,那么返 回值为 5(因为 int 类型强制转换返回值)。 返回值: C++对返回值的类型限制为:不能是数组,但可以是其他类型。比如 int,比如表 达式,比如指针,比如结构和对象(暂时还不能理解)。
另外,按照说明,虽然函数不能返回数组,但是可以将数组作为结构或者对象组 成部分来返回)。 函数在遇见第一个返回语句(return)后结束,无视后面的语句。 返回语句可以是表达式,例如 return a*a*a; 函数原型: 为什么需要函数原型: ①原型描述了函数到编译器的接口。——将函数返回值的类型,和参数的类型、 数量告诉编译器。 ②原型告诉编译器,函数需要什么。 例如代码: int abc(double); //函数原型 …… double b = abc(3.3); (1)比如在调用函数的时候,函数原型就告诉编译器,需要输入一个 double 类 型的值(假如输入类型错误,比如输入了一个 char 类型的,编译器就会提示错 误)。 //通过函数原型调用函数,将返回值用于赋值 (2)然后 abc(3.3)在调用函数并计算之后,返回一个值,并将该值放在一个指定 的位置上(可能是 CPU 寄存器,或内存之中,具体我不知道……),然后调用 函数(比如说 main())从这个位置取回返回值; 由于函数原型指出了 abc()的类型为 int,因此编译器知道应检索多少个字节,以 及如何解释他们。如果没有这些信息,编译器只能进行猜测,当然,编译器不可 能去猜他们。——还是不太理解这段话第二个逗号之后的意思。 ③之所以需要原型,而不是在使用的时候在文件中进行检索函数的定义。是因为 这样做效率低。因为在检索的时候,编译器停止对例如 main()的编译,甚至函数 定义可能不在文件之中。——文中的解释看起来有点晕。 ④但是函数原型是如何和函数定义相关联的?——即其机制是怎么样的? 函数原型的语法: 类型名 函数名(传递的变量); ①函数原型是一条语句,所以以分号结束“;”(英文的分号);
②如果有返回值的话,需要有对应的类型名;如果没有的话,可以为 void; ③函数名就是函数名,和函数定义的函数名要相同; ④如果有传递的变量,则写上变量名;如果没有,可以为空。可以加变量名,也 可以不加(并没有什么区别,变量名只是起到一个占位符的作用,也可以和函数 定义的变量名不一样)比如(int a)和(int)似乎没有区别。 ⑤可以直接复制函数定义的函数头,作为函数原型。 两种函数原型的区别(ANSI C 和 C++): ANSI C 借鉴了 C++的原型,但为了与基本 C 兼容,ANSI C 的原型是可选的,C++ 是必备。 double abc() ; 以上这个函数原型,在 C++里,绿色部分实质上和(void)是等价的; 在 ANSI C 中,意味着不指出参数——在之后定义参数列表(不懂!是指在函数 定义时么?)。 而 C++如果是不指定参数列表的话,应该用省略号,如 double abc(...) ; ————但是 C++中的不指定参数列表在实践中失败了。 一般仅当与接受可变参数的 C 函数(比如 printf())交互时才这么做。 原型的功能: 原型对程序员来说,可以极大的降低程序出错的几率。因为,原型可以确保以下 几点: ①编译器能正确处理函数返回值(通过函数的类型名); ②编译器检查使用的参数数目是否正确(比如需要 2 个参数,在调用的时候,是 否传递了 2 个参数); ③编译器检查使用的参数类型是否正确(比如 int 和 char)。如果不正确,则转 换为正确的类型(如果可能的话,比如把 int 转为 double,把 double 转为 int 之 类可以互转的); ④可以提示程序员,原型中传递的参数的变量名(作为占位符使用)在函数定义 中意味着什么(例如某个 int 类型变量表示传递的是血量,则在原型中使用 int hp) ⑤避免发生以下错误: (1)传递的变量的类型和要求的变量类型不同——此时将通过强制类型转换解 决这个问题(但前提两个都是算数类型); 不过潜在的错误是,将大的范围的数转为小的范围的数,可能会出错。比如某个 超出 int 类型范围的数转为 int。 函数原型自动将被传递的参数(比如 abc(5.5)中的 5.5)强制转换为期望的类型(比 如 int 类型的 5)。
(2)但若传递变量的类型和要求变量的类型差异较大时(比如 int 和指针),那 么不会启动强制转换——因为没有意义。 函数定义: 形参和实参: 例如一个函数头为:double abc (double x);在调用这个函数的时候,函数创建了 一个 double 变量 x,就像在函数里面进行声明一样。 只不过,这个变量 x 的值,是在调用的时候根据传递参数的值来确定的。 例如在调用函数时:double e=abc (5); 那么在调用函数 abc 的时候,x 的值就为 5。 假如说有代码: int a = 5; double b = abc(a); …… double abc(int x) { int b = x++; return b; } 在调用函数时,函数 abc 使用的 x 是之前函数中变量 a 的副本,对 x 的操作(x++) 将不影响之前函数中的变量 a。 对于这种情况,用于接收传递值的变量(在这里是 x)被称为形参(在 C++又被 称为参量 parameter); 传递给函数的值被称为实参(在这里是变量 a)(在 C++又被称为参数 argument)。 在函数中声明的变量,例如上面的 int b,以及形参(参量)(如上面的 int x), 是该函数(double abc)所私有的。 在函数被调用的时候,计算机为这些变量分配内存,在函数结束时,计算机将释 放这些函数的内存。因此,他们是局部变量(自动变量)。 形参和其他局部变量最大的区别是: ①形参从调用该函数的那里获得自己的值; ②而其他变量在函数内部获得自己的值。 多个参数: 函数可以有多个参数,在调用的时候,参数和参数之间用逗号分开即可。 例如:double abc(int a,double b,string c) 在调用的时候:double m=abc(1, 2.2, "abc") 三个不同类型的变量 1、2.2、abc 被同时传递给函数 abc 的三个不同类型的变量
a、b、c。 在声明的时候需要这么做:double abc(int, double, string); 和普通声明非常相似。 注意: ①多个参数的类型可以相同,也可以不同。 ②多个参数在传递变量时,要依次给一个确定的、且符合要求的值。 (九十三)函数与数组 当且仅当在函数头或者函数原型中: 例如:int *a 和 int a[] 这两个的含义是相同的,指的是 a 是一个 int 指针。 但是在函数调用和函数内部,这两个的含义并不相同。 指针算数: 在之前的指针算数中说过,指针实际上就是一个地址,是指针指向的那个地址; 指针可以直接和一个 int 值相加,结果是指针指向的地址偏移。 在使用函数时,传递参数可以是一个地址,通过传递地址、以及成员数量,然后 变相传递一个数组。 例如代码: //关键词:随机受到多次伤害,并通报每次伤害的值。 #include #include //函数 clock()使用 #include //函数 Sleep()使用 using namespace std; const int number = 5; //常量 number,方便修改次数 int dam(int*str, int cishu); //总伤害=每次的伤害之和 int main() { int abc[number]; cout << "你受到了" << number << "次伤害,系统将随机计算这" << number << "次的伤害值: " << endl; for (int i = 0;i < number;i++) //为数组循环赋值,利用循环数 { double delay = rand() % 1000; //随机一个 rand 值,范围为 0~999。注意,这是伪随机 数,所以每次随机的结果似乎都是一样的。
cout << "等待" << delay / 1000 << "秒,计算下次伤害" << endl; Sleep(delay); //等待 rand 值的毫秒 abc[i] = clock() % 100; //利用时钟除以 100 求余,计算 0~99 的随机值,并为数组成 cout << "你受到的第一次伤害为:" << abc[i] << endl; //通报数组成员的值 员赋值 } int total = dam(abc, number); //定义 total,传递的函数为数组 abc(的地址),以及数组 成员的个数 number cout << "你总共受到了" << total << "点伤害。" << endl; cout << "sizeof 总伤害的数组: " << sizeof(abc) << endl << endl; //计算前 3 次伤害 total = dam(abc, 3); //计算前 3 次伤害 cout << "你前三次总共受到了" << total << "点伤害。" << endl; //偏移指针 total = dam(abc + 2, 3); //计算第 3~5 次伤害 cout << "你第三次~第五次总共受到了" << total << "点伤害。" << endl; system("pause"); return 0; } int dam(int*str, int m) { int total = 0; for (int i = 0;i < m;i++) total = total + str[i]; //等于之前的和加现在的这个 cout << "dam 函数中的指针的地址:"<
分享到:
收藏