27.函数返回值为指针

27.指针-指针和函数-函数返回值为指针


27.1 知识点

返回值为指针的函数是什么

顾名思义,函数返回指针,即返回一个指向数据的地址。通过返回指针,函数可以向外部提供数据的访问权限。

声明

int* returnPointer();  // 返回指针的函数

定义

int* returnPointer() {
    int* ptr = new int(10);  // 动态分配内存并初始化为 10
    return ptr;  // 返回指向该内存的指针
}

使用

// 调用返回指针的函数
int* ptr = returnPointer();  // 调用函数并获取返回的指针
cout << ptr << endl;  // 打印指针的地址,示例输出:0000025487FA78A0
cout << *ptr << endl;  // 解引用指针,输出指针指向的值 10

delete ptr;  // 释放动态分配的内存

返回指针变量指向地址的生命周期问题

返回指针变量时,需要特别注意指针指向的内存的生命周期问题。

  1. 局部变量:不允许返回局部变量地址,因为局部变量在函数执行完毕后就会被释放。即使打印了正确的值,之后可能无法正确访问。
  2. 静态变量:允许返回静态变量地址,因为静态变量生命周期从程序开始,一直持续到程序结束。
  3. 全局变量:允许返回全局变量地址,因为全局变量生命周期从程序开始,一直持续到程序结束。

声明

// 全局变量
int result = 0;

int* add(int a, int b);  // 返回局部变量地址的函数
int* add2(int a, int b); // 返回静态变量地址的函数
int* add3(int a, int b); // 返回全局变量地址的函数

void test(int array[][4], int rows);  // 打印二维数组的函数

定义

int* add(int a, int b) {
    // 局部变量
    int x = a + b;
    int* p = &x;  // 返回局部变量的地址
    return p;  // 但此时局部变量已经超出了作用域,返回值不可靠
}

int* add2(int a, int b) {
    // 静态变量
    static int c = a + b;  // 静态变量的生命周期贯穿程序运行
    return &c;  // 返回静态变量的地址
}

int* add3(int a, int b) {
    // 全局变量
    result = a + b;  // 修改全局变量
    return &result;  // 返回全局变量的地址
}

// 定义一个函数 test,接受一个二维数组作为参数
void test(int array[][4], int rows) {
    // 遍历二维数组并打印每个元素
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 4; j++) {
            cout << array[i][j] << " ";  // 打印当前元素
        }
        cout << endl;  // 每一行结束后换行
    }
}

使用

// 调用返回局部变量指针的函数
int* p = add(5, 5);
// cout << p << endl; // 如果加了这行,打印会输出无效地址
cout << *p << endl;  // 输出指针指向的值 10
cout << *p << endl;  // 输出指针指向的值,结果未定义,因为局部变量已经被销毁

// 调用返回静态变量指针的函数
p = add2(5, 5);
cout << p << endl;  // 输出静态变量的地址
cout << *p << endl;  // 输出静态变量的值 10
cout << *p << endl;  // 静态变量的值仍然是 10

// 调用返回全局变量指针的函数
p = add3(6, 6);
cout << p << endl;  // 输出全局变量的地址
cout << *p << endl;  // 输出全局变量的值 12
cout << *p << endl;  // 全局变量的值仍然是 12

// 再次调用返回全局变量指针的函数
p = add3(6, 6);
cout << p << endl;  // 输出全局变量的地址
cout << *p << endl;  // 输出全局变量的值 12
cout << *p << endl;  // 全局变量的值仍然是 12

// 声明并初始化一个 2x4 的二维数组
int array[2][4] = { {1, 2, 3, 4}, {5, 6, 7, 8} };

// 将 test 函数的地址赋给 void* 指针 pp
void* pp = (void*)test;

// 直接将 void* 指针转换为函数指针类型,并调用 test 函数
((void (*)(int(*)[4], int))pp)(array, 2);  // 通过转换后的函数指针调用,打印 1 2 3 4 5 6 7 8

尾置返回类型

尾置返回类型:在C++11中,可以使用尾置返回类型来声明函数的返回类型。在这种方式下,返回类型不在函数返回值前,而是放在参数列表之后,用 -> 指定返回类型。

示例:函数 getI 返回 int 类型的值。

声明

auto getI() -> int;  // 尾置返回类型函数声明
// 返回指针的尾置返回类型示例
auto returnPointerExample() -> int*;  // 返回一个指针,指向动态分配的内存

定义

auto getI() -> int
{
    return 10;
}

// 返回指针的尾置返回类型函数示例
auto returnPointerExample() -> int*
{
    int* ptr = new int(20);  // 动态分配内存并初始化为 20
    return ptr;  // 返回指向该内存的指针
}

使用

int i = getI();  // 调用尾置返回类型的函数
cout << i << endl;  // 输出 10

// 调用尾置返回类型返回指针的函数
int* ptrExample = returnPointerExample();  // 获取指向动态分配内存的指针
cout << ptrExample << endl;  // 输出指针地址
cout << *ptrExample << endl;  // 输出指针指向的值 20
cout << *ptrExample << endl;  // 输出指针指向的值 20 指向的内存地址没有被回收

delete ptrExample;  // 释放内存
// cout << *ptrExample << endl;  //报错 释放了内存

总结

  • 当函数返回指针时,必须确保指针指向的内存不会在函数结束后被销毁。

    • 不要返回指向局部变量的指针,因为局部变量会在函数结束时被销毁。
    • 可以返回指向静态变量或全局变量的指针,因为它们的生命周期贯穿整个程序运行。
  • 尾置返回类型是一种新的函数声明方式,特别适用于复杂的返回类型或函数指针。在尾置返回类型中,返回类型通过 -> 关键字声明在函数参数列表之后。


27.2 知识点代码

Lesson27_指针_指针和函数_函数返回值为指针.cpp

#include <iostream>
using namespace std;

#pragma region 知识点一 返回值为指针的函数是什么

int* returnPointer();  // 返回指针的函数

#pragma endregion

#pragma region 知识点二 返回指针变量指向地址的生命周期问题

// 全局变量
int result = 0;

int* add(int a, int b);  // 返回局部变量地址的函数
int* add2(int a, int b); // 返回静态变量地址的函数
int* add3(int a, int b); // 返回全局变量地址的函数

void test(int array[][4], int rows);  // 打印二维数组的函数

#pragma endregion

#pragma region 知识点三 尾置返回类型

auto getI() -> int;  // 尾置返回类型函数声明
// 返回指针的尾置返回类型示例
auto returnPointerExample() -> int*;  // 返回一个指针,指向动态分配的内存

#pragma endregion

int main() {
    std::cout << "函数返回值为指针\n";

    #pragma region 知识点一 返回值为指针的函数是什么

    // 调用返回指针的函数
    int* ptr = returnPointer();  // 调用函数并获取返回的指针
    cout << ptr << endl;  // 打印指针的地址,示例输出:0000025487FA78A0
    cout << *ptr << endl;  // 解引用指针,输出指针指向的值 10

    delete ptr;  // 释放动态分配的内存

    #pragma endregion

    #pragma region 知识点二 返回指针变量指向地址的生命周期问题

    // 调用返回局部变量指针的函数
    int* p = add(5, 5);
    // cout << p << endl; // 如果加了这行,打印会输出无效地址
    cout << *p << endl;  // 输出指针指向的值 10
    cout << *p << endl;  // 输出指针指向的值,结果未定义,因为局部变量已经被销毁

    // 调用返回静态变量指针的函数
    p = add2(5, 5);
    cout << p << endl;  // 输出静态变量的地址
    cout << *p << endl;  // 输出静态变量的值 10
    cout << *p << endl;  // 静态变量的值仍然是 10

    // 调用返回全局变量指针的函数
    p = add3(6, 6);
    cout << p << endl;  // 输出全局变量的地址
    cout << *p << endl;  // 输出全局变量的值 12
    cout << *p << endl;  // 全局变量的值仍然是 12

    // 再次调用返回全局变量指针的函数
    p = add3(6, 6);
    cout << p << endl;  // 输出全局变量的地址
    cout << *p << endl;  // 输出全局变量的值 12
    cout << *p << endl;  // 全局变量的值仍然是 12

    // 声明并初始化一个 2x4 的二维数组
    int array[2][4] = { {1, 2, 3, 4}, {5, 6, 7, 8} };

    // 将 test 函数的地址赋给 void* 指针 pp
    void* pp = (void*)test;

    // 直接将 void* 指针转换为函数指针类型,并调用 test 函数
    ((void (*)(int(*)[4], int))pp)(array, 2);  // 通过转换后的函数指针调用,打印 1 2 3 4 5 6 7 8

    #pragma endregion

    #pragma region 知识点三 尾置返回类型

    int i = getI();  // 调用尾置返回类型的函数
    cout << i << endl;  // 输出 10

    // 调用尾置返回类型返回指针的函数
    int* ptrExample = returnPointerExample();  // 获取指向动态分配内存的指针
    cout << ptrExample << endl;  // 输出指针地址
    cout << *ptrExample << endl;  // 输出指针指向的值 20
    cout << *ptrExample << endl;  // 输出指针指向的值 20

    delete ptrExample;  // 释放内存
    //cout << *ptrExample << endl;  //报错 释放了内存

    #pragma endregion
}

#pragma region 知识点一 返回值为指针的函数是什么

// 顾名思义,函数返回指针,即返回一个指向数据的地址。
// 通过返回指针,函数可以向外部提供数据的访问权限。
int* returnPointer() {
    int* ptr = new int(10);  // 动态分配内存并初始化为 10
    return ptr;  // 返回指向该内存的指针
}

#pragma endregion

#pragma region 知识点二 返回指针变量指向地址的生命周期问题

// 返回指针变量时,需要特别注意指针指向的内存的生命周期问题。
// 1. 局部变量:不允许返回局部变量地址,因为局部变量在函数执行完毕后就会被释放。
//    即使打印了正确的值,之后可能无法正确访问。
// 2. 静态变量:允许返回静态变量地址,因为静态变量生命周期从程序开始,一直持续到程序结束。
// 3. 全局变量:允许返回全局变量地址,因为全局变量生命周期从程序开始,一直持续到程序结束。

int* add(int a, int b) {
    // 局部变量
    int x = a + b;
    int* p = &x;  // 返回局部变量的地址
    return p;  // 但此时局部变量已经超出了作用域,返回值不可靠
}

int* add2(int a, int b) {
    // 静态变量
    static int c = a + b;  // 静态变量的生命周期贯穿程序运行
    return &c;  // 返回静态变量的地址
}

int* add3(int a, int b) {
    // 全局变量
    result = a + b;  // 修改全局变量
    return &result;  // 返回全局变量的地址
}

// 定义一个函数 test,接受一个二维数组作为参数
void test(int array[][4], int rows) {
    // 遍历二维数组并打印每个元素
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 4; j++) {
            cout << array[i][j] << " ";  // 打印当前元素
        }
        cout << endl;  // 每一行结束后换行
    }
}

#pragma endregion

#pragma region 知识点三 尾置返回类型

// 尾置返回类型:在C++11中,可以使用尾置返回类型来声明函数的返回类型。
// 在这种方式下,返回类型不在函数返回值前,而是放在参数列表之后,用 `->` 指定返回类型。
// 示例:函数 getI 返回 int 类型的值
auto getI() -> int
{
    return 10;
}

// 返回指针的尾置返回类型函数示例
auto returnPointerExample() -> int*
{
    int* ptr = new int(20);  // 动态分配内存并初始化为 20
    return ptr;  // 返回指向该内存的指针
}

#pragma endregion

#pragma region 总结

// 当函数返回指针时,必须确保指针指向的内存不会在函数结束后被销毁。
// - 不要返回指向局部变量的指针,因为局部变量会在函数结束时被销毁。
// - 可以返回指向静态变量或全局变量的指针,因为它们的生命周期贯穿整个程序运行。

// 尾置返回类型是一种新的函数声明方式,特别适用于复杂的返回类型或函数指针。
// 在尾置返回类型中,返回类型通过 `->` 关键字声明在函数参数列表之后。

#pragma endregion

27.3 练习题

编写一个函数,返回指向 两个值相加函数add 或 两个数相减函数multiply 的指针,具体返回哪个函数根据传入的字符(’+’ ‘-‘)决定。

声明

// 声明加法函数和减法函数
int add(int a, int b);
int multiply(int a, int b);

// 返回值为空类型指针的函数,返回指向函数的指针
void* getFunction(char c);

// 返回值为函数指针的函数,返回一个指向加法或减法函数的指针
int (*getFunction2(char c))(int, int);

// 使用尾置返回类型声明的返回值为函数指针的函数
auto getFunction3(char c) -> int (*)(int, int);

定义

// 加法函数
int add(int a, int b)
{
    return a + b;
}

// 减法函数
int multiply(int a, int b)
{
    return a - b;
}

// 根据传入字符返回对应的函数指针
// 如果字符为 '+' 返回加法函数指针,若为 '-' 返回减法函数指针
// 否则返回 nullptr
void* getFunction(char c)
{
    if (c == '+')
        return add;  // 返回加法函数指针
    else if (c == '-')
        return multiply;  // 返回减法函数指针
    else
        return nullptr;  // 返回空指针
}

// 返回值为函数指针的函数,返回指向加法或减法函数的指针
// 函数指针返回值类型为 int,参数为两个 int 类型的参数
int (*getFunction2(char c))(int, int)
{
    if (c == '+')
        return add;  // 返回加法函数指针
    else if (c == '-')
        return multiply;  // 返回减法函数指针
    else
        return nullptr;  // 返回空指针
}

// 使用尾置返回类型的方式,返回一个指向加法或减法函数的指针
auto getFunction3(char c) -> int (*)(int, int)
{
    if (c == '+')
        return add;  // 返回加法函数指针
    else if (c == '-')
        return multiply;  // 返回减法函数指针
    else
        return nullptr;  // 返回空指针
}

使用

// 获取加法或减法函数的指针,通过字符传入决定
void* p = getFunction('5');  // '5' 不是 '+' 或 '-',所以返回 nullptr
if (p != nullptr)
{
    // 将返回的 void* 类型指针转换为合适的函数指针类型并调用
    int v = ((int (*)(int, int))p)(5, 10);
    cout << v << endl; // 输出加法或减法的结果
}
else
    cout << "请通过+或-去获取函数" << endl;  // 未找到合适的函数

// 通过函数指针获取加法或减法函数并调用
int (*func)(int, int) = getFunction2('6');  // '6' 不是 '+' 或 '-',所以返回 nullptr
if (func != nullptr)
{
    cout << func(5, 6) << endl;  // 输出函数的计算结果
}
else
    cout << "请通过+或-去获取函数" << endl;

// 通过自动类型推导获取加法或减法函数并调用
int (*func2)(int, int) = getFunction3('-');  // 返回减法函数
if (func2 != nullptr)
{
    cout << func2(6, 6) << endl;  // 输出减法的结果
}
else
    cout << "请通过+或-去获取函数" << endl;

声明一个函数,该函数可以传入两个回调函数和一个数值,当这个值小于50时返回第一个回调,大于等于50时返回第二个回调函数。返回后在外部调用

声明

// 声明一个函数,该函数返回一个函数指针,依据条件返回不同的回调函数
void* getFunc(int i, void (*fun)(), void (*fun2)());

// 返回一个函数指针的函数,依据条件返回不同的回调函数
void (*getFunc2(int i, void (*fun)(), void (*fun2)()))();

// 使用尾置返回类型声明的返回值为函数指针的函数
auto getFunc3(int i, void (*fun)(), void (*fun2)()) -> void (*)();

// 定义两个简单的回调函数
void print1();
void print2();

定义

// 根据传入的数字选择不同的回调函数
// 如果数字小于50,返回第一个回调函数,否则返回第二个回调函数
void* getFunc(int i, void (*fun)(), void (*fun2)())
{
    if (i < 50)
        return fun;  // 返回第一个回调函数指针
    else
        return fun2;  // 返回第二个回调函数指针
}

// 返回一个函数指针,依据传入的数字选择不同的回调函数
void (*getFunc2(int i, void (*fun)(), void (*fun2)()))()
{
    if (i < 50)
        return fun;  // 返回第一个回调函数指针
    else
        return fun2;  // 返回第二个回调函数指针
}

// 使用尾置返回类型声明的函数,返回不同的回调函数指针
auto getFunc3(int i, void (*fun)(), void (*fun2)()) -> void (*)()
{
    if (i < 50)
        return fun;  // 返回第一个回调函数指针
    else
        return fun2;  // 返回第二个回调函数指针
}

// 第一个回调函数,输出 "小于50"
void print1()
{
    cout << "小于50" << endl;
}

// 第二个回调函数,输出 "大于等于50"
void print2()
{
    cout << "大于等于50" << endl;
}

使用

// 获取并调用不同的回调函数,传入的数字为51,选择第二个回调函数
void (*func3)() = (void (*)())getFunc(51, print1, print2);
func3();  // 输出 "大于等于50"

// 使用 getFunc2 获取回调函数并调用
func3 = getFunc2(44, print1, print2);  // 传入44,选择第一个回调函数
func3();  // 输出 "小于50"

// 使用 getFunc3 获取回调函数并调用
func3 = getFunc3(51, print1, print2);  // 传入51,选择第二个回调函数
func3();  // 输出 "大于等于50"

27.4 练习题代码

Lesson27_练习题.cpp

#include <iostream>
using namespace std;

#pragma region 练习题一

// 声明加法函数和减法函数
int add(int a, int b);
int multiply(int a, int b);

// 返回值为空类型指针的函数,返回指向函数的指针
void* getFunction(char c);

// 返回值为函数指针的函数,返回一个指向加法或减法函数的指针
int (*getFunction2(char c))(int, int);

// 使用尾置返回类型声明的返回值为函数指针的函数
auto getFunction3(char c) -> int (*)(int, int);

#pragma endregion

#pragma region 练习题二

// 声明一个函数,该函数返回一个函数指针,依据条件返回不同的回调函数
void* getFunc(int i, void (*fun)(), void (*fun2)());

// 返回一个函数指针的函数,依据条件返回不同的回调函数
void (*getFunc2(int i, void (*fun)(), void (*fun2)()))();

// 使用尾置返回类型声明的返回值为函数指针的函数
auto getFunc3(int i, void (*fun)(), void (*fun2)()) -> void (*)();

// 定义两个简单的回调函数
void print1();
void print2();

#pragma endregion

int main()
{
    std::cout << "函数返回值为指针 练习题\n";

    #pragma region 练习题一

    // 获取加法或减法函数的指针,通过字符传入决定
    void* p = getFunction('5');  // '5' 不是 '+' 或 '-',所以返回 nullptr
    if (p != nullptr)
    {
        // 将返回的 void* 类型指针转换为合适的函数指针类型并调用
        int v = ((int (*)(int, int))p)(5, 10);
        cout << v << endl; // 输出加法或减法的结果
    }
    else
        cout << "请通过+或-去获取函数" << endl;  // 未找到合适的函数

    // 通过函数指针获取加法或减法函数并调用
    int (*func)(int, int) = getFunction2('6');  // '6' 不是 '+' 或 '-',所以返回 nullptr
    if (func != nullptr)
    {
        cout << func(5, 6) << endl;  // 输出函数的计算结果
    }
    else
        cout << "请通过+或-去获取函数" << endl;

    // 通过自动类型推导获取加法或减法函数并调用
    int (*func2)(int, int) = getFunction3('-');  // 返回减法函数
    if (func2 != nullptr)
    {
        cout << func2(6, 6) << endl;  // 输出减法的结果
    }
    else
        cout << "请通过+或-去获取函数" << endl;

    #pragma endregion

    #pragma region 练习题二

    // 获取并调用不同的回调函数,传入的数字为51,选择第二个回调函数
    void (*func3)() = (void (*)())getFunc(51, print1, print2);
    func3();  // 输出 "大于等于50"

    // 使用 getFunc2 获取回调函数并调用
    func3 = getFunc2(44, print1, print2);  // 传入44,选择第一个回调函数
    func3();  // 输出 "小于50"

    // 使用 getFunc3 获取回调函数并调用
    func3 = getFunc3(51, print1, print2);  // 传入51,选择第二个回调函数
    func3();  // 输出 "大于等于50"

    #pragma endregion
}

#pragma region 练习题一

// 加法函数
int add(int a, int b)
{
    return a + b;
}

// 减法函数
int multiply(int a, int b)
{
    return a - b;
}

// 根据传入字符返回对应的函数指针
// 如果字符为 '+' 返回加法函数指针,若为 '-' 返回减法函数指针
// 否则返回 nullptr
void* getFunction(char c)
{
    if (c == '+')
        return add;  // 返回加法函数指针
    else if (c == '-')
        return multiply;  // 返回减法函数指针
    else
        return nullptr;  // 返回空指针
}

// 返回值为函数指针的函数,返回指向加法或减法函数的指针
// 函数指针返回值类型为 int,参数为两个 int 类型的参数
int (*getFunction2(char c))(int, int)
{
    if (c == '+')
        return add;  // 返回加法函数指针
    else if (c == '-')
        return multiply;  // 返回减法函数指针
    else
        return nullptr;  // 返回空指针
}

// 使用尾置返回类型的方式,返回一个指向加法或减法函数的指针
auto getFunction3(char c) -> int (*)(int, int)
{
    if (c == '+')
        return add;  // 返回加法函数指针
    else if (c == '-')
        return multiply;  // 返回减法函数指针
    else
        return nullptr;  // 返回空指针
}

#pragma endregion

#pragma region 练习题二

// 根据传入的数字选择不同的回调函数
// 如果数字小于50,返回第一个回调函数,否则返回第二个回调函数
void* getFunc(int i, void (*fun)(), void (*fun2)())
{
    if (i < 50)
        return fun;  // 返回第一个回调函数指针
    else
        return fun2;  // 返回第二个回调函数指针
}

// 返回一个函数指针,依据传入的数字选择不同的回调函数
void (*getFunc2(int i, void (*fun)(), void (*fun2)()))()
{
    if (i < 50)
        return fun;  // 返回第一个回调函数指针
    else
        return fun2;  // 返回第二个回调函数指针
}

// 使用尾置返回类型声明的函数,返回不同的回调函数指针
auto getFunc3(int i, void (*fun)(), void (*fun2)()) -> void (*)()
{
    if (i < 50)
        return fun;  // 返回第一个回调函数指针
    else
        return fun2;  // 返回第二个回调函数指针
}

// 第一个回调函数,输出 "小于50"
void print1()
{
    cout << "小于50" << endl;
}

// 第二个回调函数,输出 "大于等于50"
void print2()
{
    cout << "大于等于50" << endl;
}

#pragma endregion


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏