C++ Primer 第六章 函数 复习(1)

简介: C++ Primer 第六章 函数 复习

C++ Primer 第六章 函数

6.1 函数基础

函数是一个命名了的代码块,通过函数执行相应的代码。可以有 0 个或多个参数,可重载


/*
  编写一个求数阶乘的程序
*/
int fact(int val){
    int ret =1; //局部变量,用于保存计算结果
while(val > 1){
        ret *= val --;
    }
    return ret;
}
/*
  函数调用:
  用实参初始化函数对应的形参(类型,个数需要匹配)
  主函数暂时中断,背调函数开始执行
*/
int main(){
    int j = fact(5); //j等于120
}

局部对象


局部对象:生命周期从变量声明开始,到函数块末尾结束


局部静态对象:从变量声明开始,至程序结束时销毁


size_t count_calls(){
    static size_t ctr =0; //调用结束后,这个值仍然有效
    return ++ctr;
}

参数传递


传值参数,传引用参数


//该函数接受一个指针,然后将指针所指的位置置为 0void reset(int *p){
  *p =0; //改变指针p所指对象的值
     p =0; //改变p的局部拷贝,实参并未改变
}
//该函数接受一个int对象的引用,然后将对象所指的值置为 0void reset(int& i){
  i =0; //改变了 i 所引用对象的值
}

使用引用避免拷贝


如果函数无需改变引用形参的值,最好将其声明为常量引用

//比较两个 string 对象的长度
bool isShorter(const string& s1,const string& s2){
    return s1.size() < s2.size();
}

使用引用形参返回额外信息


//返回s中第一次出现的位置索引,引用参数occurs赋值统计c出现的总次数
string::size_type find_char(const string& s,char c,string::size_type& occurs){
    auto ret = s.size();
    occurs =0;
for(decltype(ret) i=0;i!=ret;;++i){
if(s[i]==c){
            //只有第一次出现的时候,才会被记录
if(ret==s.size()) ret = i;
++ occurs;
        }
    }
    return ret;
}

const 形参和实参


形参的顶层 const 会被忽略掉


void fcn(const int i){/*fcn能读i,但不能修改*/}
void fcn(int i){/*错误,重复定义*/}

指针或引用形参与 const


void reset(int* i){*i =0; i=0;}
void reset(int& i){i =0;}
//返回s中第一次出现的位置索引,引用参数occurs赋值统计c出现的总次数
string::size_type find_char(const string& s,char c,string::size_type& occurs){
    auto ret = s.size();
    occurs =0;
for(decltype(ret) i=0;i!=ret;;++i){
if(s[i]==c){
            //只有第一次出现的时候,才会被记录
if(ret==s.size()) ret = i;
++ occurs;
        }
    }
    return ret;
}
int main(){
    int i =0;
    const int ci = i;
    string::size_type ctr =0;
    reset(&i); //调用形参类型是 int* 的 reset 函数
    reset(&ci); //错误,不能用指向 const int 对象的指针初始化 int*
    reset(i); //调用形参类型是 int& 的 reset 函数
    reset(ci); //错误,不能把普通引用绑定到 const 对象 ci 上
    reset(42); //错误,不能把普通引用绑定到字面值上
    reset(ctr); //错误,类型不匹配,ctr是无符号类型
    //正确,find_char第一个形参是对常量的引用
    find_char("Hello",'o',ctr);
}

数组形参


//尽管形式不同,但三个print函数是等价的
//每个函数都有一个 const int* 类型的形参
void print(const int*);
void print(const int[]);
void print(const int[10]); //这里的10只是一个期望
/*
  以数组未形参的函数必须确保使用数组时不会越界
*/
//1、使用标记指定数组长度
void print(const char* cp){
if(cp){ //如果不是空指针
while(*cp){ //取出不是空字符
            cout << *p++; //输出当前字符,并移动到下一个位置
        }
    }
}
//2、使用标准库规范
void print(const int* beg,const int* end){
    //输出之前的所有元素
while(beg != end){
        cout << *beg++;
    }
}
//3、显式传递一个表示数组大小的形参
void print(const int[] ia,size_t size){
for(size_t i=0;i!=size;++i){
        cout << ia[i];
    }
}//可使用 print(j,end(j)-begin(j))调用

C++ 允许将变量定义成数组的引用


//正确:形参是数组的引用,维度是类型的一部分
void print(const (&arr)[3]){ //()不能少
for(auto elem : arr){
        cout << elem << endl;
    }
}
int i=0,j[2] = {0,1},k[3] ={0,1,2};
print(&i); //错误,实参不是含有3个整数的数组
print(&j); //错误
print(&k); //正确
/*
  传递多维数组 : 在C++中没有实际的多维数组
*/
void print(int (*matrix)[10],int rowsize){};
void print(int matrix[][10],int rowsize){}; //实际上是指向 10 个整数的数组的指针

main:命令行选项


int main(int argc,char* argv[]){}
int main(int argc,char** argv){}
//如果运行 prog -d-o ofile data0
//argc =5//argv[0] ="prog" ... argv[4] ="data0",argv[5] =0//最后一个指针之后的元素保证为 0

含有可变形参的函数:参数个数不固定


如果所有的实参的类型相同,可以提供一个名为 initializer_list 的标准库类型



//和vector一样,initializer_list 也是一种模板类型
initializer_list<string> ls; //元素类型是string
initializer_list<int> li;
//和vector不一样的是,initializer_list对象中的元素永远是常量
void error_msg(initializer_list<string> ls){
for(auto beg=ls.begin();beg!=ls.end;++beg){
        cout << *beg << endl;
    }
}
if(expected != actual){
    error_msg("functionX",expected,actual);
}else{
    error_msg("functionX","OK");
}

6.2 函数返回值

无返回值函数 & 有返回值函数




值是如何被返回的

//返回word对象的副本(拷贝),或是一个没命名的临时string对象
string make_plural(size_t ctr,const string& word,const string& ending){
  return (ctr>1) ? word+ending : word;
}
//返回其引用,不会拷贝 string 对象
string& shorterString(const string& s1,const string& s2){
  return s1.size()<=s2.size() ? s1 : s2;
}

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

const string& manip(){
    string ret;
if(!ret.empty()){
        return ret; //错误,返回的是局部对象的引用,除了该函数,对象即被销毁
    }else{
        return "empty"; //错误,"empty"是局部临时变量
    }
}

返回类类型的函数和调用运算符


//调用string对象的size成员函数,该string对象是由函数返回的
auto sz = shorterString(s1,s2).size();

引用返回左值


char& get_val(string& str,string::size_type ix){
    return str[ix];  
} 
int main(){
    string s("a value");
    cout << s << endl;
    //如果返回类型是常量引用,则不可以给调用的结果赋值
    get_val(s,0) ='A';
    cout << s << endl;
    return 0;
}

列表初始化返回值:C++ 11


vector<string> process(){
  //...
if(expected != actual){
      return("functionX",expected,actual);
  }else{
      return("functionX","OK");
  }   
}


主函数 main 的返回值


int main(){
if(some_failure){
    return EXIT_FAILURE; //定义在cstdlib头文件中
  }else{
    return EXIT_SUCCESS;
  }
  //编译器将隐式插入一条返回0的return语句
}

递归:函数调用了自己


main函数不能自己调用自己


//计算val的阶乘
int fact(int val){
if(val>1){
    return fact(val -1)*val;
  }else{
    return 1;
  }
}

返回数组指针

数组不能拷贝,所以函数不能返回数组


typedef int arrT[10]; //arrT是一个类型别名,using arrT = int[10]
arrT* func(int i); //func返回一个指向含有10个整数的数组的指针
//声明一个返回数组指针的函数
//返回数组指针的函数形式为 : Type (*function(parm)[dimension])
/*
  ()表示其实一个函数,参数为int
  *代表返回值的类型为一个指针
  int[10] 代表返回的指针指向一个 int 类型的数组
  即这是一个返回数组指针的函数
*/
int (*func(int))[10]; 
//使用尾置返回类型,c++11//->符号开始,在本应该出现类型的地方使用 auto
//func返回数组指针的函数
auto func(int i)->int(*)[10];
//使用 decltype ,当已知函数返回的数组
int odd[] = {1,3,5};
int even[] = {2,4,6};
//返回一个指针,该指针指向含有五个整数的数组
decltype(odd) *arrPtr(int i){
    return (i%2)?&odd:&even; //返回一个指向数组的指针
}


相关文章
|
27天前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
1月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
45 6
|
1月前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
23 0
C++ 多线程之线程管理函数
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
23 3
|
1月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
154 1
|
1月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
30 1
|
1月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
41 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
2月前
|
编译器 C++
【C++核心】函数的应用和提高详解
这篇文章详细讲解了C++函数的定义、调用、值传递、常见样式、声明、分文件编写以及函数提高的内容,包括函数默认参数、占位参数、重载等高级用法。
22 3
|
3月前
|
编译器 C++ 容器
【C++】String常见函数用法
【C++】String常见函数用法
|
3月前
|
C++
c++常见函数及技巧
C++编程中的一些常见函数和技巧,包括生成随机数的方法、制表技巧、获取数字的个位、十位、百位数的方法、字符串命名技巧、避免代码修改错误的技巧、暂停和等待用户信号的技巧、清屏命令、以及避免编译错误和逻辑错误的建议。
33 6