函数C++

Posted 扣得君

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数C++相关的知识,希望对你有一定的参考价值。

第6章 函数

在前面我们已经使用过定义main函数,以及也见过其他的自定义函数,函数是一个命名了的代码块,我们通过调用函数执行相应的代码,函数可以有0个或多个参数,而且通常产生一个结果,C++可以重载函数,也就是说,同一个名字可以对应几个不同的函数

函数基础

函数的实参的类型要与函数的形参类型匹配,后者实参赋值给形参可以进行类型转换。

//example1.cpp
#include <iostream>
using namespace std;

//编写函数 返回类型为int
int double_(int num)

    return 2 * num;


int main(int argc, char **argv)

    //调用函数
    cout << double_(3) << endl; //实参为3
    //形参为num
    return 0;

函数参数列表

函数的形参可以为多个,形成函数的形参列表

//example2.cpp
#include <iostream>
using namespace std;

int mul(int num1, int num2)

    return num1 * num2;


int main(int argc, char **argv)

    cout << mul(2, 3) << endl; // 6
    return 0;

局部对象

在C++中,名字是有作用域的,对象有生命周期,形参和函数内部定义的变量统称为局部变量,其作用域在函数内部,且一旦函数执行完毕,相应内存资源被释放即栈内存。分配的栈内存将会保留,直到我们调用free或者delete。

//example3.cpp
#include <iostream>
using namespace std;
int &func()

    int i = 999;
    return i;


int *func1()

    int *i = new int(999);
    return i;


int main(int argc, char **argv)

    int *num = func1();
    cout << *num << endl; // 999
    delete num;
    int &i = func();
    cout << i << endl;
    //程序会报错,为什么,因为func调用完毕后其内的i变量内存被释放,所以相应的引用是无效的
    return 0;

局部静态组件

局部静态对象在程序的执行路径第一次经过对象定义语句时进行初始化,并且直到程序终止才被销毁,在此期间即使对象所在的函数结束执行也不会对它有影响。

//example4.cpp
#include <iostream>
using namespace std;
int count()

    static int num = 0;
    ++num;
    return num;

int main(int argc, char **argv)

    cout << count() << endl; // 1
    cout << count() << endl; // 2
    for (int i = 0; i < 4; i++)
    
        cout << count() << endl; // 3 4 5 6
    
    return 0;

函数声明

函数的名字必须在使用前声明,与变量类似,函数只能定义一次,但可以声明多次。

//example5.cpp
#include <iostream>
using namespace std;
int main(int argc, char **argv)

    // func();// error: 'func' was not declared in this scope
    //在每调用前没有声明或者定义
    return 0;


void func()

    cout << "hello function" << endl;

声明提升

//example6.cpp
#include <iostream>
using namespace std;

void func(); //函数声明

int main(int argc, char **argv)

    func();
    return 0;


//函数定义
void func()

    cout << "hello function" << endl;

在头文件中进行函数声明

//example7.cpp
#include "example7.h"
#include <iostream>
int main(int argc, char **argv)

    func(); // hello world
    return 0;


void func()

    std::cout << "hello world" << std::endl;

自定义头文件

//example7.h
#ifndef __EXAMPLE7_H__
#define __EXAMPLE7_H__

void func(); //函数声明

#endif

分离式编译

一个程序可以分为多个cpp文件,也就是将程序的各个部分分别存储在不同文件中。
大致原理是,对多个cpp分别编译,然后将多个编译后的部分进行链接操作形成了整体的程序,虽然在多个cpp中编写,但是我们只有一个全局命名空间,也就是说在多个cpp内定义相同名字的变量这是不被允许的。

example8.cpp

//example8.cpp
#include <iostream>
#include "func.h"
using namespace std;
// int i = 999;
//出错因为func.cpp已经定义了int i,不能有重复定义,全局命名空间只有一个
int main(int argc, char **argv)

    func(); // hello world
    return 0;

func.cpp

//func.cpp
#include "func.h"
#include <iostream>
using namespace std;
int i = 999;
void func()

    cout << "hello world" << endl;

func.h

#ifndef __FUNC_H__
#define __FUNC_H__
void func();
#endif

分别编译并且最后链接

g++ -c example8.cpp
g++ -c func.cpp
g++ example8.o func.o -o example8.exe
./example8.exe

或者编译并链接

g++ example8.cpp func.cpp -o example8.exe
./example8.exe

参数传递

调用函数时参数的传递分为传引用调用(引用传递)和传值调用(值传递)

传引用

//example9.cpp
#include <iostream>
using namespace std;
void func(int &i, int *j)

    i -= 1;
    *j -= 1;

int main(int argc, char **argv)

    int i = 0, j = 0;
    func(i, &j);//传递i的引用与j的内存地址
    cout << i << " " << j << endl; //-1 -1
    return 0;

为什什么要提供引用传递呢

对拷贝大的类类型对象或者容器对象,甚至有的类类型对象不支持拷贝,只能通过引用形参支持在其他函数内调用对象,例如有字符串非常长,我们根据操作情况,可以选择引用传递,因为那样省略去了字符串拷贝,节约了内存资源,使得程序效率更高。

//example10.cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;

void func(string &str, vector<int> &vec)

    cout << str << endl;
    for (auto &item : vec)
    
        cout << item << " ";
        item++;
    
    cout << endl;


int main(int argc, char **argv)

    vector<int> v1, 2, 3, 4, 5;
    string str = "hello c++";
    func(str, v);
    // hello c++ 1 2 3 4 5
    func(str, v);
    // hello c++ 2 3 4 5 6
    return 0;

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

//exaple11.cpp
#include <iostream>
#include <string>
using namespace std;

int func(int i, string &message)

    if (i < 0)
    
        message = "i<0";
        return i < 0;
    
    message = "i>=0";
    return i < 0;


int main(int argc, char **argv)

    string message;
    func(-1, message);
    cout << message << endl; // i<0
    return 0;

const形参和实参

关于顶层const的回顾

const int ci = 42;//ci不能被赋值改变,const是顶层const
int i=ci;//i可以被赋值,拷贝ci时忽略其顶层const
int *const p=&i;//const是顶层的,不能给p赋值
*p=0;//正确,可以改变p的内容,但不能改变p本身存储的内存地址

形参的底层const与顶层const

//example12.cpp
#include <iostream>
using namespace std;
// p同时加底层const与顶层const
void func(int i, const int *const p)

    cout << i << endl;  // 23
    cout << *p << endl; // 23
    //*p = 99; error: assignment of read-only location '*(const int*)p'
    // p = nullptr; error: assignment of read-only parameter 'p'

int main(int argc, char **argv)

    const int i = 23;
    func(i, &i);
    return 0;

为什么说当实参初始化形参时会忽略掉顶层const?

//example13.cpp
#include <iostream>
using namespace std;

void func(const int j)

    cout << j << endl; // 999


// void func(int j)
// 
// 
// 'void func(int)' previously defined here
// 因为顶层const是相对于函数内部作用而言的,对函数外部都是进行了拷贝

int main(int argc, char **argv)

    int num = 999;
    func(num);
    //对于外部的调用将忽略形参的顶层const因为有没有const外部都是进行对形参赋值
    return 0;

指针或引用形参与const

//example14.cpp
#include <string>
#include <iostream>
using namespace std;

// const int *p=&num; const string &str=mstr;
// p是有顶层const的int指针 str为常量引用
void func(const int *p, const string &str)

    string new_str = "hello";
    // str = new_str; //错误 因为str为常量的引用
    //  str = "hello";//错误 因为str为常量的引用
    int num = 999;
    p = &num;
    cout << str << endl;


//引用常量 底层const
//虽然有这种写法 但是我们好像从不用这种,没有引用常量
// void func(string const &str)
// 
//     cout << str << endl;
//     str = "hello";
// 

int main(int argc, char **argv)

    int num = 100;
    const string mstr = "hi";
    func(&num, mstr); // hi
    string name = "gaowanlu";
    func(&num, "oop"); // oop
    return 0;

总之 关于const与引用、指针的配和往往会使得我们头大,所以我们还是要多回顾复习以前的变量章节的const的知识

数组的传递

总之传递数组就是在传递内存地址

//example15.cpp
#include <iostream>
using namespace std;
void func(int arr[])

    for (int i = 0; i < 5; i++)
    
        cout << arr[i] << " ";
        arr[i]++;
     // 1 2 3 4 5
    cout << endl;


//重载失败 因为int*p与int arr[]等效

// void func(int *p)
// 
//     cout << sizeof(p) << endl;
// 

// void func(int arr[5])
// 
// 

void print(const int *begin, const int *end)

    while (begin != end)
    
        cout << *begin << " ";
        begin++;
    
    cout << endl;


int main(int argc, char **argv)

    int arr[5] = 1, 2, 3, 4, 5;
    func(arr);                   // 1 2 3 4 5
    func(arr);                   // 2 3 4 5 6
    print(begin(arr), end(arr)); // 3 4 5 6 7
    return 0;

数组形参与const

//example16.cpp
#include <iostream>
using namespace std;

// const int arr[]等价于const int *arr
// 底层const可以改变arr存储的地址 不能通过arr改变内存地址上的数据
// 即const int 的指针类型 const int * ,也就是数组的每个数据都是const int
void func(const int arr[], size_t size)

    size /= sizeof(int);
    for (int i = 0; i < size; i++)
    
        cout << arr[i] << " ";
    
    // arr[0] = 12; 错误不能改变数组的值
    cout << endl;
    int num = 999;
    arr = &num;
    //*arr = 1000;//error: assignment of read-only location '* arr'


int main(int argc, char **argv)

    const int arr[] = 1, 2, 3, 4;
    // arr[0] = 1;//error: assignment of read-only location 'arr[0]'
    func(arr, sizeof(arr)); // 1 2 3 4

    int num = 0;
    int const *p = &num; //底层const
    //*p = 999;//error 底层const
    cout << *p << endl; // 0
    return 0;

数组引用形参

//example17.cpp
#include <iostream>
using namespace std;

void func(int (&arr)[5])

    for (auto item : arr)
    
        cout << item << endl;
    


//错误 因为数组的引用必须指定数组的长度
void func1(int (&arr)[], int size)

    for (int i = 0; i < size; i++)
    
        cout << arr[i] << " ";
    
    cout << endl;


int main(int argc, char **argv)

    int arr[] = 1, 2, 3, 4, 5;
    func(arr);
    int arr1[] = 1, 2, 3;
    // func(arr1);//error 数组长度不是5
    // func1(arr1, 3); //error 形参没有指定数组的长度 数组的引用必须指定长度

    // int(&arr2)[] = arr1;//同理这里也是错误的
    // cout << arr2[0] << endl;
    return 0;

传递多维数组

总之简单的办法就是传递指针,然后也可以使用数组的引用

//example18.cpp
#include <iostream>
using namespace std;

// int *matrix[10] 10个指针构成的数组
// int (*matrix)[10] 指向含有10个整数的数组的指针
void func1(int (*arr)[5], int size)

    cout << size / sizeof(int) / 5 << endl; // 2


void func2(int arr[][5], int size)

    size = size / sizeof(int) / 5;
    for (int i = 0; i < size; i++)
    
        for (int j = 0; j < sizeof(arr[i]) / sizeof(int); j++)
        
            cout << arr[i][j] << " ";
        
        cout << 

以上是关于函数C++的主要内容,如果未能解决你的问题,请参考以下文章

C++入门(拷贝)构造函数和析构函数

javascript中字面量要怎么理解?尤其是函数、数组、对象字面量

C++ 中的二进制字面量

多态知识点

托管 C++ 中的逐字字面量? (就像 C# 的 @"blah")

C++基础知识之常量(字面量) 变量