C++ Primer Plus第七章读书笔记

本文详细介绍了C++中的函数基础知识,包括函数分类、返回值处理、原型与调用、参数传递(按值与引用)、数组与指针、结构、字符串操作、递归、函数指针等概念及其使用方法。
摘要由CSDN通过智能技术生成

第一次写博客,如有错误,请指正,感谢!

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);

  • 26
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值