,# 函数基础
函数定义
函数定义包含以下几个部分:返回类型、函数名字、形参列表和函数体。
int fact(int val)
{
}
列举一个简单的空函数,fact是函数名,fact前面的int是返回类型,val是形参,val前的int是接受的实参类型,花括号中的是函数体。
形参列表可以是空的,但是不能被省略,如果是省略形参可以用void或者直接为空
int fact(void)
{
}
或者
int fact()
{
}
多个形参可以使用逗号隔开,每个形参前都必须标有类型,任意两个形参不能同名。
实参是形参的初始值,与形参一一对应,无论是类型还是数量都必须对应。
6.3 用户输入一个数,计算这个数的阶乘
#include#include using namespace std; int fact(int a); int main() { int i; cin>>i; int j=fact(i); cout<<"j"<<"的阶乘为"< int ret=1; while(a>0) { ret*=a--; } return ret; }
局部对象
每一个对象都有生命周期,定义在函数体外的变量,存在于整个程序执行的过程中,在函数开始时被创建,函数结束时消失。每个变量的生命周期的长短取决于它们的定义方式。对于普通局部变量对象来说,当函数路径经过定义语句时创建,当到达定义语句所在块末尾时销毁。某些时候需要局部变量的生命周期贯穿始末的时候需要使用static将普通的局部变量,变成局部静态变量。
6.6、6.7编写一个函数,使用到形参、局部变量和局部静态变量,函数的内容是第一次返回0,之后每一次返回变量加一
#include#include using namespace std; int add() { static int a=1; int b=1; a=a+1; b=b+1; cout<<"a"< int b,i; for(i=0;i<10;i++) { cout<<"这是第"< 结果如图
函数声明与分离式编译
函数只能定义一次,但是可以声明很多次。函数的声明和定义几乎一样,只是函数声明没有实体,用一个封号代替就可以了,也可以不写形参的名字。一般把函数声明放在头文件中。
6.8、6.9 编写一个项目 fact.cc,factmain.cc和fact.hfact.h #ifndef CHAPTER_H_INCLUDE #define CHAPTER_H_INCLUDE int fact(int ); #endif fact.cpp #include "chapter.h" using namespace std; int fact(int a) { int ret=1; while(a>0) { ret*=a--; } return ret; } factmain.cpp #include#include "Chapter.h" using namespace std; int main() { int i; cin>>i; int j=fact(i); cout< 参数传递
参数的传递有两种,引用或者拷贝。
引用传递:形参是引用类型,将形参绑定到对应的实参上,可以直接改变绑定实参的值,当对象不支持拷贝 的时候可以直接引用。如下#includeusing namespace std; void reset(int &p) { p = 0; } int main() { int n=42; reset(n); return 0; } 值传递:将实参的值拷贝给形参,对形参的操作不会影响到实参。
指针形参:指针形参可以间接改变所指对象的值。如下面这段程序,实参n的值从42变为了0。void reset(int *p) { *p = 0; } int main() { int n=42; reset(&n); return 0; }6.15 输入一个字符串输出o第一次出现的索引和出现的次数
#includeusing namespace std; int find_char(const string &s,char c,int &occurs) { auto ret=s.size(); occurs=0; for(int i=0;i!=s.size();i++) { if(s[i]==c){ if(ret==s.size()) ret=i; occurs++; } } return ret; } int main() { int n,index; char c='o'; string s; cout<<"请输入小写字符串"< >s; index=find_char(s,c,n); cout< const的形参与实参
形参的顶层const会被忽略掉,对于形参来说本身就无法改变实参,只能读取实参。void f(int i) void f(const int i)这两个编译器认为是一样的。
如果子函数不会改变实参的值,尽量用常量引用,一方面可以给其他使用函数的人提示子函数不会改变常量的值,另一方面是常量引用不会造成一些错误,比如常量引用既可以引用常量,也可以引用非常量,而普通的引用只能引用非常量。6.17 输入一个字符串判断是否有大写字母,如果有询问用户是否需要将字符串中的大写字母改成小写
#includeusing namespace std; int panduan(const string &a); string gaixie(string &a); int main() { int adjuest,a; string change; string s; cin>>s; adjuest=panduan(s); if(adjuest) { cout<<"有大写字母存在,是否把小写字母改写成大写?(yes=1)"< >a; if(a=1) { change= gaixie(s); cout< int ret=0; for(const char &c:a) { ret=isupper(c); if(ret!=0) return ret; } return ret; } string gaixie(string &a) { for(char &c:a) { c=tolower(c); } return a; } 数组形参
数组有两个特殊的性质:1.数组不可以被拷贝;2.使用数组时通常会将其转化成指针。因为这两个性质无法使用值传递的方式将数组传入形参,并且传递时传递的是指向数组首地址的指针。void f(const int*) void f(const int a[]) void f(const int a[n])这三种方式形参是等价的,数组的大小对调用没有影响。
数组的引用形参
f(int (&a)[10])括号不可以少!
如何判断数组的长度
1.使用标记指定数组的长度,比如在定义一个数组时,以 /n 结尾,在子函数中检测到 /n 就认为数组结束了。
2.使用标准库,使用数组的首地址指针和尾地址指针进行传递。int j[2] f(begin(j),end(j))3.显式的传递一个形参大小
void f(const int j[],const int size )传递多维数组
多维数组就是指向数组的数组,含义就是指向首元素的指针本身就是一个数组void ((*f)[10],int row Size)f 指向数组的首元素,这个元素是由10个整数构成的数组。
上面问题的6.17 使用数组进行查找和存储#include#include using namespace std; int find_char(const string &s,char c,int* a) { a[0]=s.size(); for(int i=0;i!=s.size();i++) { if(s[i]==c){ if(a[0]==s.size()) a[0]=i; a[1]++; } } } int main() { int n,save[2]={0,0};//第一个元素存索引 第二个元素存个数 char c='o'; string s; cout<<"请输入小写字符串"< >s; find_char(s,c,save); cout< 因为数组传入的是指针,因此不需要特别的去返回数组,指针可以直接间接改变数组的值。
实参不确定的情况
无法确定实参的数量但是类型为同一类型时,可以传递一个名为initializar_list的标准库类型,如果实参的类型也无法确定,可以编写可变参数模板。
initializer_list是一种标准库类型,用于表示某种特定类型的值的数组,用法和vector类似,但是里面的值都是常量值,无法改变其对象。void f(initializer_listil) 计算未知个数元素的和
#include#include using namespace std; int add(initializer_list li) { int sum=0; for(int val:li) { sum+=val; } return sum; } 省略形参
void f(parm-list,……) void f(……)



