C++函数基础 (二)

数组形参

数组的两个特殊性质对我们定义和使用作用在数组上的函数有影响。这两个性质是:不允许拷贝数组 以及使用数组时通常会将其转换成指针。所以当我们传递一个数组时,实际上传递的是指向数组首元素的指针。
尽管不能以值传递的形式传递数组,但是我们可以把形参写成类似数组的形式。

void print(const int*);
void print(const int[]);
void print(const int[10]);//这里的维度表示我们期望数组含有多少元素,实际不一定

上面三条声明,尽管表现形式不同,但是是等价的。当编译器对print函数调用时,只检查传入的参数是否是const int*类型。

int i=0,j[2]={0,1};
print(&i);//正确,&i的类型是int*
print(j);//正确,j自动转换成int*并指向j[0]

因为数组是以指针的形式传递给函数的,所以一开始函数并不知道数组的确切大小,为以防调用时数组越界,调用者应该为此提供一些额外信息。
管理指针形参有三种常用技术:

  1. 使用标记指定数组长度
    要求数组本身有一个结束标记,典型实例是C风格字符串。C风格字符串存储在字符数组中,并且在最后一个字符后面跟着一个空字符。函数遇到空字符时停止。
void print(const char*cp)
{
	if(cp)//若cp不是一个空指针 
	while(*cp)//只要指针指的不是空字符 
	cout<< *cp++;//输出当前字符并将指针向前移动一个位置 
}

适用于那些有明显结束标记且该标记不会与普通数据混淆的情况,就是安全的。

  1. 使用标准库规范
    传递指向数组首元素和尾后元素的指针,这种方法受到了标准库的启发
void print(const int *beg,const int *end)
{
	while(beg!=end)
	cout<<*beg++<<endl;//输出当前元素并将指针向前移动一个位置 
}
//在这里使用标准库函数提供需要的指针
int j[2]={0,1};
print( begin(j) ,end(j) );

只要调用者能正确的计算指针所指的位置,就是安全的。

  1. 显式传递一个表示数组大小的形参
    在C程序和过去的C++程序中常常使用这种方法
//size 表示数组的大小
void print(const int ia[],size_t size)
{
	for(size_t i=0;i!=size;++i)
	cout<<ia[i]<<endl;
 } 
 int j[]={0,1};
 print(j, end(j) - begin(j) );//第二个参数为数组大小的值

只要传递给函数的size值不超过实际数组的大小,就安全。

关于引用的讨论同样适用于指针,当函数不需要对数组元素执行写操作的时候,数组的形参应该是指向const的指针,只有当函数确实要改变元素值的时候,才把形参定义为指向非常量的指针。

数组引用形参

C++语言允许将变量定义为数组的引用,即(可以建立数组的引用,不能建立引用的数组),基于同样道理,形参也可以是数组的引用。

void print(int (&arr)[10])
{
       for(auto elem : arr)
       cout<<elem<<endl;
}

因为数组的大小是构成数组类型的一部分,所以这一种方法无形中限制了print函数的可用性,我们只能将函数作用于大小为10的数组。

int i=0,j[2]={0,1};
int k[10]={0,1,2,3,4,5,6,7,8,9};
print(&i);//错误,实参不是含有10个整数的数组
print(j);//错误,实参不是含有10个整数的数组
print(k);//正确

即不同于数组形参的只要是int*就可以,必须是大小为10的数组,可以使用模板函数来解决这一尴尬困境。

传递多维数组
void print(int(*matrix)[10],int rowsize)

matrix被声明成指向含有10个整数的数组的指针

返回类型与return语句

返回 void 的函数不要求非得有return语句,因为在这类函数的最后会隐式地执行retrurn 语句。void类型的函数可以有无返回值的return语句。不过通常安全起见,应写 return 0;通常情况下,void函数如果想在中间退出,可以使用return语句类似于break;。 .
尽量满足单一出口原则。

//检查两个string对象的对应字符是否相等 
bool str_subrange(const string &str1,const string &str2)
{
	if(str1.size()==str2.size())
	return str1==str2;//返回布尔值
	auto size=(str1.size()<str2.size())?str1.size():str2.size();
	for(decltype(size)i=0;i!=size;++i)//以较短字符串长度为限 
	{
		if(str1[i]!=str2[i])
		return;// 错误一 :bool类型函数的return语句不应该无返回值 
	 } 
	 //错误二: 在含有return语句的循环后面应该也有一条return语句,因为不满足的话是不会退出的 
}
不要返回局部对象的指针或引用

函数完成后,局部变量便被销毁

const string &manip()
{
   string ret="hello world";
   if(!ret.empty())
      return ret;//错误,ret是局部对象,而函数返回类型是局部对象的引用
   else
      return "Empty";//错误,“Empty”是一个局部临时量

返回一个值的方式和初始化一个变量或形参的方式一样,返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果。所以上述代码两条return语句都指向了不可用的内存空间.

主函数main的返回值

如果函数的返回类型不是void,那么它必须返回一个值。但是我们允许main函数没有return语句直接结束,编译器将隐式地插入一条return 0;
main函数的返回值可以看做是状态指示器,返回0表示执行成功,返回其他值表示失败,非0值的含义由机器而定。但为了统一起见,cstdlib头文件定义了两个预处理变量,

int main()
{
    if (.....)
    return EXIT_FAILURE;
    else
    return EXIT_SUCCESS;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值