第七章——函数(C++的编程模块)

这篇具有很好参考价值的文章主要介绍了第七章——函数(C++的编程模块)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

复习函数的基本知识

要使用C++函数,必须完成如下工作:

  • 提供函数定义
  • 提供函数原型
  • 调用函数 

库函数是已经定义和编译好的函数,同时可以使用标准库头文件提供其原型,因此只需要正确地调用这种函数即可。但是创建自己的函数时,必须自行处理上面提到的3个方面。例如

#include<iostream>
using namespace std;

void hello();	//函数的声明

int main()
{
	cout << "主函数将调用自己编写的hello这个函数:" << endl;
	hello();	//函数的调用
	cout << "调用自编函数hello结束" << endl;
	return 0;
}

//函数的声明
void hello() 
{
	cout << "我向大家问好!"<<endl;
}

第七章——函数(C++的编程模块),C++ Primer Plus,c++,开发语言 

程序按行顺序执行。执行函数hello()时,将暂停main()中的代码;等函数hello()执行完毕之后,继续执行main()中的代码。 

定义函数

可以将函数分为两类:没有返回值的和有返回值的函数。

没有返回值的函数称为void函数,通用格式如下:

void functionName(parameterList)
{
    statement(s)
    return;
}

 其中,parameterList指定了传递给函数的参数类型和数量。

有返回值的函数将生成一个值,并将它返回给调用函数。这种函数的返回类型被声明为返回值的类型。通用格式如下:

typeName functionName(parameterList)
{
    statement(s)
    return value;
}

 对于有返回值的函数,必须使用返回语句,以便将值返回给调用函数。注意返回值的类型不能是数组,但可以是其他任何类型——整数、浮点数、指针、结构、对象

第七章——函数(C++的编程模块),C++ Primer Plus,c++,开发语言

函数在执行返回语句后结束。如果函数包含多条返回语句,则函数在执行遇到的第一条返回语句后结束。例如

int bigger(int a,int b)
{
    if(a > b)
        return a;
    else
        return b;
}

 函数原型和函数调用

看下面一个例子

#include<iostream>
using namespace std;
void cheers(int);		//prototype, no return value
double cube(double x);  //prototype, return a double
int main()
{
	cheers(5);			//function call
	cout << "Give me a number: ";
	double side;
	cin >> side;
	double volume = cube(side);   //function call
	cout << "A " << side << "-foot cube has a volume of ";
	cout << volume << " cubic feet" << endl;
	cheers(cube(2));
	return 0;
}

void cheers(int n)
{
	for (int i = 0; i < n; i++)
	{
		cout << "Cheers! ";
	}
	cout << endl;
}
double cube(double x)
{
	return x * x * x;
}

第七章——函数(C++的编程模块),C++ Primer Plus,c++,开发语言 

1.为什么需要原型?

原型描述了函数到编译器的接口,也就是说它将函数返回值的类型(如果有的话)以及参数的类型和参数的数量告诉编译器。

函数原型是怎样影响下面这条语句的? 

double volume = cube(side);

 对于上面这条语句,函数原型告诉编译器,cube()有一个double参数。如果程序没有提供这样的参数,原型将让编译器能够捕获这种错误;其次,cube()函数完成计算后,将把返回值放在指定的位置,然后调用函数(这里是main()函数)将从这个指定位置取得返回值。由于原型指出了cube()的返回类型是double,因此编译器知道应该检索多少字节以及如何解释它们。如果没有这些信息,编译器将只能进行猜测,而编译器是不会这样做的。

2.原型的语法

函数的原型是一条语句,因此必须以分号结束。最简单的方法就是 复制函数定义中的函数头并添加分号。(函数原型不要求提供变量名,有类型列表就行了;下面这两种都是正确的)

void hell(int);
void hell(int x);

3.原型的功能

原型确保以下几点:

  • 编译器正确处理函数返回值
  • 编译器检查使用的参数数目是否正确
  • 编译器检查使用的参数类型是否正确;如果不正确,则在能力范围内转换为正确的类型 

函数参数和按值传递 

 C++通常按值传递参数,这意味着将数值参数传递给函数,而后者将其赋给一个新的变量。

用于接收传递值的变量被称为形参,传递给函数的值被称为实参。

第七章——函数(C++的编程模块),C++ Primer Plus,c++,开发语言

 在函数中声名的变量(包括参数)是该函数私有的。在函数被调用时,计算机将为这些变量分配内存,在函数结束时,计算机将释放这些变量使用的内存,这样的变量被称为局部变量。

如果在main()中声明了一个名为x的变量,同时在另一个函数中也声明了一个名为x的变量,则它们将是两个完全不同的、毫无联系的变量

第七章——函数(C++的编程模块),C++ Primer Plus,c++,开发语言

多个参数

 函数可以有多个参数,在调用函数时,只需使用逗号将这些参数分开即可:

n_chars('R',50);

 上述函数调用将两个参数传递给函数n_chars()

同样,在定义函数时,也在函数头中使用由逗号分隔的参数声名列表

void n_chars(char c,int n)  //two arguments

该函数头指出,函数n_chars()接受一个char参数和一个int参数,必须分别指定每个参数的类型,不能像声明常规变量那样,将声明组合在一起。

函数和数组

函数是处理复杂类型(如数组、结构)的关键,下面学习如何将数组和函数结合在一起

假设现在要计算一个数组中所有元素的和,我们可以使用for循环逐个遍历相加即可,这样没换一个数字都要进行相应的修改。这里我们写出一个统一的接口,让对于不同的数组修改的尽可能少,不必每次都编写新的循环。

#include<iostream>
using namespace std;
const int ArSize = 8;
int sum_arr(int arr[], int n);
int main()
{
	int cookies[ArSize] = { 1,2,4,8,16,32,64,128 };
	int sum = sum_arr(cookies, ArSize);
	cout << "Total cookies: " << sum << endl;
	return 0;
}
int sum_arr(int arr[], int n)
{
	int total = 0;
	for (int i = 0; i < n; i++)
	{
		total = total + arr[i];
	}
	return total;
}

第七章——函数(C++的编程模块),C++ Primer Plus,c++,开发语言 

 我们看函数头

int sum_arr(int arr[], int n)

 方括号指出arr是一个数组,方括号为空则表示可以将任何长度的数组传递给该函数。但实际情况并不是这样:arr实际上并不是数组,而是一个指针。(在编写函数的其余部分时,可以将arr看作是数组)

函数如何使用指针来处理数组

前面介绍过,C++将数组名解释为其第一个元素的地址

cookies == &cookies[0]

 数组声明使用数组名来标记存储位置,对数组名使用sizeof将得到整个数组的长度(以字节为单位),将取地址运算符&用于数组名时,将返回整个数组的地址

在函数调用:

int sum = sum_arr(cookies, ArSize);

其中cookies是数组名,而根据C++规则,cookies是其第一个元素的地址,因此函数传递的是地址。由于数组的元素的类型为int,因此cookies的类型必须是int指针,即int*。这表明正确的函数头应该是这样的

int sum_arr(int *arr,int n)

这证明 int *arr和int arr[ ]这两个函数头都是正确的。因为在C++中,当且仅当用于函数头或函数原型中,它们两者的含义才是相同的,都意味着arr是一个int指针。在其他的上下文中,                   int * arr和int arr[ ]的含义是不同的。 

 我们可以看到,上述程序并没有将数组内容传递给函数,而是将数组的位置(地址)、包含的元素种类(类型)以及元素数目(变量n)传递给函数,有了这些信息后,函数便可以使用原来的数组。

传递常规变量时,函数将使用该变量的拷贝;但传递数组时,函数将使用原来的数组

 将数组地址作为参数可以节省复制整个数组所需的时间和内存。

指针和const

可以用两种不同的方式将const关键字用于指针。

第一种方法是让指针指向一个常量对象,这样可以防止使用该指针来修改所指向的值;

int age = 39;
const int* pt = &age;

该声明指出,pt指向一个const int(39),因此不能使用pt来修改这个值

*pt += 1;      //INVALID
cin >> *pt;    //INVALID

pt的声明并不意味着它指向的值实际上就是一个常量,而只意味着对pt而言,这个值是常量。(例如pt指向age,而age不是const,可以直接通过age变量来修改age的值,但是不能使用pt指针来修改它)

*pt = 20; //INVALID
age = 20;

在这里注意又有两种情况,以前我们总是将常规变量的地址赋给常规指针,而这里将常规变量的地址赋给指向const的指针(因此还有两种情况:将const变量的地址赋给指向const的指针、将const变量的地址赋给常规指针。其实只有第一种可行,第二种是不可行的

const float g_earth = 9.8;
const float *pe = &g_earth;    //VALID

 对于这一种情况,既不能使用g_earth来修改值9.8,也不能使用指针pe来修改。

 尽可能使用const

将指针参数声明为指向常量数据的指针有两条理由:

1)这样可以避免由于无意间修改数据而导致的编程错误

2)使用const使得函数能够处理const和非const实参,否则只能接受非const参数

第二种方法是将指针本身声明为常量,这样可以防止改变指针指向的位置。

int sloth = 3;
int *const finger = &sloth;

 这种声明结构使得finger只能指向sloth,但允许使用finger来修改sloth的值

递归

C++函数有一种有趣的特点——可以自己调用自己(与C语言不同的是,C++不允许main()调用自己),这种功能被称为递归。

 如果递归函数调用自己,则被调用的函数也将调用自己,这将无限循环下去,除非代码中包含终止调用链的内容。通常的方法将递归调用放在if语句中,如下面的一个递归函数文章来源地址https://www.toymoban.com/news/detail-546812.html

void recurs(argumentlist)
{
    statements1
    if(test)
        recurs(arguments2)
    statements2
}

到了这里,关于第七章——函数(C++的编程模块)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第七章 函数矩阵

    和矩阵函数不同的是,函数矩阵本质上是一个矩阵,是以函数作为元素的矩阵。 矩阵函数本质上是一个矩阵,是以矩阵作为自变量的函数。 函数矩阵和数字矩阵的运算法则完全相同。 不过矩阵的元素 a i j ( x ) a_{ij}(x) a ij ​ ( x ) 需要是闭区间 [ a , b ] [a,b] [ a , b ] 上的实函数

    2024年02月04日
    浏览(63)
  • Python之第七章 函数 --- 基础

    目录 Python之第七章 函数 --- 基本 1.模块化程序设计 1.基本思想 2.特点 2.定义函数 1.格式: 2.函数名: 3.形式参数: 4.函数体 ​编辑 3.函数调用 1.作用 2.格式 3.调用方式 4.实例 4.return语句 1.作用 2.注意 3.return可以返回任意Python的对象 5.函数参数 1.位置参数 ​2.参数 3.默

    2024年02月09日
    浏览(49)
  • 《Flink学习笔记》——第七章 处理函数

    为了让代码有更强大的表现力和易用性,Flink 本身提供了多层 API 在更底层,我们可以不定义任何具体的算子(比如 map,filter,或者 window),而只是提炼出一个统一的“处理”(process)操作——它是所有转换算子的一个概括性的表达,可以自定义处理逻辑,所以这一层接口

    2024年02月10日
    浏览(51)
  • 单片机入门教程:第七章 1602LCD液晶显示模块

    在单片机的人机交互系统中,常常需要显示系统运行中的某些信息和数据,例如,字符、汉字或者图形等。液晶显示器(LCD)正好可以完成此项任务,它是一种功耗很低的显示器,在电子表、计算器、数码相机、计算机的显示器和液晶电视上都可以看到它的身影。液晶显示器

    2024年02月09日
    浏览(55)
  • 【MySQL新手到通关】第七章 聚合函数使用详解

    为了方便测试,我们导入一些数据 数据如下 什么是聚合函数 聚合函数作用于一组数据,并对一组数据返回一个值。 聚合函数类型 AVG() 求平均值 SUM() 求和 MAX() 求最大值 MIN() 求最小值 COUNT() 求总行数 聚合函数语法 聚合函数不能嵌套调用。比如不能出现类似“AVG(SUM(字段名称

    2024年02月08日
    浏览(41)
  • 基于FPGA的UDP协议栈设计第七章_RGMII模块设计

    该部分内容主要需要掌握各种IO和时钟相关的原语使用 以太网的通信离不开PHY芯片,PHY芯片实现实现了RGMII接口到网口(RJ45)的转换, RGMII接口就是PHY芯片和FPGA之间的接口。 GMII :GMII(Gigabit Media Independant Interface),千兆MII接口。GMII采用8位接口数据,工作时钟125MHz,因此传

    2024年04月15日
    浏览(81)
  • go 笔记 第七章 golang 的函数 func 方法

    声明函数 func 函数名(入参1 类型, 入参2 类型,… )(出参1 类型, 出参2 类型…){ 函数体,写逻辑 出参一定要全部 return, return 出参 } 函数内部不可以声明带名字的函数,可以声明匿名函数和自执行函数 函数名大写可以被其他包调用,小写私有,变量名也是一样 return 后面可以不

    2024年02月15日
    浏览(44)
  • 曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

    原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/ 译者:池中物王二狗(sheldon) blog: http://cnblogs.com/willian/ 源码:github: https://github.com/willian12345/coding-curves 曲线艺术编程系列第7章 我承认这一章脑暴时,再三考虑过是否要将抛物线包含进来。此篇覆盖的抛物线比起之前三章

    2024年02月08日
    浏览(43)
  • 【Rust】Rust学习 第七章使用包、Crate和模块管理不断增长的项目

    目前为止,我们编写的程序都在一个文件的一个模块中。伴随着项目的增长,你可以通过将代码分解为多个模块和多个文件来组织代码。一个包可以包含多个二进制 crate 项和一个可选的 crate 库。伴随着包的增长,你可以将包中的部分代码提取出来,做成独立的 crate,这些

    2024年02月13日
    浏览(40)
  • Effective Modern C++ 第七章 并发API 1

    目录 条款35:优先使用基于任务而非基于线程的程序设计 要点速记:  条款36:如果异步是必要的,则指定std::launch::async 要点速记: 参考:EffectiveModernCppChinese/src/7.TheConcurrencyAPI/Item35.md at master · CnTransGroup/EffectiveModernCppChinese (github.com) 基于任务的方法通常比基于线程的方法更

    2024年02月07日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包