IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++知识点记录(2)函数 -> 正文阅读

[C++知识库]C++知识点记录(2)函数

1. 函数与数组

? ? ? ?大多数情况下,C++与C语言一样,将数组名视为指针,C++将数组名解释为数组第一个元素的地址,即arr == &arr[0]。但存在一些例外情况:首先,数组声明使用数组名来标记数组存储的位置;其次,将sizeof运算符作用于数组将得到整个数组的长度(单位为字节);再者,对数组名取地址(将地址运算符&作用于数组名)将会得到整个数组的地址,若定义 int cookies[8] = {}; 则&cookies将返回一个32字节内存块的地址(假设int占4字节)。

(1)数组函数使用示例(重点关注使用cin得到坏输入时如何重启输入)

// 房地产
#include <iostream>
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() {
	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)) {
			// bad input
			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) {
			// bad input
			cin.clear();
			while (cin.get() != '\n')
				continue;
			cout << "Bad input, input process terminated.\n";
			break;
		}
		else if (temp < 0) {
			cout << "i = " << i << endl;
			break;
		}
		ar[i] = temp;
	}
	cout << "i = " << i << endl;
	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;
}

(2)使用数组区间的函数示例

// 使用数组区间的函数
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int ArSize = 8;
int sum_arr(const int* begin, const int* end);

int main() {
	int cookies[ArSize] = { 1,2,4,8,16,32,64,128 };
	int sum = sum_arr(cookies, cookies + ArSize);
	cout << "Total cookies eaten: " << sum << endl;
	sum = sum_arr(cookies, cookies + 3);
	cout << "First three eaters ate " << sum << " cookies.\n";
	sum = sum_arr(cookies + 4, cookies + 8);
	cout << "Last four eaters ate " << sum << " cookies.\n";

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

(3)指针和const

? ? ? 仅当只有一层间接关系(如指针指向基本数据类型)时,才可以将非const地址或指针赋给const指针。如果条件允许,则应当将指针形参声明为指向const的指针(即尽量使用const)。

2. 函数与C风格字符串

(1)将C风格字符串作为参数的函数

// strgfun.cpp -- functions with a string argument
#include <iostream>
using namespace std;
unsigned int c_in_str(const char* str, char ch);   //传参是一个字符串(指向字符的指针)

int main() {
	char mmm[15] = "minimum";   //可以用字符串常量去初始化一个字符数组
	const char* wail = "ululate"; //字符指针
	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; //注意打印字符串,给cout三种情况都可以打印字符串

	return 0;
}

unsigned int c_in_str(const char* str, char ch) {
	unsigned int count = 0;
	while (*str) {
		if (*str == ch)
			count++;
		str++;
	}
	return count;
}

(2)返回C-风格字符串的函数

????????函数无法返回一个字符串,但可以返回字符串的地址,这样做的效率更高。

// strgback.cpp -- a function that returns a pointer to char
#include <string>
using namespace std;
char* buildstr(char c, int n);  //函数声明--原型

int main() {
	int times;
	char ch;

	cout << "Enter a character: ";
	cin >> ch;
	cout << "Enter a integer: ";
	cin >> times;
	char* ps = buildstr(ch, times);
	cout << ps << endl;

	delete[] ps;
	ps = buildstr('+', 20);
	cout << ps << "-DONE-" << ps << endl;
	delete[] ps;

	return 0;
}

char* buildstr(char c, int n) {
	char* pstr = new char[n + 1];
	pstr[n] = '\0';
	while (n-- > 0) {
		pstr[n] = c;
	}
	return pstr;
}

????????上述代码对于内存管理的设计,即让函数返回一个指针,该指针指向new分配的内存,的缺点是,程序员必须记住使用delete。而C++类可以利用构造函数和析构函数处理这些细节。

3. 函数和结构

? ? ? ? 可以将一个结构赋给另外一个结构,同样,也可以按值传递结构,就像普通变量那样,在这种情况下,函数将使用原始结构的副本。另外,函数也可以返回结构。与数组名就是数组第一个元素的地址不同,结构名只是结构的名称,要获得结构的地址,必须使用地址运算符&

? ? ? ? 使用结构编程时,最直接的方式是像处理基本类型那样来处理结构;也就是说将结构作为参数传递,并在需要时将结构用作返回值使用。但是有个缺点,如果结构非常大,则复制结构将增加内存要求,降低系统运行速度。由于此,很多C语言程序员倾向于传递结构的地址,然后用指针来访问结构内容,C++还可以使用按引用传递的方式。

(1)传递和返回结构(按值传递的例子)

// 将行程时间相加得到小时和分钟的和
#include <iostream>
//#include <fstream>
//#include <string>
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() {
	using namespace std;
	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) {
	using namespace std;
	cout << t.hours << " hours, "
		<< t.mins << " minutes\n";
}
// 空间坐标系之间的转换
#include <iostream>
#include <cmath>  //其中部分函数非常重要
//#include <fstream>
//#include <string>
// 定义表示两种坐标系的结构
struct rect {
	double x;
	double y;
};
struct polar {
	double distance;
	double angle;
};

// 函数原型
polar rect_to_polar(rect xypos);
void show_polar(polar dapos);

int main() {
	using namespace std;
	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) {
	using namespace std;
	polar answer;  //按值传递
	answer.distance = sqrt(xypos.x * xypos.x + xypos.y * xypos.y);  //<cmath>中的函数
	answer.angle = atan2(xypos.y, xypos.x); 
	//atan2()可根据x和y计算角度,另一函数atan()不能区分180度之内和之外的角度,用起来不方便
	return answer;
}
void show_polar(polar dapos) {
	using namespace std;
	const double Rad_to_deg = 57.29577951;  //弧度转角度,大约为180/pi,看好实际情况需要哪一种表示形式
	// C++库中的数学函数假设角度的单位为弧度,因此应以弧度为单位来测量角度,但为了便于显示,转换为角度值
	cout << "distance = " << dapos.distance;
	cout << ", angle = " << dapos.angle * Rad_to_deg;
	cout << " degrees\n";
}

(2)传递结构的地址

// 空间坐标系之间的转换 -- 传递结构指针
#include <iostream>
#include <cmath>  //其中部分函数非常重要
//#include <fstream>
//#include <string>
// 定义表示两种坐标系的结构
struct rect {
	double x;
	double y;
};
struct polar {
	double distance;
	double angle;
};

// 函数原型
void rect_to_polar(const rect* pxy, polar* pda);
void show_polar(const polar* pda);

int main() {
	using namespace std;
	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) {
	using namespace std;
	pda->distance = sqrt(pxy->x * pxy->x + pxy->y * pxy->y);
	pda->angle = atan2(pxy->y, pxy->x);
}

void show_polar(const polar* pda) {
	using namespace std;
	const double Rad_to_deg = 57.29577951;
	cout << "distance = " << pda->distance;
	cout << ", angle = " << pda->angle * Rad_to_deg;
	cout << " degrees\n";
}

4. 函数和string对象

? ? ? ? 与数组相比,string对象与结构更相似。可以将一个对象赋给另一个对象,可以将对象作为完整的实体进行传递。如果需要多个字符串,可以声明一个string对象数组,而不是二维char数组。

// 传递string对象数组
#include <iostream>
//#include <fstream>
#include <string>
using namespace std;
const int SIZE = 5;
void display(const string sa[], int n);

int main() {
	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;
	}
}

????????该程序像对待内置类型(如int)一样对待string对象。

5. 函数与array对象

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

// 使用C++11模板类array的例子
#include <iostream>
#include <array>
//#include <fstream>
#include <string>

const int Seasons = 4;
const std::array<std::string, Seasons> Snames = { "Spring", "Summer", "Fall", "Winter" };

// 可以修改array对象的函数
void fill(std::array<double, Seasons>* pa);
// 不可以修改array对象的函数
void show(std::array<double, Seasons> da);

int main() {
	std::array<double, Seasons> expenses;
	fill(&expenses);
	show(expenses);
	
	return 0;
}

void fill(std::array<double, Seasons>* pa) {
	using namespace std;
	for (int i = 0; i < Seasons; i++) {
		cout << "Enter " << Snames[i] << " expenses: ";
		cin >> (*pa)[i];  //注意,由于优先级,这里的括号必不可少
	}
}

void show(std::array<double, Seasons> da) {
	using namespace std;
	double total = 0.0;
	cout << "\nEXPENSES\n";
	for (int i = 0; i < Seasons; i++) {
		cout << Snames[i] << ": $" << da[i] << endl;
		total += da[i];
	}
	cout << "Total Expenses: $" << total << endl;
}

6. 函数中的递归

(1)包含一个递归调用的递归

? ? ? ? 注意,每个递归调用都创建自己的一套变量。

// recur.cpp -- using recursion
#include <iostream>
#include <array>
#include <string>
//#include <fstream>
void countdown(int n);

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

void countdown(int n) {
	using namespace std;
	cout << "Counting down ... " << n  << " (n at " << &n << ")" << endl;
	if (n > 0)
		countdown(n - 1);
	cout << n << ": Kaboom!" << "(n at " << &n << ")" << endl;
}

(2)包含多个递归调用的递归

? ? ? ? 在需要将一项工作不断分为两项较小的类似的工作时,递归非常有用。例如绘制标尺:标出两端,找到中点并将其标出。然后将同样的操作作用于标尺的左半部分和右半部分。递归方法有时被称为分而治之策略(divide-and-conquer strategy)。

// ruler.cpp -- using recursion to subdivide a ruler
#include <iostream>
#include <array>
#include <string>
//#include <fstream>

const int Len = 66;
const int Divs = 6;
void subdivide(char ar[], int low, int high, int level);

int main() {
	using namespace std;
	char ruler[Len];
	int i;
	for (i = 1; i < Len - 2; i++) 
		ruler[i] = ' ';
	ruler[Len - 1] = '\0';
	int max = Len - 2;
	int min = 0;
	ruler[min] = ruler[max] = '|';
	cout << ruler << endl;
	for (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) {
	if (level == 0)
		return;
	int mid = (high + low) / 2;
	ar[mid] = '|';
	subdivide(ar, low, mid, level - 1);
	subdivide(ar, mid, high, level - 1);
}

? ? ? ? 如果要求的递归层次很多,这种递归方式时一种糟糕的选择。

7. 函数指针

? ? ? ? 函数也有地址,函数的地址时存储其机器语言代码的内存的起始地址。获取函数的地址只需要使用函数名(后面不跟参数),也就是说,如果think()是一个函数,则think就是该函数的地址。

? ? ? ? 使用函数指针时,比较棘手的是编写原型,而传递地址则非常简单。

// fun_ptr.cpp -- pointers to functions 
// 计算代码耗费时间,由函数指针传递不同的计算方式
#include <iostream>
//#include <array>
//#include <string>
//#include <fstream>
double betsy(int);
double pam(int);
void estimate(int lines, double (*pt)(int));

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

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

double pam(int lns) {
	return 0.03 * lns + 0.0004 * lns * lns;
}

void estimate(int lines, double(*pf)(int)) {
	using namespace std;
	cout << lines << " lines will take ";
	cout << (*pf)(lines) << " hour(s)\n";
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-04 11:00:48  更:2021-08-04 11:02:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 10:27:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码