函数定义
-
函数是将一部分代码进行封装,便于重用、维护,使得代码更加的整洁。
-
定义函数格式:
- 类型 函数名(类型 形参1,…){ 函数体; return 类型值;}
-
函数调用,使用 函数名(实参),传入实参个数和类型要与形参对应;类型不匹配时,会隐式转换,若无法转换,则报错;
-
函数定义示例
// 求和函数,基本类型参数传值
int sum(int a, int b){ // 函数调用时,值传递
int c = a + b;
a++;
b++; // 内部无法修改外部a、b变量的值
return c;
}
// 传引用
int divide(int &a, int &b){ // 这里的&是引用
a *= 2;
return a / b; // 这里的a、b是对 **实参变量** 的引用 引用再&运算就是取地址
}
// 调用时传入变量 或者 引用变量
int a, b;
a = b = 5;
divide(a, b); // 函数内部是对变量的引用(相当于变量的别名),可以修改原始变量的值
// 传引用,且函数内部不能通过引用修改变量的值(只读)
int divide(const int& a, const int& b) { // const用于定义常量,值无法修改,这里表示引用无法修改变量的值
a *= 2; // 内部再修改 就报错
cout << "inner sum:" << a << endl;
return a / b;
}
函数案例
- 求 2 10 {2^{10}} 210 的值;->1024
#include <math.h> // C++ 兼容C格式的头文件
// pow 函数可以求幂运算
int calc(int base, int exponential){
return pow(base, exponential);
}
- 输入一个非负整数n,求n的阶乘;
// 递归
int calcFactorial(int n) {
if (n == 0 || n == 1) {
return 1; // 有明确的返回条件
}
return n * calcFactorial(n - 1); // 递归 函数调用自身
}
// (工程项目的)入口函数
int main() {
cout << calcFactorial(6) << endl;
return 0;
}
- 输入一个非负整数n,求1-> n的斐波那契数列;
- n为0、1时,f(n) = 1;
- f ( n ) = f ( n − 1 ) + f ( n − 2 ) ; n > = 2 f(n) = f(n-1) + f(n-2);n>= 2 f(n)=f(n−1)+f(n−2);n>=2,即从第三项开始,每一项均为前两项之和。
- 递归思想,函数调用自身且函数有明确的返回条件;
// 计算斐波那契每一项的值
int calcFibonacci(int n) {
if (n == 0 || n == 1) {
return 1;
}
return calcFibonacci(n - 1) + calcFibonacci(n - 2);
}
// void 表示无返回值
void outputValue(int n) {
// cout 输出到控制台 << 流输出运算符
cout << calcFibonacci(n) << " " << endl;
}
// 入口函数
int main() {
cout << "输入一个自然数:" << endl;
// 控制台输入 >> 流输入运算符
int n;
cin >> n;
// 循环输出n以内的斐波那契数列
for (int i = 0; i <= n; i++) {
outputValue(i);
}
return 0;
}
作用域
- 函数内的变量及形参都是局部变量,只在函数内部可以使用;
- 函数外部的变量为全局变量,全局可以使用,其他源文件也可以引用;
- static 修饰的局部变量为局部静态对象(默认初始化为0),函数每次压栈执行时,静态对象的值
不会重置;而局部变量在函数每次压栈执行时创建,返回出栈时销毁; - static 修饰的全局变量为全局静态对象,只能在本源文件中使用;
// 统计一个函数被调用的次数
int callTime(int p) {
static int times; // 静态对象 默认初始化为0; 而局部变量(自动对象,存在栈中)必须自己初始化;
times++;
return times;
}
- 如果函数在调用时,在此之前的代码中尚未定义,则必须先声明该函数,才可以调用;
- 如 int callTime(int p); 为函数声明,去掉函数体;
- 形参名也可以省略;
- 在a.cpp源文件中定义一个函数F,可以在b.cpp中调用,调用前只需简单声明即可;c.app中要调用该函数也需要提前声明;
- 为了避免多次调用需多次声明,可以创建一个头文件,并在该头文件中声明一次,其他源文件包含该头文件即可;

a.cpp
// a.cpp
#include <string> // cout 输出string类型时,必须引入该头文件,否则报错
#include "lauf.h" // 常在头文件中声明函数、类、结构体等
using namespace std;
// 定义
string getName() {
string name = "jack";
return name;
}
lauf.h
#ifndef LAUF_H
#define LAUF_H
#pragma once // 仅编译一次
#include <string>
using namespace std;
// 函数声明
string getName();
#endif
b.cpp
//
#include <iostream>
#include "lauf.h" // 包含自定义的头文件
using namespace std;
// 项目工程 入口函数
int main() {
cout << getName() << endl; // 直接调用函数
return 0;
}
函数传参
- 值传递,实参的值拷贝一份给形参; 实参、形参互不影响;
- 引用传递,将实参的别名传给形参,实参、形参指向同一地址;
// bool 是C++的标准类型
bool cmpStr(string str1, string str2){ // 值传递
return str1.size() > str2.size();
}
bool cmpStr(string& str1, string& str2){ // 引用 别名 传递
return str1.size() > str2.size();
}
// 尽量使用常量引用 作为形参
bool cmpStr(const string& str1, const string& str2){ // 常量引用,无法通过引用修改变量的值
return str1.size() > str2.size();
}
// 调用时,传入 变量 或者 引用变量
string s1 = "jack";
string s2 = "tom";
string& s3 = s1; // 定义引用
cmpStr(s1, s2); // 传值 还是传引用 取决于形参类型
cmpStr(s1, s3);
- 数组传递,数组不允许直接拷贝;
- void operateArr(const int arr[ ], int size){}; 实参传入数组名(首地址)
- void operateArr(const int* ptr, int size){}; 实参传入数组名;
- void operateArr(const int(& arr)[10]){}; 实参传入数组名,进行数组的引用;
// 数组拷贝
#include <iostream>
#include "lauf.h" // 包含自定义的头文件
using namespace std;
void printArray(const int arr[], int size) { // 数组无法直接拷贝; 故函数内部无法使用sizeof计算数组的大小,所以必须传入数组的大小;
for (int i = 0; i < size; i++) {
cout << arr[i] << endl;
}
}
// 入口函数
int main() {
// 定义一个数组, 常量指定长度
int arr[5] = { 1, 2, 1, 3, 4 };
printArray(arr, 5); // 数组无法直接拷贝
return 0;
}
// 数组引用
#include <iostream>
#include "lauf.h" // 包含自定义的头文件
using namespace std;
void printArray(int(&arr)[5]) { // 必须指定长度
for (int i : arr) { // 遍历数组元素
cout << i << endl;
}
}
// 入口函数
int main() {
// 定义一个数组, 常量指定长度
int arr[5] = { 1, 2, 1, 3, 4 };
printArray(arr);
return 0;
}
// *********************
// 修改数组的值
#include <iostream>
#include "lauf.h" // 包含自定义的头文件
using namespace std;
void modifyArray(int (&arr)[5]) { // 必须指定长度
// 引用数组 可以使用sizeof 计算大小
int size = sizeof(arr) / sizeof(arr[0]);
cout << size << endl;
for (int i = 0; i < size; i++) {
// 修改数组的值
arr[i] = pow(arr[i], 2);
}
for (int e : arr) {
cout << e << endl;
}
}
// 入口函数
int main() {
// 定义一个数组, 常量指定长度
int arr[5] = { 1, 2, 1, 3, 4 };
modifyArray(arr);
return 0;
}
函数返回值
- 无返回值 void类型;
void func(int a, int b){
int c = a + b;
return; // 无返回值 return 可以省略
}
- 有返回值
// 返回值的拷贝
string func(const string& name){
return name; // 这里返回 name值的拷贝;
}
// 返回 值的引用
const string & func(const string& name){
return name; // 这里不会拷贝name的值,而是直接返回对其的引用(高效)
}
函数返回数组
- 方式1,指针形式
// 方式1
int* func(int n, int size) {
// 动态分配数组,使用new
int* arr = new int[size]; // 返回首地址(指针) 使用完成后 必须delete[] arr 释放
for (int i = 0; i < size; i++) {
// 数组赋值
arr[i] = pow(i, 2); // 取平方
}
return arr; // 返回数组首地址
}
// 入口函数
int main() {
// 指定数组的长度
int size = 5;
int* p = func(10, size); // 调用函数, 返回数组
// 输出
for (int i = 0; i < size; i++) {
cout << *(p + i) << endl; // 指针偏移,并解引用
}
delete[] p;// 删除 堆内存 中的空间
return 0;
}
-方式2,typedef 定义数组类型别名
#include <iostream>
#include "lauf.h" // 包含自定义的头文件
using namespace std;
// typedef 定义类型别名
typedef int lauf[5]; // 声明一个 长度为5的int数组 lauf类型
int arr[5] = { 1, 3, 5, 1, 6 }; // 全局变量 形式
// 定义返回 数组指针 的函数
lauf* func(int n) {
return &arr; // 返回数组的地址,如果函数内部定义数组 int arr[5] = { 1, 3, 5, 1, 6 }; 则函数执行结束弹栈(局部变量存在栈内存),数组内存被释放,再通过首地址取值就会出错!!!
// 必须使用static修饰
// static int arr[5] = {1,3,5,1,6}; // 静态数组对象,放入全局数据区,函数结束弹栈不会释放数组空间;
}
// 入口函数
int main() {
// 声明 数组指针 变量
int(*p)[5] = func(5); // 调用函数, 返回 数组指针
// 输出
for (int i = 0; i < 5; i++) {
cout << *(*p + i) << endl; // *p 解引用到arr的首地址
}
return 0;
}
- 方式3, 数组指针 类型后缀形式
#include <iostream>
#include "lauf.h" // 包含自定义的头文件
using namespace std;
// 后置类型
auto func(int n)->int(*)[5] {
//int arr[5] = { 1, 3, 5, 1, 6 }; 这种形式,函数执行结束会释放数组空间;
static int arr[5] = {1,2,5,1,6}; // 静态数组对象,放入全局数据区,函数结束弹栈不会释放数组空间;
return &arr; // 返回数组的地址
}
// 入口函数
int main() {
// 声明 数组指针 变量
int(*p)[5] = func(5); // 调用函数, 返回 数组指针
// 输出
for (int i = 0; i < 5; i++) {
cout << *(*p + i) << endl; // *p 解引用到arr的地址
}
return 0;
}
本文详细介绍了C++中的函数定义、作用域规则、参数传递(值传递与引用传递)、返回值(无返回值、返回拷贝、返回引用)以及函数返回数组的不同实现方法,包括指针、typedef和后置类型等。

1万+

被折叠的 条评论
为什么被折叠?



