C++函数(课本)

函数

C++有两种程序模块:函数(function)和类(class

任何c++的应用程序都是由各种标准库提供的模块和程序员自定义的模块组装而成。

函数概念:功能的抽象,指这个模块定义的操作,适用于指定数据类型的数据集。调用者只关心函数能做什么,不关心如何做。

函数两个重要作用:任务划分、代码重用。

函数定义&调用

函数定义两部分:函数首部、函数操作描述。

函数首部是函数的接口,包含函数的参数和返回类型。

函数操作描述由函数体的语句序列体现。

使用函数称为调用函数,即通过表达式或语句激活并执行函数代码的过程,调用形式必须与函数接口对应。

函数定义:

从使用角度看,有两种函数:标准库函数、自定义函数

标准库函数由c++系统定义并供用户调用,可以看做对语言功能的扩充。

自定义函数是用户根据特定任务编写的函数。

自定义函数的形式与主函数的形式相似,一般形式为:

类型 函数名(形式参数表){

语句序列

}

 

第一行是函数首部(也叫函数头),大括号里的是函数体(体现函数操作描述)。

函数名是用于自定义标识符。

用于包含形式参数表的小括号()是函数的标识符号。任何情况不能省。

无参函数表示不依赖外部数据,执行独立操作。

函数调用:

调用要做两件事:指定函数地址、提供实参

函数名就是函数地址

实参提供被调函数执行所需信息并接收函数返回的信息。(???)

调用的一般形式:

函数名(实参表)

注:实参与形参在个数、类型、位置上必须一一对应!

函数原型:

函数原型是c++重要特性之一。

是函数的声明,作用是告诉编译器有关函数接口的信息:函数名、返回值类型

参数个数、参数类型、参数顺序,编译器根据函数原型检查函数调用的正确性

因为函数原型没有实现代码,所以形参表中不需要参数名,只有类型即可。通常添加参数名是为了可读性,编译器会自动忽略参数名。

 

如果函数定义出现在程序第一次调用之前,就不需要函数原型来声明,这时候函数定义就有函数原型的作用。

函数参数的传递

参数是调用函数与被调函数间交换数据的通道。

函数被调前,形参没有存储空间;被调时,系统建立与实参对应的形参存储,函数通过形参与实参通信、完成操作;函数执行完时,系统收回形参的临时存储空间。

C++有三种参数传递机制:值传递(值调用)、指针传递(地址调用)、引用传递(引用调用)。

传值参数

作为实参的表达式的值被复制到对应形参名所标识的对象中,成为形参初始值。

完成值传递后,函数体中对形参的访问、修改都是在这个对象上完成,与实参对象无关。

如果实参、形参类型不同,将按照形参类型进行强制转换,然后复制(赋值)给形参。

 

副作用:c++没有规定函数调用时的实参求值顺序。

实参求值顺序的不同规定,对一般参数无影响,但若实参表达式之间有求值关联(有顺序要求),则同一个程序在不同编译器下可能有不同结果。

Eg

函数定义为:

int add(int a,int b){

return a+b;

}

调用部分为:

x=4;y=6;

cout<<add(++x,x+y)<<endl;

 

分析:

如果先求第一个实参值,那么输出结果为:5+5+6=16

如果先求第二个实参值,那么输出结果为:4+6+5=15

避免方法:

在调用前就求出实参的值:

x=4;y=6;x++;

cout<<add(x,x+y)<<endl;

 

默认参数:

C++允许指定参数的默认值,当函数调用省略默认参数时,默认值自动传递给被调函数。如果调用时显式指定实参值,则不适用默认参数值。

Eg:double dist(double,double,double=0,double=0);//函数原型

说明:

l 函数的形参说明中设置一个或多个实参默认值,默认参数必须在参数表的最右边。调用具有多个默认参数的函数时,如果省略参数不是最右边的参数,则被省略参数的右边所有参数也该被省略。(这个规定在逻辑上能理解,如果默认参数位置不固定,那么省略时必定需要多打个逗号用作提示,不美观也不高效)

l 默认参数要在函数名第一次出现时指定,通常在函数原型中(有时候不需要函数原型就在函数定义中),若已经在函数原型中给出默认参数,在函数定义的时候不能重复。

l 默认参数的默认值可以是常量、全局变量或函数调用,但不能是局部变量。

l 默认参数可以用于内联函数。(后续会说)

指针参数

形参是指针类型时,称指针参数。

指针参数对应的实参是地址表达式。调用时,实参把对象的地址值赋值给指针参数变量,被调函数就可以在函数体中通过指针参数变量来间接访问实参地址所指的对象。这种参数传递方式称为指针传递或地址调用。

(感觉其实还是传值调用,只不过在所谓的传值调用里的值是对象本身,而这里传的值是对象的地址)

 

当将常对象的地址传递给指针参数时,指针参数必须用const约束,表示这个指针参数的值所指的对象不可改变,是个常量。

(如果不用const约束,即使在这个函数内并没有对这个常量试图做改变,但是编译器从函数原型分析出有这种可能,就会报错,所以const必须加。另外,只是简单的不像实参被这个函数修改,不论实参对象是否是常量,都可以用const约束)

 

引用参数

若形参被定义为引用类型,称为引用参数。引用参数对应的实参是对象名

函数被调用时,形参不需要开辟新的存储空间,形参名作为引用(也就是别名)绑定于实参所标识的对象上。执行时,对形参的操作就是对实参操作,直到函数结束,撤销引用绑定。

引用参数和指针参数都不需要像传值参数那样产生实参对象的副本,并且,引用参数不像指针参数那样间接访问实参对象,特别适用于大对象参数的高效操作。

和指针参数的情形一样,为了避免被调函数对实参对象产生不必要的修改,可用const约束。如果实参对象是常对象(如果是像幻数或者表达式等这类没有标识符的,就没有对象的概念,所以会产生一个匿名对象保存这个幻数或表达式的值,然后引用参数绑定在这个匿名对象上),对不起,必须用const

函数的返回类型

C++可以通过指针参数或引用参数修改实参,获取函数执行结果。return语句也可以返回表达式的执行结果。

表达式的类型必须与函数原型定义的类型一致,负责表达式的值会被强制转换为函数原型中的返回类型。

l 返回基本类型:将要返回的值赋给c++定义的匿名对象,通过这个匿名对象把数值带回函数的调用点,继续执行后续代码。

l 返回指针类型:不能返回局部变量的指针,没意义。局部变量在函数结束后会被系统释放空间。

 

原型声明举例:

Int * add(int *x,int *y);

 

l 返回引用类型:不产生实际返回对象的副本,返回时的匿名对象是实际返回对象的引用。实际返回对象依然不能是局部变量,原因同上。返回对象可以使非局部或静态变量。另外,因为函数调用返回引用,使得整个函数调用本身是对象的引用,所有,返回引用的函数调用可以作为左值。

 

原型声明举例:

Int & add(int &,int&);

函数调用机制

每个函数都是独立定义的模块,函数之间可以互相调用。

每个应用程序只有一个main函数,由系统启动。

 

函数之所以能正确实现调用,是由于系统设置一个先进后出堆栈进行调用信息管理。出现函数调用时,系统首先把调用现场的各种参数、返回地址压入堆栈,然后传递参数,转交控制权给被调函数,函数执行完毕,堆栈弹出返回地址、现场参数并交还控制权继续向下执行。(在ucore里有更详细的解释)

嵌套调用

由函数1调用函数2,函数2调用函数3,这种方式称为嵌套调用。

嵌套调用的代码结构图:

 

堆栈结构如下:

 

递归调用

函数自身调用称为递归调用,两种:直接递归(函数1调用函数1)、间接递归(函数1调用其他函数,其他函数调用函数1,注:其他函数可以是很多个,只要调用图出现环即是)

 

递归是推理和问题求解的一种强有力方法,因为许多对象(尤其是数学对象)都具有递归的结构。

 

简单的说,如果通过一个对象自身的结构来描述整个或部分该对象,则称为递归。

 

可以使用有限的语句描述无限的集合。

 

堆栈变化:系统把有关参数和地址压入堆栈直到推到满足终止条件,找到问题的基本模式为止,然后进行回归:从堆栈中逐层弹出有关地址和参数,执行地址所指向的代码,直到栈空,得到最后解。

 

举例:斐波那契数列求解、阶乘求解、求两个正整数的最大公约数、汉诺塔

 

函数地址&函数指针

函数是编译器处理的对象。每个函数经过编译之后生成的都是二进制代码,这些代码要调入内存才能用运行。每条指令、每个函数模块都有一个首地址,其中函数的首地址称为函数入口地址,即函数指针。

函数的地址

举例查看地址的表示:

一个函数:void simple(){cout<<”a simple program.\n”;//

};

调用:

simple();//函数名调用

(& simple)();//地址调用

(* & simple)();//间接调用

输出:

cout<<simple<<endl;//函数名是地址

cout<<&simple<<endl;//取函数地址

cout<<*&simple<<endl;//函数地址所指对象

运行结果:

a simple program.

a simple program.

a simple program.

0043B248

0043B248

0043B248

举例分析:

simple&simple*&simple看似不同,在c++中都是simple()函数在内存中的入口地址值,称为函数地址。

 

程序设计语言对数据对象的地址和名加以区别,采用名访问时,编译器能根据类型解释存储单元的值。

函数这种代码对象,编译器不区分地址和名。对于一个已经定义的函数,函数名、函数地址(指针)、函数指针所指对象都是同一样东西,表示函数入口地址。

 

调用函数的格式:

函数地址 (实参表)

函数地址实质上是个地址表达式,即可以是能够表示函数入口地址的式子。(在ucore实验中有几个这样的例子)

函数指针

指向函数的指针变量简称为函数指针。

函数的类型*****

定义函数指针,首先要搞清楚这个指针的类型,也就函数的类型。

函数的类型是指函数的接口,包括函数的参数定义和返回类型。

如:double max(double,double);

该函数的类型(接口)为:

double (double,double)

可以用typedef关键字定义函数类型名:

Typedef 返回类型 函数类型名 (形参表);

例:typedef double functionType(double,double);

functionType定义了一类接口相同的函数的抽象,即抽象了含两个double参数和返回类型为double的相同类型的函数。

此时:

functionType max,min,average

等价于:(这个比较新奇,感觉还是挺骚的,说明自己C没学好)

double max(double,double);

double min(double,double);

double average(double,double);

这三个函数原型声明。

函数指针

要定义指向某一类函数的指针变量,可以用以下两种:(并不仅有这两种,后面会说)

返回类型 (指针变量名)(形参表);

函数类型 指针变量名;

在前者中,指针变量名)“ 这部分中的小括号()不能省,否则整个语句就变成一个会返回指针类型的函数的原型了,因为()优先级比”*“

 

沿用上例:

第一种就是:

double (* fp1)(double,double);

第二种就是:

functionType * fp1,*fp2;//可以定义多个同类型指针

 

第三、四种定义指向某一类函数的指针变量的方法是使用typedef关键字。

具体如下:

typedef 返回类型 (指针类型)(形参表);

typedef 函数类型 指针类型;

其中指针类型是用户自定义的类型,在使用的时候,如下:

指针类型 指针变量1,指针变量2...,指针变量n

其实用typedef就是定义了一个别名而已,把”*”省了。(偷懒好吧)

 

举例: 

先定义指针变量的类型:

typedef double (*pt)(double,double);

typedef function *pt;

然后定义指针变量:

pt pf3,pf4;

用函数指针调用函数

一个已经定义的函数指针,一旦被赋给函数地址后就能调用函数。

使用函数指针调用函数的一般形式:

指针变量名)(实参表);

(*fp1)();(*fp2)();

指针变量名(实参表)

fp3();fp4();

第一种方法的”*“是因为要取指针所指地址的对象

第二种方法不加“*”是因为,用了typedef关键字,把*都定义过了。

 

我们知道编译器对函数的名字和函数的地址不加区别,那么

(*fp)();

(**fp)()是什么结果?

实验如下:(deepin系统,g++编译器)

代码:

#include<iostream>

using namespace std;

double max(double a,double b){

return a>b?a:b;

}

int main(){

typedef double funcType(double,double);

double (*fp1)(double,double);

funcType *fp2;

typedef double (*fpt1)(double,double);

typedef funcType *fpt2;

fp1=max;

fp2=max;

fpt1 fp3=max;

fpt2 fp4=max;

cout<<(*fp1)(1,2)<<endl;

cout<<(*fp2)(1,2)<<endl;

cout<<(fp3)(1,2)<<endl;

cout<<(fp4)(1,2)<<endl;

cout<<*fp1<<endl;

cout<<**fp2<<endl;

cout<<***fp3<<endl;

cout<<****fp4<<endl;

 

return 0;

}

运行结果:

 

综上,编译器说到做到,说不区分函数名字和地址就不区分,真是个君子好吧。

 

也就是说,不管哪种方式定义的指针,只要正确指向了函数,且至少有一个“*”号(包括typedef定义包含进去的“*”),就可以调用函数。

 

 

 

注意下例:

fp=max;

fp(1,2);//

(*fp)(1,2);//

(&fp)(1,2);//

分析:前两个对是因为函数的性质所决定,编译器对函数名和函数地址不加区别,第三个错是因为,指针的地址不是函数的地址,指针的值才是函数的地址。


 

内联函数&重载函数

       

内联函数是c++为了降低小程序(小段函数)调用开销而采取的一种机制。

函数重载是指以同一个名字命名多个版本的函数实现,是一种简单的多态形式。

内联函数

函数调用的时候,需要建立栈空间来保存调用时的现场和返回地址,并进行参数传递,产生程序转移。这些工作都需要时间、空间上的开销。如果有数量比较多的那种功能简单、代码简短的函数,花费这些开销有点划不来。所以提供内联函数,编译器在编译时把内联函数的函数体嵌入到每个函数调用处,节省开销。

 

定义内联函数:在函数名第一次出现时(回顾函数参数部分,为形参设置默认值的时候同该要求),在函数名前使用关键字inline。通常都是在函数原型中。若已经在函数原型中指定,不能在函数定义时重复。

形式为:

inline 返回类型 函数名(形参表);

 

内联函数的调用方法同其他普通函数。

其他说明:

只适用于1-5行的小程序,函数体不能含有复杂流程控制语句,否则inline无效。(应该是编译器自己会判断)

递归函数不能说明为内联函数。(虽然很短,但是递归函数的特点就是能用有限的语句描述无限的问题...所以,你懂的)

重载函数

 

C++允许定义多个同名函数,各函数有不同的参数集,这些同名函数称为重载函数。

编译器会根据参数类型和个数的不同产生调用匹配。

常用于生成几个类似任务而处理不同数据个数、类型的同名函数。

 

函数返回类型在编译器的调用匹配不起作用

如:

Double max(double ,double,double);

Int max(int ,int ,int );

Int max(int ,int);

变量存储特性&标识符作用域*****

一个被说明的变量,除名字、类型和值的基本特性外,还有其他特性,包括存储、作用域、可见性和链接等特性。

标识符存储特性确定了标识符在内存中的生存时间和链接特性。

标识符作用域是指在程序正文中能够引用这个标识符的那部分区域。

如果一个标识符在作用域的某部分程序正文中能够被直接引用,则称标识符在这个区域中可见。

C++的一个应用程序称为一个项目,一个项目由多个文件组成。标识符的链接特性决定标识符能否被工程中的其他文件引用。

(这段话比较玄......我标个红好吧...

存储特性

两类存储特性:自动存储、静态存储。

自动存储

用关键字autoregister说明。只有变量具有自动存储特性:

这种变量进入说明的块时生成,在结束块时删除。

 

函数的参数和局部变量是自动存储的(包括main函数)。

 

C++默认变量是自动存储的,所以关键字auto很少用。

 

关键字register把变量放在寄存器中。现在优化编译器能自己识别经常用到的变量,决定是否放入寄存器,而不需要程序员进行register说明。

 

由此可见,自动存储是变量的默认状态。

 

由此可见,以上说的都是废话,忘记这俩关键字吧。

静态存储

关键字externstatic说明静态存储变量和函数标识符。全局说明的标识符默认为extern意思是全局变量默认使用了extern??一会测试一下好吧)。

这俩关键字,

若用于说明变量:程序在开始执行的时候就分配和初始化存储空间。

若用于说明函数:表示从程序开始执行就存在这个函数名。

 

在程序一开始运行就存在,并不代表在整个程序中可用。

static说明的局部变量只能在定义该变量的函数体中使用,与自动变量不同的是,static变量在第一次使用时初始化(默认为0.函数退出时,系统保留其存储空间和数值,下次调用时该函数时,static变量值不变。

 

(这里对externstatic关键字的说明少的可怜,对我这种c没学好的渣渣来说简直是灾难....推荐K&R C,挺详细。)

 

 

这里欠缺一个实验,用K&R C做的实验

标识符的作用域及可见性

程序中常用到的标识符有变量、常量、函数、类型等命名符。

作用域:一个已说明的标识符在程序正文中有效的那部分区域。

可见:若一个标识符在某部分程序正文能够被直接引用,则称这个标识符在该部分程序正文内可见。

一般情况下,一个标识符在作用域内可见,但在嵌套或者层次结构程序模块中,如果定义了同名标识符,它们的可见性和作用域就不一定等价。(这句没看明白)

 

C++的标识符有五种作用域:

函数原型、块、函数、类文件作用域

类成员的作用域及可见性在类与对象继承部分讨论。

 

函数原型作用域:

只有函数原型的形参表中的标识符才具有函数原型作用域。

也就是类型名和形参名。

形参名并不要求一定有,如果有编译器自动忽略。

块作用域

块:函数定义中由一对花括号{}括起来的一段程序单元。

 

一个程序块内允许嵌套另一个块。(并不是说一个函数定义里可以有另一个函数定义,这是不允许的,因为函数是独立定义的

 

在块中说明的标识符具有块作用域。其作用域从说明点开始到右}花括号结束。

Eg:在一个函数定义中有如下片段

While(a>0){

Double sun=0;  //sum作用域从这里开始

Sum+=a;

Cin>>a;

} //sum作用域到这里结束

 

如果嵌套的内层块与外层块有同名的变量,则内层块的变量在内存块的作用域内将覆盖外层的同名变量。

 

作用域不同的变量,系统分配不同的存储空间,其生存周期也不一样。

函数作用域

 

语句标号(和goto语句搭配那种、switch中的case标号那种,后面带冒号的标识符)是唯一具有函数作用域的标识符。

 

标号可以在函数体中的任何地方使用,不能在函数体外引用。

 

实际上,函数体是个特殊的语句块。(....

 

文件作用域

 

任何在函数之外说明的标识符都具有文件作用域。

 

这种标识符从说明处起到文件结尾的任何函数都可见。

全局变量和局部变量

 

全局变量:具有文件作用域的变量,默认初始值为0

 

局部变量:具有块作用域的变量

 

当局部变量与全局变量同名时,在块内,同名的全局变量被屏蔽,要在块内访问被屏蔽的全局变量,可以使用作用域运算符:

::

 

多文件程序结构

一个项目由一个或多个文件组成,文件结构便于程序按照逻辑功能划分,便于测试。

 

一个文件可以包含多个函数定义,但是一个函数的定义必须完整地存在于一个文件中。

多文件程序结构

两类常用文件:.h头文件和.cpp源程序文件

 

一个能够表达特定程序功能的模块由两部分组成:

规范说明部分、实现部分

规范说明部分:描述一个模块与其他模块的接口。通常集中在头文件,各模块通过头文件的接口产生引用。

一般包括:

函数原型、类说明、类型说明、全局量说明、包含指令、宏定义、注释等。

实现部分:称为实现文件,放在.cpp文件中。

 

一个好的软件系统,应该分解为各种同构文件,如下图:

 

 

 

实验如下:

 

 

//a.h

double circle(double,double);

double rect(double,double);

//b.cpp:

double circle(double a,double b){

return a+b;

}

//c.cpp:

double rect(double a,double b){

return a*b;

}

//main.cpp:

#include <iostream>

using namespace std;

#include "a.h"

int main(){

double a=1,b=1;

cout<<circle(a,b)<<endl;

cout<<rect(a,b)<<endl;

 

return 0;

}

编译、运行结果:

 

预处理指令

.h文件和.cpp文件从阅读文本到可执行文件主要经过三个步骤:

预处理、编译和链接

这三个步骤对应三个工具:预处理器、编译器、连接器

预处理器:执行预处理指令,嵌入指定源文件,生成临时文件。

编译器:对临时文件进行语法分析、语义分析,生成目标代码。

连接器:链接标准库,生成可执行文件。

 

预处理执行不是c++的语句,只是一种常用的工具。以开头,一行一句,可以根据需要出现在程序的任何地方。

 

文件包含

#include指令实现文件包含:在编译之前把指定文件的文本到该命令所在的位置,用于支持多文件形式组织的c++程序。

 

格式:

#include<filename>

#include”filename”

 

其中filename文件全名(包括后缀)。

 

第一种形式(尖括号<>):用于包含c++提供的系统标准头文件,这些文件放在c++系统目录中的include子目录下。

 

第二种形式(双引号””):用于包含程序自己建立的头文件。编译器首先搜索当前目录,没找到再去搜索c++系统子目录。自定义头文件需要.h扩展名(在c里面系统的头文件也有.h,但是C++里系统提供的标准头文件名没有.h扩展名)。

 

文件包含一般放在程序开头,因为函数原型必须在函数定义和函数调用之前出现。

宏定义指令

#define 指定文本来替换程序中出现的标识符。

 

形式:

#define 标识符 文本

在c中常用于定义常量,带参数的#define用于定义简单的函数。

 

由于宏定义在正式编译(编译器)前执行,所以不(能)对替换内容进行检查。

 

++constinline定义的内联函数代替了#define定义常量和函数的作用。

Eg:(c语言中)

#define PI 3.1415926

#define area(r) PI*r*r

(c++中)

const double PI=3.1415916;

Inline double area(double r){return PI*r*r;}

(使用部分都一样,片段)

double x=3.6;

x=area(x);

条件编译

可以根据一个常量值作为判断条件,决定源程序中某一段代码是否参加编译(也就是是否会出现在预处理生成的临时文件中)。其结构与if选择语句非常相似。

 

 

 

三种常用形式:

#if 常量表达式

程序文本

#endif

-----------------------------------

#if 常量表达式

程序文本1

#else

程序文本2

#endif

-------------------------------------

#ifndef 标识符

#define 标识符

程序文本

#endif

解释:若标识符没有定义,则编译程序文本;若已经定义,则程序文本被忽略。

-------------------------------------

 

第一种、第二种常用于在调试阶段注释掉一大段待调试的代码,其作用相当于/*........*/,但是更清晰。

第三种常用于多文件结构的头文件中,避免include指令嵌入文本导致重复定义的问题。

 

声明语句是可以在一个文件中重复出现。

 

养成习惯:

尽量做到声明和定义分离,在头文件中只写数据类型、函数原型声明,把变量定义、函数定义放在cpp文件中。

多文件程序使用全局变量

前面说过有用文件作用域的变量就是全局变量,其作用域为说明处到文件结尾。若(ˇˍˇ) 想在其他文件中使用该变量,可在使用它的文件中使用extern关键字先声明一下下。

,file1.cpp中定义了一个全局变量:

int a;

要是想在file2.cpp中使用它,就要求有声明:

extern int a;

然后就可以在file2.cpp中使用它了。

 

关键字extern告诉编译器,这个变量a要么一会在本文件中稍后定义,要么在另一个文件中定义。编译器会通知链接器,找到变量a的说明位置,解决对该变量的引用问题。

 

 

因为全局变量可以被所有函数访问,所以会降低函数之间数据传递的开销。但是违背了程序结构化和信息隐藏的原则,若非效率至上,不用。

(都是追求效率好吧,妈宝男才追求安稳...

 

关于extern关键字和函数:

函数原型默认是extern(确实,函数定义要么在本文件后面,要么在其他文件中),所以,一个文件中只要声明了函数原型,函数定义就可以放在同一个文件中或者另外的文件中

 

另外:

如果希望全局变量或者函数的作用范围限制在定义它的文件中,使用static关键字。其他文件就不能访问被static修饰的全局变量和函数。

命名空间

 

标准名空间

C++的新特性之一。

 

命名空间是类、函数、对象、类型和其他名字声明的集合。

 

stdc++语言的标准名空间,包含了标准头文件中各种名字的声明。

 

C++的标准头文件有:

iostream\iomanip\limit\fstream\string\typeinfo\stdexcept

(没有扩展名)

使用标准库的组件时,要指定名空间。

#include<iostream>

using namespace std;

 

其中namespacec++关键字,用于说明命名空间(或称为名字作用域),申明之后程序就能直接使用iostream中的元素(组件名),如cincout

如果没指定命名空间,(ˇˍˇ) 想~用标准库里的元素,就得在包含进标准库的基础上,使用“std::xxx这种格式。其中XXX就是cincout这类组件名。

 

对于c语言的标准头文件,在VC.NET程序中包含这些头文件的时候,可以在头文件名前加上前缀c,然后去掉.h后缀。

如:

include<stdio>等价于#include<cstdio>

定义名空间

定义命名空间的格式如下:
namespace 标识符{

语句序列

命名空间可以追加嵌套

如:

namespace A{

void f();

void g();

}

namespace B{

void h();

namespace { //嵌套部分

void i();

}

}

namespace A{  //追加部分

void j();

}

 

命名空间遵循先说明再使用原则,例如函数f和g不能使用命名空间B的成分,因为B还没声明。

 

使用命名空间

 

Using语句可以指定使用的命名空间,两种形式:

using namespace 名空间;

using 名空间::元素;

Using语句指定的命名空间(或元素)的名字是当前作用域的一部分。

 

 

给出一个例子:

 


 

 

终止程序执行

return 语句可以终止函数的执行,此外c++还有多种终止程序的方式,以下介绍几个常用函数:

abort函数:

函数原型:void abort(void);

功能:中断程序的执行,返回c++系统主窗口。

该函数在cstdlib头文件声明。

 

实验代码及结果:

 


assert函数:

函数原型:void assert(int expression);

功能:计算表达式expression的值,若值为false,则中断程序执行,显示中断执行所在文件和程序行,返回c++系统主窗口。

cassert头文件声明

 

实验代码及结果:

 

 

exit函数:

函数原型:void exit(int status);

功能:中断程序的执行,返回退出代码,回到c++系统主窗口。

cstdlib头文件中声明。

参数status是整形常量,终止程序时将他作为退出代码返回给操作系统,c++看不见exit的返回值,通常为0或1,该参数可以省略。

实验代码及数据:

 

此处报错,找不到这个头文件。

 

百度:

 

经过一番操作:

(我决定不淌这趟浑水好吧....

 

 

以上三个函数都会直接退出整个应用程序,常用于处理系统的异常错误,c++还有一套处理异常的结构化方法,具体见异常部分。


  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值