C/C++教程

6.3C++的返回类型和return语句

本文主要是介绍6.3C++的返回类型和return语句,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

返回类型和return语句

return语句终止当前正在执行的函数并将控制权返回到调用该函数的地方。 returun语句有两种形式:

return;
return expression;

1.无返回值函数

没有返回值的return语句只能用在返回类型是void的函数中。返回void的函数不要求非得有return语句,如果不写,最后会隐式的执行return。

如果void函数想在它中间位置提前退出,可以使用return语句,类似循环中的break语句。如:

//swap函数
void swap(int &v1, int &v2) {
    if (v1 == v2) {
        return; //结束被调函数,返回主调函数的调用点
    }
    int tmp = v2;
    v2 = v1;
    v1 = temp;
    //不写return,隐式调用return
}

2.有返回值的函数

只要函数的返回类型不是void,则该函数内的每条return语句必须返回一个值。并且,return语句返回值的类型必须与函数的返回类型相同,或能隐式转换成函数的返回类型。

①值是如何被返回的

返回一个值的方式和初始化一个变量或形参的方式完全一样:返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果。

如:返回两个字符串中较短的一个

string shortString(const string &s1, const string &s2) {
    return s1.size() < s2.size() ? s1 : s2;
}
int main() {
    string s = shortString("abc", "abcd"); //调用点
}

//等价于
const string &s1 = "abc";
const string &s2 = "abcd";
string tmp = s1.size() < s2.size() ? s1 : s2; //tmp是个临时量
string s = tmp; //返回的值初始化调用点的临时量tmp,再用tmp初始化s

如果函数返回引用,则该引用仅是它所引用对象的一个别名

如:返回两个字符串中较短的一个的引用

const string &shortString(const string &s1, const string &s2) {
    return s1.size() < s2.size() ? s1 : s2;
}
int main() {
    string s = shortString("abc", "abcd"); //调用点
}

//等价于
const string &s1 = "abc";
const string &s2 = "abcd";
const string &tmp = s1.size() < s2.size() ? s1 : s2; //tmp是个临时量
string s = tmp; //返回的值初始化调用点的临时量tmp,再用tmp初始化s

其中形参和返回类型都是const string的引用,tmp和s1都是string(“abc”)的常量引用,不管是调用函数还是返回结果都不会真正拷贝string对象。

②不要返回局部对象的引用或指针

函数完成后(创建临时量之后),它所占用的存储空间也随之被释放。因此,函数终止意味着局部变量的引用将指向不再有效的内存区域。 返回,局部对象的引用将产生错误。

如:

const string& mainip(string ret) {
    if (!ret.empty()) {
        return ret; //错误:返回局部对象的引用
    }
    else {
        return "Empty"; //错误:"Empty"是局部临时量
    }
}

int main() {
    string s1 = mainip("abc");
    cout << s1 << endl; 
}

 //等价于
string ret = "abc";
const string &tmp = ret; //ret在创建完临时量tmp后销毁
string s1 = tmp; //此时,tmp所引用的对象已经销毁,tmp相当于野指针,不能操作

当函数结束后局部变量所占用的空间就随之释放了,所以两条return语句都指向了不再可用的内存空间。

③引用返回左值

函数的返回类型决定函数调用返回的是左值还是右值。调用一个返回引用的函数得到左值,其他返回类型得到右值。我们能为返回类型为非常量引用的函数结果赋值。

如:下标运算符的函数形式get_val

char &getVal(string &str, int i) {
    return str[i];
}
int main() {
    string s("abc");
    getVal(s, 0) = 'A';
    cout << s << endl;
}
//输出结果为Abc

//等价于
string s("abc");
string &str =s;
int i = 0;
char &tmp = str[0];
tmp = 'A'; //临时量tmp是s[0]的一个引用,改变tmp会改变str[0]的值。

④列表初始化返回值

函数可以返回花括号包围的值的列表。类似于其他返回结果,此处的**列表用来初始化函数返回的临时量。**如果列表为空,临时量执行值初始化;否则,返回的值由函数返回类型决定。

如:定义一个getString返回vector<string>{"wo", "ele"}.

vector<string> getString() {
    return { "wo", "ele" };
}
int main() {
    vector<string> s = getString();
    cout << *s.begin() << " " << *(s.begin()+1) << endl;
    return 0;
}

//等价于
vector<string> tmp = vector<string>{"wo", "ele"};
vector<string> s = tmp;

3.返回数组指针

因为数组不能被拷贝,所以函数不能返回数组。但是,函数可以返回数组的指针或引用。

直接定义一个返回数组的指针或引用的函数比较麻烦,可以通过两种方法来进行:

如:定义一个函数,将输入数组的第一个数改为0,返回该数组的引用

  • 直接表示法
int (&func(int(&a)[10]))[10] { //可以看出直接表示法太过复杂
	a[0] = 0;
	return a;
}
void printArr(const int(&a)[10]) {
    for (int i = 0; i < 10; ++i) {
        cout << a[i] << " " ;
    }
}
int main() {
    int a[10]{2,2,2,2,2,2,2,2};
    func(a)[1] = 3; //由于返回的是数组的引用,因此可以作为左值
    printArr(a);
    return 0;
}
//输出结果:0 3 2 2 2 2 2 2 0 0
  • 使用类型别名
//类型别名定义
using arrT = int[10];
//等价于
//typedef int arrT[10];
arrT& func1(int(&a)[10]) { //可以看出函数的形式清晰了喜多
    a[1] = 1;
    return a;
}
int main() {
    int a[10]{2,2,2,2,2,2,2,2};
    func1(a)[0] = 3; //返回的是输入数组的引用,因此可以作为左值
    printArr(a);
    return 0;
}
//输出结果为:3 1 2 2 2 2 2 2 0 0
  • 使用尾置返回类型

尾置返回类型对任何函数都能用,但是对于返回类型很复杂的函数最有效,如返回类型是数组的指针或数组的引用。

auto func2(int(&a)[10])->int(&)[10]{ //可以清楚看出返回类型是数组的引用
    a[2] = 4;
    return a;
}
int main() {
    int a[10]{2,2,2,2,2,2,2,2};
    func2(a)[0] = 3;
    printArr(a);
    return 0;
}
//输出结果为3 2 4 2 2 2 2 2 0 0
这篇关于6.3C++的返回类型和return语句的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!