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