C++基础学习---问题的模块化求解

C++基础学习—问题的模块化求解

问题的模块化求解

模块化程序设计

模块化程序的组成

函数的概念

函数的定义和声明

函数的定义

有关形参的进一步说明

函数的声明

函数调用

函数调用的格式

参数的传递方式

为形参指定默认值

数组名作为函数参数

结构体变量作函数参数

递归函数

递归调用过程分为两个阶段-递推和回归

Hanoi塔问题

内联函数

函数重载

变量的作用域和存储类型

局部变量

全局变量

使用全局变量的几点说明

变量的存储类型

C++程序运行时使用的内存区域

变量的存储类型

问题的模块化求解

模块化程序设计
模块化程序的组成
编写一个规模较大的程序,可按其功能划分为若干相对独立的模块.
好处:

程序开发更易控制
利于软件重用
避免重复代码
容易调试和维护
每个模块由一个函数实现

函数的概念

  1. main()函数
由多个函数组成的程序
#程序的执行顺序
#库函数(标准函数)
标准输入/输出函数
  1. 数学库函数
字符串处理函数等
用户定义函数
:使用库函数时,需包含相应的头文件.
  1. 函数的定义和声明
    函数的定义
    <函数值类型> <函数名> (<形式参数表>)//函数头
    {
    语句序列
    }
    一个函数由函数头和函数体两部分构成.
    函数头中通常包括函数名,形式参数表以及函数的返回值类型.其中形式参数表必须包含在一对圆括号中.
    函数体-由一对花括号括起来的语句序列组成.
  2. 函数值类型-即函数的返回值类型
(1)返回简单类型
(2)返回结构类型
(3)返回指针类型
(4)返回引用类型
:如果函数无任何返回值,这时函数的返回值类型应标记为void.void类型称为无类型或空类型.
  1. 形式参数表(即形参表)
函数的参数表用于实现函数间的数据联系.
形参的说明格式:类型 形参名
当有多个形参时,各参数说明之间用逗号分隔.
注意:每个形参必须同时给出形参的类型和名称.

**如:int max(int a,b),作为函数首部定义是错误的.
因为形参b缺少类型说明符,即使与a类型相同,但作为形参说明也不能省略类型符int.
**
有关形参的进一步说明


 1. 定义函数时需考虑设置形参,形参的个数及类型根据需要设定(也可以没有参数,称为无参函数).
 2. 形参可以接受主调函数传递的实参的值.在函数中对形参进行处理,并将处理结果返回到主调函数.
 3. 形参是在函数调用时分配存储空间,同时接收实参的值.当函数执行结束后,
 4. 系统将自动释放形参所分配的存储空间.因此,形参属于函数的局部变量,只能在该函数中使用.
 5. 当形参为引用类型或指针类型时,利用形参不仅可以访问实参的值,还可以改变实参的值.
  1. 函数体
 7. {}括起来的语句序列构成,是实现函数功能的主体.
 8. 函数的编写过程类似于主函数.在函数中可以调用其它函数.
 9. 在函数体中,使用return语句返回函数执行的结果.
 10. 对于无返回值的函数,也可以使用return;将控制返回到主调函数.
 11. 说明:在一个函数中允许出现多个return语句,但在函数执行期间只能有一个语句起作用,
 12. 在函数体的最后位置,一个无返回值的return;语句可以省略.
  1. 函数的声明

在C++中,程序编译的单位是源程序文件(即源文件),在一个由多个函数构成的程序可以组织存放在一个或多个源文件中.


 - 源文件中,函数之间的排列顺序没有固定的要求,但要满足"先定义后使用"的原则.
 - 对于标准库函数的使用,在程序开头使用#include命令将所需的头文件包含进来即可.
 - 对于自定义的函数,要么在调用之前定义,要么在调用之前作函数声明.
 - 函数的声明是指在函数被调用之前对函数的类型,名称以及参数等信息所作的说明.
 - 函数声明的格式如下:
类型名 函数名(类型1 形参1,类型2 形参2,);

类型名 函数名(类型1,类型2,);//可省略形参
**

在形式上就是在函数定义的首部后加分号(;)构成.
函数声明说明了函数所采用的形式,称为函数原型.**

  1. 函数调用

函数定义后,并不能自动执行,必须通过函数调用来实现函数的功能.
函数调用,即控制执行某个函数.
C++中,主函数可以调用其他子函数,而其它函数之间也可以相互调用.
在本节中,我们将介绍一下内容:

函数调用的格式
参数的传递方式
为形参指定默认值
数组名作函数参数
结构体变量作函数参数
函数调用的格式

函数调用的一般格式:
<函数名>(<实际参数表>)//有参调用
或 <函数名>()//无参调用
其中:

<函数名>为要使用的函数的名字.
<实际参数表>是以逗号分隔的实参列表,必须放在一对圆括号中.<实参表>与<形参表>中参数个数,类型和次序应保持一致.
当调用无参函数时,函数名后的圆括号不能省略.
9.实参的几种形式

形参为简单类型变量,对应的实参可以是:常量,变量及表达式.
形参为数组,对应的实参为数组().
形参为结构类型,对应的实参为结构类型变量.

double Area(double,double,double);
cout<<Area(4.0,5.0,6.0)<<endl;
cout<<Area(a,b,c)<<endl;
cout<<Area(a+1,b+1,c+2)<<endl;

  1. 函数调用的形式

(1)函数调用作为一个独立的语句(用于无返回值的函数)
调用的形式为:
函数名 (实参表); 或 函数名();
函数的嵌套调用
函数的嵌套调用是指在调用一个函数的过程中,被调用的函数又调用了另一个函数.
参数的传递方式

  1. C++中参数有三种传递方式:

 1. 值传递
 2. 引用传递
 3. 指针传递

值传递
6. 调用时,将实参的值传递给对应的形参,这就是值传递.

由于形参有自己的独立的存储空间,又作为函数的局部变量使用,
因此在函数中对形参值的任何修改都不会改变实参变量的值.

好处
减少函数之间的数据依赖,增强了函数自身的独立性.
注意:函数的形参声明为简单类型或结构类型变量,实参与形参将采用值方式传递.

引用传递
(1)引用
引用是一种特殊变量,它被认为是一个变量的别名.
引用定义的格式如下:
<数据类型> &<引用名>=<目标变量名>;
其中: &为引用(变量)的标志符号,<引用名>是一个标识符.
<数据类型>为<目标变量>的类型.
例如:int a,&b=a;
该例说明了a是一个整型变量,b是一个引用整型变量a的引用,即b是a变量的一个别名.这时,使用a与使用b是等价的.

对引用的说明:
定义一个引用,其实是为目标变量起一个别名.引用并不分配独立的内存空间,它与目标变量共用其内存空间.
定义一个引用(变量),如果该引用不是用作函数的参数或返回值,
则必须提供该引用的初值(即必须提供引用的目标变量名).
使用引用与使用目标变量效果是相同的.

(2)引用传递

  • 为实现引用传递,这时函数的形参应定义为引用类型变量,而对应的实参应为变量名,该变量将作为引用的目标变量名.
  • 函数调用时,作为形参的引用变量并不分配新的内存空间,它将作为实参变量的别名与其共用内存.
  • 使用引用参数可以直接操作实参变量,从而能够实现通过修改形参的值而达到修改对应实参值的目的.
  • 通过设置多个引用参数,可以从函数中带回多个结果值.
  • 说明:引用作为函数形参,其引用的目标变量默认为调用该函数时对应的实参变量名,所以,在定义函数时,对于引用类型参数不必提供引用的初值.
    为形参指定默认值
    C++语言允许在函数定义时为形参指定默认参数值.这样,在函数调用时,如果没有提供实参,则形参自动使用其默认值.
    如:void f(int x=0,int y=0);//形参的默认值0
    f();//未提供实参值,形参x,y使用默认值0
    f(2,4);//形参x,y将使用实参的值2和4
    f(1);//形参x接受1,而y使用0
    可以对部分形参定义默认值.这时默认值应出现在从右到左的连续若干个形参中.
注意:指定参数的默认值可以在函数定义中进行,也可以在函数原型中进行.
通常写在函数名在程序中第一次出现的位置.

数组名作为函数参数

**数组元素**作实参,对应的形参为变量,一次传递一个元素,采用值传递.
**数组名**作实参,对应的形参为一个数组,一次传递整个数组.
数组作参数,其参数传递可理解为形参数组与实参数组共用同一数组空间(即共用实参数组空间).
因此,在函数中,使用形参数组就是在使用实参数组,改变形参数组元素的值就是改变实参数组元素的值,
这一点与引用传递非常相似.

一维数组的传递
一维数组作形参的声明格式:<类型> <数组名>[]
其中,[]中可以省略数组的长度值.(可认为形参数组与实参数组长度相同)
对应的实参应为同类型的一维数组名.(仅用数组名)
说明:为了使函数知道需要处理的数组元素的个数,通常给函数再传递一个表示元素个数的整型数.

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

int fun(int b[], int m, int n) {
	int i, s = 0;
	for (i = m; i < n; i++) {
		s = s + b[i];
	}
	return s;
}

int main() {

	int x, a[] = { 0,1,2,3,4,5,6,7,8,9 };
	x = fun(a, 0, 10);
	cout << x << endl;
	x = fun(a, 3, 5);
	cout << x << endl;
	return 0;

	return 0;
}

二维数组的传递
二维数组作形参的声明格式:<类型><数组名>[][<列数>]
其中:<列数>为常数,不能省略,行数可缺省.
调用时的实参应为同类型的二维数组名.
注意:用作实参的二维数组,其列数必须与形参中的<列数>相同.
例如:二维数组名作参数.编写一个函数,将N阶方阵转置.(N<10)

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

void tranmat(int a[][10], int n) {
	int t;
	for (int i = 0; i < n - 1; i++) {
		for (int j = i; j < n; j++) {
			t = a[i][j];
			a[i][j] = a[j][i];
			a[j][i] = t;
		}
	}
}

int main() {

	int x[10][10], n;
	cout << "输入n(n<10):";
	cin >> n;
	cout << "输入" << n << "行" << n << "列元素:" << endl;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cin >> x[i][j];
		}
	}
	tranmat(x, n);
	cout << "转置矩阵结果如下:" << endl;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cout << x[i][j] << " ";
		}
		cout << endl;
	}

	return 0;
}

结构体变量作函数参数

实参为结构体类型变量
形参为同类型的结构变量
传递方式为值传递

在函数调用时,系统首先为形参变量(即结构变量)分配存储空间,接着将实参变量(结构变量)各成员值传递给形参变量的各个成员.对形参成员的修改不会影响实参成员值的变化.

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

//定义一个结构体类型
struct student {
	int stno;
	char name[20];
	int age;
};

void print(student s) {
	//输出
	cout << s.stno << endl;
	cout << s.name << endl;
	cout << s.age << endl;
}

int main() {

	student stu = { 1001,"li",19 };
	print(stu);//实参为结构变量

	return 0;
}

递归函数
递归函数是直接或间接地调用了自身的函数.

利用递归算法可以将一个规模较大的问题转化为规模较小的同类问题来求解.

递归函数-计算一个非负整数n!
特征:

1.定义中包含该函数本身(即递归公式)
2.必须有终止条件
递归调用过程分为两个阶段-递推和回归
递推-将原问题不断分解为新的规模更小的问题,逐渐从未知向已知方向推测
回归-是从已知条件出发,按递推的逆过程,逐个求值,最后到达递推的开头,解决原问题.
#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

int f(int n) {//计算n!
	if (n == 0) {
		return 1;
	}
	else {
		return n * f(n - 1);//直接递归调用
	}
}

int main() {

	int n;
	int factorial;
	cout << "输入n的值:"<<endl;
	cin >> n;
	factorial = f(n);
	cout << factorial << endl;

	return 0;
}

Hanoi塔问题

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

//函数move将一个盘子从x到y
void move(char x, char y) {
	cout << x << "---->" << y << endl;
}

void hanoi(int n, char a, char b, char c) {
	if (n == 1) {
		move(a, c);
	}
	else {
		hanoi(n - 1, a, c, b);//借助c将n-1个盘子从a移到b
		move(a, c);//从a移到c
		hanoi(n - 1, b, a, c);//借助a将n-1个盘子从b移到c
	}
}

int main() {

	int m;
	cout << "请输入盘子数:";
	cin >> m;
	cout << "移动" << m << "个盘子的过程如下:" << endl;
	hanoi(m, 'A', 'B', 'C');

	return 0;
}

内联函数
程序通过一组函数实现是一种好的设计方法.但是函数调用涉及执行时间的开销.
C++提供的内联函数可以减少函数调用的开销.
内联函数的定义格式:
inline <函数值类型> <函数名>(<形式参数表>){
函数体
}
对用户来说,内联函数的定义与调用与普通函数的使用方法是相似的.
作为编译系统,它将程序中调用内联函数的语句(或表达式)用内联函数体中的代码进行替换.这样在执行时就避免了对内联函数的调用,从而减少了因函数调用所增加的时间开销,提高了程序运行的效率.
使用内联函数可以节省运行时间,但却增加了目标程序的长度.因此一般只将规模很小而使用频繁
的简单函数声明为内联函数.
例:编写程序,计算12+22+32+…+102,将计算整数平方的功能定义为内联函数.

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

inline int square(int x) {
	return x * x;
}


int main() {

	int i, sum = 0;
	for (i = 0; i < 10; i++) {
		sum += square(i);
	}
	cout << "sum=" << sum << endl;

	return 0;
}

说明:编译程序在遇到内联函数调用式square(i)时,就用square函数体中代码代替square(i),同时将实参代替形参.这样语句sum+=square(i);将被替换为sum+=i*i;

函数重载
函数重载是指在一个程序中,可以定义多个 具有相同函数名,不同参数列表的函数(至少参数的类型或参数个数或参数类型的顺序不同).这些的函数被称为重载函数.
当调用一个重载函数时,编译系统将通过检查函数调用中的参数个数,类型和顺序来选择恰当的函数.
重载函数通常用于实现功能类似而所处理的数据类型不同的问题.
例:形参个数相同但类型不同的函数重载.

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

int Abs(int x) {
	return x >= 0 ? x : -x;
}

double Abs(double x) {
	return x >= 0 ? x : -x;
}

int main() {

	int a = -3;
	double b = 35.5;
	cout << Abs(a) << endl;
	cout << Abs(b) << endl;

	return 0;
}

例:形参类型相同,但个数不同的函数重载.

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

int Add(int x, int y) {
	int sum;
	sum = x + y;
	return sum;
}

int Add(int x, int y, int z) {
	int sum;
	sum = x + y + z;
	return sum;
}

int Add(int x, int y, int z, int t) {
	int sum;
	sum = x + y + z + t;
	return sum;
}

int main() {

	cout << Add(3, 5) << endl;
	cout << Add(3, 5,7) << endl;
	cout << Add(3, 5,7,9) << endl;

	return 0;
}

变量的作用域和存储类型
~变量的作用域是指变量的适用范围.
~根据变量的使用范围不同,C++中的变量被分为局部变量和全局变量.

局部变量
在一个函数内或复合语句内定义的变量称为局部变量(函数的形参也属于局部变量).
局部变量只允许在其定义的函数或复合语句中使用,离开所在的函数或复合语句后该局部变量将不能使用.
例如:主函数中定义的变量,也不能在其他函数中使用.
复合语句中定义的变量,也只能在该复合语句中使用
for语句中控制变量的作用域.编译系统通常将循环语句中定义的变量作为局部变量处理,因此该变量在循环外是不能使用的.
说明:局部变量是在执行该函数或复合语句时自动建立,当该函数或复合语句执行完毕后将自动释放.所以在不同的函数或复合语句中定义同名的局部变量,也不会相互干扰.局部变量也称为自动类型变量.
全局变量
全局变量说明于所有函数之外,可以为所有函数共同使用.
全局变量可以在各个函数之间建立数据的传输通道.

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

int a = 3, b = 5;//定义两个全局变量

int Max(int a, int b) {
	return a > b ? a : b;
}

int main() {

	int a = 8;
	cout << Max(::a, b) << endl;

	return 0;
}
注意:在函数中,当局部变量与全局变量同名时,遵循"局部变量优先"的原则.
这时,如果想使用全局变量,应在变量名前加上作用域运算符"::"即可.

使用全局变量的几点说明
(1)全局变量的作用范围是从定义点到整个源程序的结束.
在定义点之前,如果其它函数要引用全局变量,可以在该函数中用extern对全局变量进行声明.
例如:
F1(){
extern a,b;//全局变量声明
使用全局变量a,b
}
F2(){
}
int a=2,b=5;//全局变量定义
(2)使用全局变量,可以增加函数间的直接联系,减少函数定义时的参数.
(3)由于全局变量在整个程序进行中始终占用内存,这样,使用全局变量将降低程序的通用性,可靠性和移植性,这是全局变量的负面作用.

变量的存储类型

~不同的变量所分配的存储区域也不同,这就是变量的存储类型.
C++程序运行时使用的内存区域
从上到下:
堆区:存放动态分配的数据
栈区:存放局部数据.如局部变量
全局数据区:存放全局数据和静态数据,如全局变量
程序代码区:存放程序的各个函数的代码

变量的存储类型

变量的存储类型是变量在内存中存储的方式,根据变量的存储类型,可以知道变量的作用域和生存期.
这里,介绍4个存储类型,分别是
auto(自动类),
register(寄存器类),
static(静态类),
extern(外部类).
在C++中定义一个变量的完整形式是:
<存储类型> <数据类型> <变量名>;

自动变量-用auto修饰(默认的定义方式).
如:定义一个局部变量i.
auto int i;与 int i;是相同的.
说明:自动变量在其定义块(函数或复合语句)开始执行时分配空间,在块执行结束时释放空间.所以自动变量的声明期开始于块的执行,终止于块的结束.
寄存器变量-用register修饰
将尽可能存放在CPU的寄存器中,以提高程序的运行效率
注意:进局部变量和形参可作为寄存器变量.
静态变量-用static修饰
~静态变量分配在全局数据区中,定义时系统将提供默认的初始值.
~静态变量在编译时分配存储空间,在整个程序执行结束后释放存储空间.所以,静态变量具有全局生命期.
~根据声明的位置不同,静态变量又分为静态局部变量和静态全局变量.
~静态局部变量是在"块"中定义的静态变量.它具有局部作用域,却有全局生命期.在"块"执行结束后,该静态局部变量并不释放(其值依旧存在),以便下次调用时可继续使用.
————————————————

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是刘彦宏吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值