栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++

本章内容包括:
  • 函数基本知识
  • 函数原型
  • 按值传递
  • 处理数组的函数
  • const指针参数
  • 处理文本字符串的函数
  • 处理结构的函数
  • 处理string对象的函数
  • 调用自身的函数(递归)
  • 指向函数的指针
7.1 函数基本知识

原型、调用、定义

7.1.1 定义函数
  • 无返回值return可选,有返回值return必须
  • 返回值类型不能直接为数组
  • 可以将数组作为结构或对象组成部分间接返回
7.1.2 函数原型和函数调用
  • 为什么需要原型? 事先打个招呼,不致于太陌生
  • 原型参数列表中,可以包括变量名,也可以不包括(饭店订餐问几人几点到,而不会问每个人姓名)
7.2 函数参数和按值传递 7.2.1 多个参数
  • 如果函数的两个参数类型相同,必须为每个参数指定类型
    void fifi(float a, float b)
    void fufu(float a, b)    //NOT acceptable
//程序清单7.3
//函数有两个参数
#include 

using namespace std;

void n_chars(char c, int n);

int main(void)
{
	char ch;
	int times;

	cout << "Enter a character: ";
	cin >> ch;
	while (ch != 'q')
	{
		cout << "Enter an integer: ";
		cin >> times;
		n_chars(ch, times);
		cout << "nEnter another character or press the q-key to quit: ";
		cin >> ch;
	}
	cout << "The value of times is " << times << ".n";
	return 0;
}

void n_chars(char c, int n)
{
	while (n-- > 0)
		cout << c;
}
  • ch是字符,字符与数字混合输入时,cin>>ch可以跳过换行符
  • ch是字符串时,字符串与数字混合输入,cin.get(ch),注意消耗换行符
    while(cin.get() != 'n')
        continue;
7.3 函数和数组
//程序清单7.5
//函数与一维数组
#include 

using namespace std;

const int ArSize = 8;

int sum_arr(int arr[], int n);

int main(void)
{
	int cookies[ArSize] = {1, 2, 4, 8, 16, 32, 64, 128};
	int sum = sum_arr(cookies, ArSize);
	cout << "Total cookies eaten: " << sum << endl;
	return 0;
}

int sum_arr(int arr[], int n)
{
	int total = 0;
	for (int i = 0; i < n; i++)
		total += arr[i];
	return total;
}
  • C++将数组名解释为其第一个元素的地址:cookies == &cookies[0]
  • 该规则有一些例外。首先数组声明使用数组名标记存储位置;其次对数组名使用sizeof得到整个数组的长度;第三地址运算符&用于数组名时返回整个数组的地址
int sum_arr(int arr[], int n)    //数组表示法
int sum_arr(int * arr, int n)    //指针表示法
//int arr[] 标识起始位置
//int n 标识整个数组在内存中的地址范围

arr[i] == *(arr + i)    //arr指针加i,取出值就是数组第i个元素的值
&arr[i] == arr + i      //arr指针加i,就是数组第i个元素的地址

int sum = sum_arr(cookies, ArSize)        //返回整个数组的和
sum = sum_arr(cookies, 3)                 //数组前3个元素的和
sum = sum_arr(cookies + 4, 4)             //数组后4个元素的和
7.3.3 更多数组示例
//程序清单7.7
//数组函数与const
#include 

using namespace std;

const int Max = 5;
int fill_array(double ar[], int limit);
void show_array(const double ar[], int n);
void revalue(double r, double ar[], int n);

int main(void)
{
	double properties[Max];
	int size = fill_array(properties, Max);
	show_array(properties, size);
	if (size > 0)
	{
		cout << "Enter revaluation factor: ";
		double factor;
		while (!(cin >> factor))			//错误输入清理专用
		{
			cin.clear();                    //清除错误标识位
			while (cin.get() != 'n')
				continue;                   //消耗缓冲区所有内容
				cout << "Bad input; Please enter a number: ";
		}
		revalue(factor, properties, size);
		show_array(properties, size);
	}
	cout << "Done.n";
	cin.get();
	cin.get();
	return 0;
}

int fill_array(double ar[], int limit)
{
	double temp;
	int i;
	for (i = 0; i < limit; i++)
	{
		cout << "Enter value #" << (i + 1) << ": ";
		cin >> temp;
		if (!cin)							//错误输入清理专用
		{
			cin.clear();
			while (cin.get() != 'n')
				continue;
			cout << "Bad input; Please enter a number: ";
			break;
		}
		else if (temp < 0)
			break;
		ar[i] = temp;
//      else
//          ar[i] = temp;
	}
	return i;    //成功录入的数量
}

void show_array(const double ar[], int n)    //不希望通过指针修改指向对象内容
{
	for (int i = 0; i < n; i++)
	{
		cout << "Property #" << (i + 1) << ": $";
		cout << ar[i] << endl;
	}
}

void revalue(double r, double ar[], int n)
{
	for (int i = 0; i < n; i++)
		ar[i] *= r;
}

 7.3.4 使用数组区间的函数
  • 指定元素区间,可以通过传递两个指针完成:一个指针标识数组开头,另一个指针标识数组尾部。
//程序清单7.8
#include 

using namespace std;

const int ArSize = 8;
int sum_arr(const int* begin, const int* end);

int main(void)
{
	int cookies[ArSize] = { 1,2,4,8,16,32,34,128 };
	int sum = sum_arr(cookies, cookies + ArSize);
	cout << "Total cookies eaten: " << sum << endl;
	sum = sum_arr(cookies, cookies + 3);
	cout << "First three eaten: " << sum << endl;
	sum = sum_arr(cookies + 4, cookies + 8);
	cout << "Last four eaten: " << sum << endl;
	return 0;
}

int sum_arr(const int* begin, const int* end)
{
	const int * pt;
	int total = 0;
	for (pt = begin; pt != end; pt++)
		total += *pt;
	return total;
}
7.3.5 指针和const
  • const int * pt == int const * pt
  • 指针指向常量对象,防止使用指针来修改所指向的值
  • int * const pt
  • 将指针本身声明为常量,防止改变指针指向的位置
  • const int * const pt
  • 既不允许使用指针修改指向的值,也不允许指针更换指向对象
7.4 函数和二维数组
int data[3][4] = {{1,2,3,4}, {9,8,7,6}, {2,4,6,8}};
int total = sum(data, 3);

//sum的原型
int sum(int (*ar2)[4], int size);
//指向4个int组成数组的指针
//等于
int sum(int ar2[][4], int size);
//而不是
int sum(int *ar2[4], int size);
//这是4个int*指针组成的数组
//另外函数参数不能是数组


ar2[r][c] == *(*(ar2 + r) + c)
ar2                    //指向 4 个 int 数组的第一行的指针
ar2 + r                //指向第 r 行的指针(4 个 int 的数组)
*(ar2 + r)             //第 r 行
*(ar2 + r) + c         //指向第 r 行 第 c 列的指针
*(*(ar2 + r) + c)      //第 r 行 第 c 列
7.5 函数和C—风格字符串 7.5.1 将C—风格字符串作为参数的函数

三种表示字符串的方式:

  • char数组
  • 引号括起的字符串常量(字符串字面值)
  • 被设置为字符串地址的char指针(char*)
//程序清单7.9
//函数和字符串
#include 

using namespace std;

//unsigned int c_in_str(const char* str, char ch);    //指针表示法
unsigned int c_in_str(const char str[], char ch);     //数组表示法

int main(void)
{
	char mmm[15] = "minimum";
	const char* wail = "ululate";     //字符指针
//  char* wail = (char*)"ululate";    //类型不匹配,加const或强制类型转换

	unsigned int ms = c_in_str(mmm, 'm');
	unsigned int us = c_in_str(wail, 'u');
	cout << ms << " m characters in " << mmm << endl;
	cout << us << " u characters in " << wail << endl;
	return 0;
}

//unsigned int c_in_str(const char* str, char ch)
unsigned int c_in_str(const char str[], char ch)
{
	unsigned int count = 0;
	while (*str)			//字符串常量以结尾
	{
		if (*str == ch)
			count++;
		str++;              //将指针移动到下一个字符
	}
	return count;
}
7.5.2 返回C—风格字符串的函数

函数无法返回一个字符串,但可以返回字符串的地址,而且效率更高

//程序清单7.10
#include 

using namespace std;

char* buildstr(char c, int n);

int main(void)
{
	int times;
	char ch;

	cout << "Enter a character: ";
	cin >> ch;
	cout << "Enter an integer: ";
	cin >> times;
	char * ps = buildstr(ch, times);
	cout << ps << endl;
	delete[] ps;
	return 0;
}

char* buildstr(char c, int n)
{
	char* pstr = new char[n + 1];
	pstr[n] = '';
	while (n-- > 0)
		pstr[n] = c;
	//for (int i = 0; i < n; i++)
	//	pstr[i] = c;
	return pstr;
}
7.6 函数和结构 7.6.1 传递和返回结构
//程序清单7.11
//函数与结构
#include 

using namespace std;

struct travel_time
{
	int hours;
	int mins;
};

const int Mins_per_Hr = 60;
travel_time sum(travel_time t1, travel_time t2);
void show_time(travel_time t);

int main(void)
{
	travel_time day1 = {5, 45};
	travel_time day2 = {4, 55};
	travel_time trip = sum(day1, day2);
	cout << "Two-day total: ";
	show_time(trip);

	travel_time day3 = {4, 32};
	cout << "Three-day total: ";
	show_time(sum(trip, day3));

	return 0;
}

travel_time sum(travel_time t1, travel_time t2)
{
	travel_time total;

	total.mins = (t1.mins + t2.mins) % Mins_per_Hr;
	total.hours = t1.hours + t2.hours + (t1.mins + t2.mins) / Mins_per_Hr;
	return total;
}

void show_time(travel_time t)
{
	cout << t.hours << " hours, " << t.mins << " minutesn";
}
7.6.2 另一个处理结构的函数 
//程序清单7.12
#include 
#include 

using namespace std;

struct polar
{
	double distance;
	double angle;
};
struct rect
{
	double x;
	double y;
};

polar rect_to_polar(rect xypos);
void show_polar(polar dapos);

int main(void)
{
	rect rplace;
	polar pplace;

	cout << "Enter the x and y values: ";
	while (cin >> rplace.x >> rplace.y)
	{
		pplace = rect_to_polar(rplace);
		show_polar(pplace);
		cout << "Next two numbers (q to quit): ";
	}
	cout << "Done!n";
	return 0;
}

polar rect_to_polar(rect xypos)
{
	polar answer;
	answer.distance = sqrt(xypos.x * xypos.x + xypos.y * xypos.y);
	answer.angle = atan2(xypos.y, xypos.x);
	return answer;
}

void show_polar(polar dapos)
{
	const double Rad_to_Deg = 57.29577591;
	cout << "distance = " << dapos.distance << ", angle = " << dapos.angle * Rad_to_Deg << " degreesn";
}
 7.6.3 传递结构的地址

 节省时间和空间

  • 调用函数时,将结构的地址(&pplace)而不是结构本身(pplace)传递给它
  • 将形参声明为指向polar的指针,即polar*类型。由于函数不应该修改结构,故使用const
  • 由于形参是指针而不是结构,因此使用间接成员运算符(->),而不是成员运算符(.)
//程序清单7.13
#include 
#include 

using namespace std;

struct polar
{
	double distance;
	double angle;
};
struct rect
{
	double x;
	double y;
};

void rect_to_polar(const rect* pxy, polar* pda);
void show_polar(const polar* pda);

int main(void)
{
	rect rplace;
	polar pplace;

	cout << "Enter the x and y values: ";
	while (cin >> rplace.x >> rplace.y)
	{
		rect_to_polar(&rplace, &pplace);
		show_polar(&pplace);
		cout << "Next two numbers (q to quit): ";
	}
	cout << "Done!n";
	return 0;
}

void rect_to_polar(const rect * pxy, polar * pda)
{
	pda->distance = sqrt(pxy->x * pxy->x + pxy->y * pxy->y);
	pda->angle = atan2(pxy->y, pxy->x);
}

void show_polar(const polar * pda)
{
	const double Rad_to_Deg = 57.29577591;
	cout << "distance = " << pda->distance << ", angle = " << pda->angle * Rad_to_Deg << " degreesn";
}

程序清单7.12和7.13之间的差别在于,7.12使用结构副本,7.13使用指针,指针能够对原始结构进行操作,效率更高,消耗内存更少

7.7 函数和string对象
//程序清单7.14
#include 
#include 

using namespace std;

const int SIZE = 5;

void display(const string sa[], int n);

int main(void)
{
	string list[SIZE];
	cout << "Enter your " << SIZE << " favorite astronomical sights:n";
	for (int i = 0; i < SIZE; i++)
	{
		cout << i + 1 << ": ";
		getline(cin, list[i]);
	}

	cout << "Your list:n";
	display(list, SIZE);

	return 0;
}

void display(const string sa[], int n)    //看似数组,实际指针
{
	for (int i = 0; i < n; i++)
		cout << i + 1 << ": " << sa[i] << endl;
}
7.8 函数和array对象
//程序清单7.15
#include 
#include 
#include 

using namespace std;

const int Seasons = 4;
//array arr
const array Snames = { "Spring", "Summer", "Fall", "Winter" };

void fill(array* pa);
void show(array da);

int main(void)
{
	array  expenses;
	fill(&expenses);
//不能写成fill(expense),此时fill修改expense副本,应该用指针
	show(expenses);

	return 0;
}

void fill(array * pa)
{
	for (int i = 0; i < Seasons; i++)
	{
		cout << "Enter " << Snames[i] << " expense: ";
		cin >> (*pa)[i];
//cin >> pa[i] 不能这样写, pa是array对象的指针,并不是对象
//cin >> *pa[i] 也不能这样写,[]优先级高于*
	}
}

void show(array da)
{
	double total = 0;
	cout << "nEXPENSEn";
	for (int i = 0; i < Seasons; i++)
	{
		cout << Snames[i] << ": $" << da[i] << endl;
		total += da[i];
	}
	cout << "Total Expense: $" << total << endl;
}
7.9递归 7.9.1包含一个递归调用的递归
//程序清单7.16
#include 

using namespace std;

void countdown(int n);

int main(void)
{
	countdown(4);
	return 0;
}

void countdown(int n)
{
    //Countdown ... 按函数调用顺序执行
	cout << "Countdown ... " << n << " (n at " << &n << ")" << endl;
	if (n > 0)    //执行条件
		countdown(n - 1);    //更新条件
    //Kaboom: 按函数调用相反顺序执行
	cout << "Kaboom: " << n << " (n at " << &n << ")" << endl;
}

//每个递归调用创建新变量,地址都不同
7.9.2 包含多个递归调用的递归
//程序清单7.17
#include 

using namespace std;

const int Len = 66;
const int Divs = 6;

void subdivide(char ar[], int low, int high, int level);

int main(void)
{
	char ruler[Len];            //字符数组
	for (int i = 0; i < Len - 2; i++)
		ruler[i] = ' ';         //清空
	ruler[Len - 1] = '';      //避免出现乱码
	int max = Len - 2;
	int min = 0;
	ruler[min] = ruler[max] = '|';
	cout << ruler << endl;
	for (int i = 1; i <= Divs; i++)
	{
		subdivide(ruler, min, max, i);
		cout << ruler << endl;
		for (int j = 1; j < Len - 2; j++)
			ruler[j] = ' ';
	}
	return 0;
}

void subdivide(char ar[], int low, int high, int level)
//void subdivide(char *ar, int low, int high, int level)
{
	if (level == 0)        //循环条件
		return;
	int mid = (high + low) / 2;
	ar[mid] = '|';
	subdivide(ar, low, mid, level - 1);        //level - 1 更新条件
	subdivide(ar, mid, high, level - 1);
}
7.10 函数指针 7.10.1 函数指针的基础知识
  • 获取函数地址

如果think()是函数,则think就是该函数地址。一定要区分传递的是函数地址还是函数返回值

process(think)        //函数地址
thought(think())      //函数返回值
  • 声明函数指针
double pam(int);        //函数声明
double (*pf)(int);      //函数指针声明

 pf是这类函数的指针,必须在声明中将(*pf)括起。括号优先级高于*

double *pf(int)        //*pf(int)代表pf()是返回指针的函数
double (*pf)(int)      //(*pf)(int)代表pf是指向函数的指针
  • 使用函数指针调用函数

使用(*pf)时,将之看做函数名即可

double pam(int);
double (*pf)(int);
pf = pam;
double x = pam(4);
double y = (*pf)(5);
//实际上,C++也允许像使用函数名那样使用pf
//pf 和 (*pf)等价
double y = pf(5);
7.10.2 函数指针示例 
//程序清单7.18
#include 

using namespace std;

double betsy(int lns);
void estimate(int lines, double (*pf)(int));

int main(void)
{
	int code;
	cout << "How many lines of code do you need? ";
	cin >> code;
	cout << "Here's Betsy's estimate:n";
	estimate(code, betsy);
	return 0;
}

double betsy(int lns)
{
	return 0.05 * lns;
}

void estimate(int lines, double (*pf)(int))
{
	cout << lines << " lines will take " << (*pf)(lines) << " second(s)n";
	//cout << lines << " lines will take " << pf(lines) << " second(s)n";
}
7.10.3 深入探讨函数指针
//程序清单7.19
#include 

using namespace std;

const double* f1(const double ar[], int n);
const double* f2(const double [], int n);
const double* f3(const double *, int n);

int main(void)
{
	double av[3] = { 1112.3, 1542.6, 2227.9 };

	//PART 1
	//函数指针
	const double* (*p1)(const double*, int) = f1;
    //函数指针(函数名)赋给函数指针
	auto p2 = f2;
//  const double* (*p2)(const double*, int) = f2;
	cout << "Using pointers to functions:n";
	cout << "Adress    Valuen";
    //函数返回值地址 : 函数返回值
	cout << (*p1)(av, 3) << ": " << *(*p1)(av, 3) << endl;
    //(*p1)(av, 3) == f1(av, 3)
	cout << p2(av, 3) << ": " << *p2(av, 3) << endl;
    //p2(av, 3) == f2(av, 3)

	//PART 2
	//指针数组
    //pa/pb是包含3个函数指针的数组
	const double* (*pa[3])(const double*, int) = { f1, f2, f3 };
    //数组名是指向第一个元素的指针,pa和pb都是指向函数指针的指针
	auto pb = pa;
//  const double* (**pb)(const double*, int) = pa;
	cout << "nUsing an array of pointers to functions:n";
	cout << "Adress Valuen";
	for (int i = 0; i < 3; i++)
		cout << pa[i](av, 3) << ": " << *pa[i](av, 3) << endl;

	cout << "nUsing a pointer to a pointer a function:n";
	cout << "Adress Valuen";
	for (int i = 0; i < 3; i++)
		cout << pb[i](av, 3) << ": " << *pb[i](av, 3) << endl;

	//PART 3
	//函数指针数组的指针
	cout << "nUsing pointers to an array of pointersn";
	cout << "Adress Valuen";
    //pc指向整个数组的指针
	auto pc = &pa;
//  const double* *(*pc)[3](const double*, int) = &pa;
	cout << (*pc)[0](av, 3) << ": " << *(*pc)[0](av, 3) << endl;
    //(*pc)[0](av, 3) == pa[0](av, 3) == f1(av, 3)
    //pd是指针,指向包含3个元素的数组
	const double* (*(*pd)[3])(const double*, int) = &pa;
	const double* pdb = (*pd)[1](av, 3);
//  (*pd)[1](av, 3) == pa[1](av, 3) == f2(av, 3) -->pdb指向f2(av, 3)
	cout << pdb << ":" << *pdb << endl;
	cout << (*(*pd)[2])(av, 3) << ": " << *(*(*pd)[2])(av, 3) << endl;
//  cout << (*pd)[2](av, 3) << ": " << *(*pd)[2](av, 3) << endl;
//  (*(*pd)[2])(av, 3) == (*pa[2])(av, 3) == f3(av, 3)
	return 0;
}
//pd指向数组,*pd就是数组,(*pd)[i]是数组中的元素,即函数指针
//函数调用是(*pd)[i](av,3),*(*pd)[i](av,3)是返回的指针指向的值
//或者调用(*(*pd)[i])(av,3),*(*(*pd)[i])(av,3)是指向double的值
const double* f1(const double* ar, int n)
{
	return ar;        //数组名,第一个元素地址
}

const double* f2(const double ar[], int n)
{
	return ar + 1;    //第二个元素地址
}

const double* f3(const double ar[], int n)
{
	return ar + 2;    //第三个元素地址
}

 这个代码学的不够清楚,再看看

 注意括号优先级:

  • (*pa[2])(av, 3) == f3(av, 3) 第三个元素的地址
  • *pa[2](av, 3) == *f3(av, 3)  第三个元素的值
7.10.4 使用typedef进行简化
typedef double real           //real 成了double的别名
typedef const double* (*p_fun)(const double*, int);    //p_fun是函数指针别名
p_fun p1 = f1;                //p1指向函数f1
p_fun pa[3] = {f1, f2, f3};   //pa 3 个函数指针的数组
p_fun (*pd)[3] = &pa;         //pd 指向一个由 3 个函数指针组成的数组

用定义变量的方式,加上typedef,变量就变成类型别名

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1001119.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号