<C++ Primer >学习笔记 第六章 函数(上)

<C++ Primer >学习笔记 第六章 函数(上),第1张

,# 函数基础
函数定义
函数定义包含以下几个部分:返回类型、函数名字、形参列表和函数体。

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"<<"的阶乘为"<<j<<endl; 
}
int fact(int a)
{
	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"<<a<<" ";
	cout<<"b"<<b<<" ";
	return 0;
}
main()
{
	int b,i;

	for(i=0;i<10;i++)
	{
		cout<<"这是第"<<i<<"次调用的结果"<<" ";
		add();
		cout<<endl;
	}
}

结果如图

函数声明与分离式编译
函数只能定义一次,但是可以声明很多次。函数的声明和定义几乎一样,只是函数声明没有实体,用一个封号代替就可以了,也可以不写形参的名字。一般把函数声明放在头文件中。
6.8、6.9 编写一个项目 fact.cc,factmain.cc和fact.h

fact.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<<i<<"的阶乘为"<<j<<endl; 
}

参数传递
参数的传递有两种,引用或者拷贝。
引用传递:形参是引用类型,将形参绑定到对应的实参上,可以直接改变绑定实参的值,当对象不支持拷贝 的时候可以直接引用。如下

#include
using 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第一次出现的索引和出现的次数

#include
using 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<<"请输入小写字符串"<<endl;
	cin>>s; 
    index=find_char(s,c,n);
    cout<<index<<" "<<n;
	return 0;
 } 

const的形参与实参
形参的顶层const会被忽略掉,对于形参来说本身就无法改变实参,只能读取实参。

void f(int i)
void f(const int i)

这两个编译器认为是一样的。
如果子函数不会改变实参的值,尽量用常量引用,一方面可以给其他使用函数的人提示子函数不会改变常量的值,另一方面是常量引用不会造成一些错误,比如常量引用既可以引用常量,也可以引用非常量,而普通的引用只能引用非常量。

6.17 输入一个字符串判断是否有大写字母,如果有询问用户是否需要将字符串中的大写字母改成小写

#include
using 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)"<<endl;
	  cin>>a;
	  if(a=1)
	  {
	  	change= gaixie(s);
	  	cout<<change;
	  }
	  
	}
	else 
	cout<<"没有大写字母存在"<<endl; 
	
}

int panduan(const string &a)
{
	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<<"请输入小写字符串"<<endl;
	cin>>s; 
    find_char(s,c,save);
    cout<<save[0]<<" "<<save[1];
	return 0;
 } 

因为数组传入的是指针,因此不需要特别的去返回数组,指针可以直接间接改变数组的值。
实参不确定的情况
无法确定实参的数量但是类型为同一类型时,可以传递一个名为initializar_list的标准库类型,如果实参的类型也无法确定,可以编写可变参数模板。
initializer_list是一种标准库类型,用于表示某种特定类型的值的数组,用法和vector类似,但是里面的值都是常量值,无法改变其对象。

void f(initializer_list<string> il)

计算未知个数元素的和

#include 
#include 

using namespace std;
int add(initializer_list<int> li)
{
	int sum=0;
	for(int val:li)
	{
		sum+=val;
	}
	return sum;
}

省略形参

void f(parm-list,……)
void f(……)

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/872726.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-13
下一篇2022-05-13

发表评论

登录后才能评论

评论列表(0条)

    保存