第一次写博客,如有错误,请指正,感谢!
7.1 复习函数的基本知识
创建自己的函数需要:提供函数定义,提供函数原型(习惯称其为函数声明),调用函数(库函数头文件提供原型,正常调用即可)
#include <iostream>
using namespace std;
void test(); //函数声明
int main()
{
test(); //函数调用
system("pause");
return 0;
}
void test()//函数定义
{
cout << "函数定义主体部分" << endl;
}
这是一个简单的函数定义加声明以及调用的例子,cout 也属于一个函数,需要包含头文件后才能使用。
7.1.1 定义函数
1.将函数分为两类:有返回值(typeName)和无返回值(void).其中typename可以为整型、浮点型、指针、结构和对象,数组不能为返回值
2.函数如何返回值:通过将返回值复制到指定的CPU寄存器或内存单元中将其返回。随后,调用程序将查看该内存单元。返回函数和调用函数必须就该内存单元存储的数据类型达成一致
7.1.2 函数原型和函数调用
1.函数原型的作用:传入的参数是否匹配;返回值放入指定位置;调用函数时取得返回值并且知道其类型;
2.函数原型的用法:函数定义复制后加分号即可,参数名可以没有,但是还是建议加上,代码阅读起来比较方便;
C++和ANSI C(C89)的区别:
C++括号为空和使用void一样,C89中括号为空意味着不指出参数,在后面会定义参数列表。C++中不指定参数列表应使用省略号…
3.函数原型的功能:帮助编译器工作,使程序员降低程序出错概率;函数原型自动将被传递的参数强制转换成期望的类型。
7.2 函数参数和按值传递
传递给函数的值称为实参(参数,argument),用于接收传递值的变量称为形参(参量,parameter)。
在函数声明的变量(包含参数)是该函数私有的,函数调用时变量分配内存,函数结束时释放内存。这些变量统称为局部变量。
7.2.1 多个参数
ch为char类型的参数,cin.get(ch)读取所有的输入字符,包括空格和换行符,cin>>跳过空格和换行符
7.2.2 接收两个参数的函数
排列组合公式:C(n,m) = (n * n-1 * n-2 …*n-m+1)/(m * m-1 * …*1)
long long double reslut = 1.0;
for(n = numbers, p = pick; p > 0; n--,p--)
{
result = result * n / p;
}
不将所有分子分母相乘后再相除,而是交替进行乘除运算以防止中间结果超出最大的浮点数。
7.3 函数和数组
int sum_arr(int arr[], int n);其中arr不是一个数组而是指针。可以用
int sum_arr(int *arr, int n)代替
7.3.1函数如何利用指针处理数组
1.arr[i] = *(arr + i)
2.&arr[i] = arr + i
7.3.2 将数组作为参数意味着什么
sizeof(arr)实际上是指针变量的长度,一般为4,不能在sum_arr函数中使用sizeof(arr)的原因是指针本身没有指出数组的长度。
int sum_arr(int arr[], int n); [√]
int sum_arr(int arr[4], int n);[x]
7.3.3更多数组示例
while(cin) =====> while(!cin.fail()) //while the stream is OK
while(!cin) =====> while(cin.fail()) //while the stream is NOT OK
7.3.5 指针和const
int age = 39;
const int* pt = &age; //pt是指向一个const int的指针,可以指向另外一个变量,但不能使用pt来修改变量值
*pt = 2; cin >> *pt; //error
/***********************************************/
int sloth = 3;
int *const ps = &sloth;//ps只能指向sloth,sloth可以通过ps来修改
const 变量的地址可以赋给指向const的指针,而const的地址不能赋给常规指针;非const变量的地址可以赋给指向const的指针
const int age = 39;
const int* pt1 = &age; (√)
int* pt2 = &age; (×)
int price = 12;
const int* pt3 = &price; (√)
尽可能使用const的原因
1.避免无意间修改数据造成的错误
2.使用const使得函数可以处理const和非const实参,否则只能处理非const数据
7.4函数和二维数组
int data[3][4] = {{1,2,3,4},{2,3,4,5},{3,4,5,6}};
int total = sum(data, 3);//将行数作为参数
sum函数原型为
int sum(int (*arr)[4], int size);或 int sum(int arr[][4], int size);
arr[r][c] = *( *(arr + r) + c)
7.5函数和C-风格字符串
7.5.1将C-风格字符串作为参数的函数
表示字符串有三种(均为char指针):
1.char数组
2.用引号括起的字符串常量
3.被设置成字符串的地址的char指针
int main()
{
char str[] = "abc";
const char * arr = "cvb";
cout << sizeof("abc") << endl; //4
cout << sizeof(str) << endl; //4
cout << strlen("abc") << endl; //3
cout << strlen(str) << endl; //3
cout << sizeof(*arr) << endl; //1
//cout << strlen(*arr) << endl; //error
cout << sizeof(arr) << endl; //4
cout << strlen(arr) << endl; //3
return 0;
}
7.5.2返回C-风格字符串的函数
函数无法返回一个字符串。返回的是字符串的地址
7.6函数和结构
分为按值传递和按址传递,通常采用传递地址的地址的方式
int ch;
cin >> ch ==>当输入不为int 类型时会发生错误,返回一个false值
struct travel_time
{
int hours;
int mins;
}
//按值传递
travel t1,t2;
travel_time sum(travel_time t1, travel_time t2);//声明
travel_time t = sum(t1,t2);//调用
travel_time sum(travel_time t1, travel_time t2)//定义
{
travel_time time;
time.hours = t1.hours + t2.hours + (t1.mins + t2.mins)/60;
time.mins = (t1.mins + t2.mins) % 60;
return time;
}
//按址传递
travel_time* sum(travel_time* t1, travel_time* t2);//声明
travel_time* t = sum(&t1,&t2);//调用
travel_time* sum(travel_time * t1, travel_time * t2)//定义
{
travel_time time;//不能创建一个travel_time指针类型,会导致运行不过
time.hours = t1->hours + t2->hours + (t1->mins + t2->mins) /60;
time.mins = (t1->mins + t2->mins) % 60;
return &time;//返回结构的指针
}
主要修改:
调用函数时将结构地址(&t1)传入而不是将结构本身传入(t1);
形参声明为指向结构的指针,即为travel_time*类型;
形参为指针,应使用间接成员运算符(->),而不是成员运算符(.);
7.7 函数和string对象
string list[5] //数组list包含五个string元素
getline(cin,list[i]) //输入字符串存到list中
7.8 函数和array对象
void fill(array<double ,4> *pa)
{
for(int i = 0; i < 4; i++)
{
cin << (*pa)[i];
}
}
7.9 递归
递归代码:
void recurs(argumens1)
{
ststement1;
if(test)
{
recurs(arguments2)
}
statement2;
}
只要if为true,每个recurs调用将执行statement1,再调用recurs(),不会调用statement2.。
if为false时,将执行调用statement2,结束后将返回调用它的recurs(),而recurs()将继续执行其statement2,依此类推。如果recurs执行n次,则statement1将顺序执行n次,statement2将相反的执行n次。
7.10 函数指针
7.10.1 基础知识
将函数的地址传给另一个函数:
1.获取函数的地址
eg:think()函数==>process(think)
2.声明一个函数指针
根据要调用的函数声明来写函数指针
eg:调用的函数为:double pam(int),则函数指针为:double (*pf)(int)
3.使用函数指针来调用函数
使用( *pf)时将其看成一个函数即可
7.10.2 深入探讨函数指针
const double* f1(const double ar[],int n);
const double* f2(const double [],int n);
const double* f3(const double *,int n);
以上三个函数参数和返回类型相同,const double ar[]和
const double* ar含义相同,函数原型可以省去标识符即f2,f3;
1.声明一个指针指向三个函数之一:
const double* (* pa)(const double ar[],int n);
2.声明并初始化
const double* (* pa)(const double ar[],int n) = f1;
3.利用自动类型推断:
auto pb = f2;
cout << (*pa)(av, 3) << *(*pa)(av, 3) << endl;
cout << pb(av, 3) << *pb(av, 3) << endl;
前半部分显示的是double*即double的地址,+取地址( *)后,后半部分显示的是地址的实际值
//利用函数指针数组指向三个函数
const double* (*pa[3])(const double ar[],int n) = {f1, f2, f3};
auto pb = pa;
//调用函数(??)
const double* px = pa[0](av, 3);
const double* py = pb[1](av, 3);
自动类型推断只能用于单值初始化,不能用于初始化列表
pa与&pa区别:
多数情况下,pa时第一个元素的地址,&pa是一整个数组的地址,虽然两者的值相同,但类型不同,
pa+1为下一个元素地址(pa+sizeof(类型));
而&pa+1的地址为pa的地址+sizeof(pa);