《C++PrimerPlus 6th Edition》第7章 函数 要点记录

《C++PrimerPlus 6th Edition》第7章 函数 要点记录

要点

  1. 要使用函数,必须完成如下工作:①提供函数原型;②提供函数定义;③调用函数

  2. C++对于返回值的类型有一定限制:不能是数组,但可以是其他任何类型——整数、浮点数、指针、甚至结构和对象(虽然C++函数不能直接返回数组,但可以将数组作为结构或对象的组成部分来返回)

  3. 函数原型:比如:double add(double a, double b);
    需要函数原型的原因:①原型描述了函数到编译器的接口,也就是说,它将函数返回值的类型(如果有的话)以及参数的类型和数量告诉编译器;②如果不定义函数原型,编译器就需要在文件中查找被调用函数,这往往效率不高,因为编译器在搜索文件的剩余部分时必须停止对main()的编译;③更严重地是,函数甚至可能并不在文件中;④C++允许将一个程序放在多个文件中,单独编译这些文件,然后再将它们组合起来,这种情况下,编译器在编译main()时,可能无权访问函数代码
    避免使用函数原型的唯一方法是,在首次使用前定义它,但这并不总是可行的。C++的编程风格是将main()放在最前面,因为它通常提供了程序的整体结构

  4. 函数原型不要求提供变量名,即使提供变量名也不要求原型中的变量名与定义中的变量名相同

  5. C++原型与ANSI C原型的比较:①ANSI C中的原型是可选的,但在C++中原型必不可少; ②对于void say_hi();在C++中,括号为空与在括号中使用void是等效的——意味着函数没有参数;但在ANSI C中,括号为空意味着不指出参数——这意味着将在后面定义参数列表;③C++中,不指定参数列表时应使用省略号void say_bye(...);,这通常仅当与接受可变参数的C函数(如printf())交互时才需要这样做

  6. 原型的功能:原型确保:①编译器正确处理函数的返回值;②编译器检查使用的参数数目是否正确;③编译器检查使用的参数类型是否正确

  7. 自动类型转换并不能避免所有可能的错误。当较大的类型被自动转换为较小的类型时,有些编译器将发出警告,指出这可能丢失数据

  8. 仅当有意义时,原型化才会导致类型转换。比如,原型不会将整数转换为结构或指针

  9. 在编译阶段进行的原型化被称为静态类型检查(static type checking),它可捕获许多在运行阶段非常难以捕获的错误

  10. C++标准使用参数(argument)来表示实参,使用参量(parameter)来表示形参

  11. 对于类似排列组合等以乘除为主的迭代计算,为了避免超越存储范围,可以将乘除运算交替进行

  12. 有些C++实现不支持long double类型,如果这样则使用double或另想办法

  13. 在C++中,当且仅当用于函数头或函数原型中,int* arrint arr[]的含义才是相同的,它们都意味着arr是一个int指针。然而,数组表示法(int arr[])提醒用户,arr不仅指向int,还指向数组中的第一个int

  14. 传递常规变量时——按值传递;传递数组时——引用传递。实际上这种区别并不违反C++按值传递的方法,对于传递数组,实际上传递的是数组的首元素地址,也是一个值,此值传递给了一个指针,只不过通过这个值可以对相应元素进行修改

  15. 字符串与其他数组作为实参传递给函数时的区别:①对于非字符串类型的数组,必须额外提供一个参数指出数组长度,而字符串可以通过'\0'来识别串尾,无需额外提供这种参数

  16. 如果传入函数的数组需要填充或修改,则不用const修饰;如果只是读取数组的内容而不修改,则可使用const实现对数组的保护,如显示数组:void show(const double str[], int n);填充数组:int fill(double str[], int limit);

  17. 可以把非常量指针的值赋给常量指针const type*,但反过来不行:因为如果可以反过来,意味着被赋予值的非常量指针可以对变量值进行修改,这样const也就没意义了。如果一定要这么做,使用运算符const_cast

  18. 关于常量指针的几个微妙问题
    pt的声明并不意味着它指向的值实际上就是一个常量,而只是意味着对pt而言,这个值是常量。可以直接通过age变量来修改age的值,但不能使用pt指针来修改它

    int age = 39;
    const int* pt = &age;
    *pt = 20; //INVALID
    age = 20; //VALID
    

    进入两级间接关系时,与一级间接关系一样将const和非const混合的指针赋值方式将不再安全。如果允许这么做,那么就会有以下代码:

    const int** pp2;
    int* p1;
    const int n = 13;
    pp2 = &p1; //not allowed, but suppose it were
    *pp2 = &n; //valid 
    *p1 = 10; // valid, but changes const n
    

    仅当只有一层间接关系时,才可以将非const地址或指针赋给const指针

  19. 尽可能使用const的理由:①可以避免由于无意间修改数据而导致的编程错误;②使用const使得函数能够处理const和非const实参,否则将只能接受非const数据

  20. 对于void show_array(const double ar[], int n);,这里的数组元素是基本类型,但如果是指针或指向指针的指针,则不能使用const

  21. 函数与二维数组:以下表示二维数组的都等价:int sum(int (*ar2)[4],int size);int sum(int ar2[][4],int size); 由于其中的ar2相当于指向指针的指针,故没有使用const

  22. 变量pstr的作用域为buildstr函数内,因此该函数结束时,pstr(而不是字符串)使用的内存将会被释放,但由于函数返回了pstr的值,因此程序仍可以通过main()中的指针ps来访问新建的字符串。

    char* buildstr(char c,  int n){
       char* pstr = new char[n+1];
       pstr[n] = '\0';
       while(n-->0){
       	pstr[n] = c;
       }
       return pstr;
    }
    
  23. 函数与结构:与数组名就是数组的数组的第一个元素不同的是,结构名只是结构的名称,要获得结构的地址,必须使用地址运算符&

  24. string作为传递给函数的实参时,是按值传递;模板array也是如此

  25. 模板array并非只能存储基本数据类型,它还可以存储类对象

  26. 函数指针使用流程:①获取函数的地址;②声明一个函数指针;③使用函数指针来调用函数

  27. 注意:对于函数指针pf,如double (*pf)(int);,以下两种使用方法都可以:①double x =(*pf)(5);double x =pf(5);

  28. 可以使用auto或typedef对类型名字进行简化,这里我给出本章习题10的代码,基本就是函数指针的典型用法了,可以自行体会

#include<iostream>
#include<cstdlib>
using namespace std;

typedef double (*calc_fun)(double,double);

double add(double,double);
double sub(double,double);
double multiply(double,double);
double divide(double,double);
double calculate(double,double,calc_fun);

int main(){
	calc_fun pf[4]{add, sub, multiply, divide};
	double x,y;
	cout<<"Please enter x and y (q to quit): ";
	const char* calc_means[4]{"A+B= ","A-B= ","A*B= ","A/B= "};
	while(cin>>x>>y){
		for(int i=0; i<4; ++i){
			cout<<calc_means[i];
			cout<<(*pf[i])(x,y)<<endl;
		}
		cout<<"Next Round enter x and y (q to quit): ";
	}
	cout<<"Done\n";
	return 0;
} 

double add(double a, double b){
	return a+b;
}

double sub(double a, double b){
	return a-b;
}

double multiply(double a, double b){
	return a*b;
}
double divide(double a, double b){
	if(b == 0.0){
		cout<<"Cannot devide By Zero!\n";
		exit(-1);
	}
	return a / b;
}	

习题

习题参考代码见我的github(上传后会把链接打上)

欢迎各位大佬们于评论区进行批评指正~


上一篇文章:《C++PrimerPlus 6th Edition》第6章 分支语句和逻辑运算符 要点记录

下一篇文章:《C++PrimerPlus 6th Edition》第8章 函数探幽 要点记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值