C++零基础到工程实战(5.2.4):指针与引用在函数传参、返回值与效率优化中的应用

目录

一、本节学习内容概要

二、指针和引用作为函数参数

[2.1 指针作为函数参数](#2.1 指针作为函数参数)

[2.2 引用作为函数参数](#2.2 引用作为函数参数)

[2.3 指针传参和引用传参的区别](#2.3 指针传参和引用传参的区别)

(1)指针传参:

(2)引用传参:

[三、const 修饰指针和引用时到底限制谁](#三、const 修饰指针和引用时到底限制谁)

[3.1 const int* x:不能修改指向的数据,但可以修改指针指向](#3.1 const int* x:不能修改指向的数据,但可以修改指针指向)

[3.2 int* const x:不能修改指针保存的地址,但可以修改指向的数据](#3.2 int* const x:不能修改指针保存的地址,但可以修改指向的数据)

[3.3 const int* const x:既不能修改值,也不能修改地址](#3.3 const int* const x:既不能修改值,也不能修改地址)

[3.4 三种写法对比总结](#3.4 三种写法对比总结)

[3.5 const int& x:不能修改引用绑定的变量](#3.5 const int& x:不能修改引用绑定的变量)

[3.6 指针和引用中 const 的最终理解](#3.6 指针和引用中 const 的最终理解)

四、使用指针和引用减少对象复制

[4.1 普通值传参会产生复制](#4.1 普通值传参会产生复制)

[4.2 使用 const string& 避免复制](#4.2 使用 const string& 避免复制)

[4.3 const char* 接收 C 风格字符串](#4.3 const char* 接收 C 风格字符串)

[4.4 右值引用 string&&](#4.4 右值引用 string&&)

五、指针和引用作为参数返回多个值,以及作为函数返回值

[5.1 指针作为参数返回多个值](#5.1 指针作为参数返回多个值)

[5.2 引用作为参数返回多个值](#5.2 引用作为参数返回多个值)

[5.3 指针作为函数返回值](#5.3 指针作为函数返回值)

[5.4 引用作为函数返回值](#5.4 引用作为函数返回值)

[5.5 不能返回普通局部变量的地址或引用](#5.5 不能返回普通局部变量的地址或引用)

六、完整代码与本节总结

[6.1 完整代码](#6.1 完整代码)

[6.2 本节核心总结](#6.2 本节核心总结)


目录

一、本节学习内容概要

二、指针和引用作为函数参数

三、const 修饰指针和引用时到底限制谁

四、使用指针和引用减少对象复制

五、指针和引用作为参数返回多个值,以及作为函数返回值

六、完整代码与本章小结


一、本节学习内容概要

在前面已经学习过指针、引用、栈区变量以及函数参数。本节继续围绕函数展开,重点理解:

cpp 复制代码
void TestParaPtr(const int* x, const int* y);
void TestParaRef(const int& x, const int& y);

这类写法的意义。

本节主要解决三个问题:

(1)为什么函数参数可以使用指针和引用?

因为指针和引用可以直接访问外部变量,避免把数据重新复制一份。对于 int 这类小数据影响不大,但对于 stringvector、结构体、类对象等较大的数据,可以明显减少复制成本。

(2)函数参数什么时候需要加 const

如果函数内部只是读取数据,不需要修改外部变量,就应该加 const

例如:

cpp 复制代码
void TestParaPtr(const int* x, const int* y);
void TestParaRef(const int& x, const int& y);

这样可以防止函数内部误修改原来的数据。

(3)指针和引用能不能作为返回值?

可以,但是必须注意生命周期问题。不能返回普通局部变量的地址和普通局部变量的引用。


二、指针和引用作为函数参数

2.1 指针作为函数参数

代码如下:

cpp 复制代码
void TestParaPtr(const int* x, const int* y)
{
    cout << "TestParaPtr " << *x << " " << *y << endl;
    cout << x << ":" << y << endl;
}

调用时:

cpp 复制代码
int x{ 99 };
int y{ 88 };

TestParaPtr(&x, &y);

这里要注意,函数形参是:

cpp 复制代码
const int* x
const int* y

所以调用时传入的必须是地址:

cpp 复制代码
TestParaPtr(&x, &y);

可以理解为:

  • 函数里的 x 保存的是外面变量 x 的地址
  • 函数里的 y 保存的是外面变量 y 的地址

所以在函数内部,如果想访问外面变量的值,就要使用解引用:

cpp 复制代码
*x
*y

完整理解如下:

复制代码
cout << *x << endl;

表示根据 x 保存的地址,找到对应变量的值并输出。


2.2 引用作为函数参数

代码如下:

cpp 复制代码
void TestParaRef(const int& x, const int& y)
{
    // x++;
    cout << "TestParaRef " << x << " " << y << endl;
    cout << &x << ":" << &y << endl;
}

调用时:

cpp 复制代码
TestParaRef(x, y);

引用和指针不同。

指针调用时需要传地址:

复制代码
TestParaPtr(&x, &y);

引用调用时直接传变量:

复制代码
TestParaRef(x, y);

因为引用可以理解为变量的别名。

也就是说,函数中的引用参数 x 和外面的变量 x 指向的是同一个数据。

所以函数内部可以直接使用:

复制代码
x
y

不需要写成:

复制代码
*x
*y

2.3 指针传参和引用传参的区别

(1)指针传参:

cpp 复制代码
void TestParaPtr(const int* x, const int* y);

TestParaPtr(&x, &y);

特点是:

  1. 调用时传地址;
  2. 函数内部用 *x 访问值;
  3. 可以传 nullptr;
  4. 从调用形式上能明显看出传的是地址。

(2)引用传参:

复制代码
void TestParaRef(const int& x, const int& y);

TestParaRef(x, y);

特点是:

  1. 调用时直接传变量;
  2. 函数内部直接用 x 访问值;
  3. 写法更像普通变量;
  4. 一般不能表示空引用。

简单来说:

复制代码
指针更强调地址;
引用更强调别名。

三、const 修饰指针和引用时到底限制谁

在函数传参时,经常会看到下面这种写法:

cpp 复制代码
void TestParaPtr(const int* x, const int* y);
void TestParaRef(const int& x, const int& y);

很多初学者看到**const 会直接理解成"这个变量不能改",但在指针中,const 的位置不同,限制的对象也不同。**

对于指针来说,主要有三种常见情况:

cpp 复制代码
const int* p;          // 不能通过 p 修改它指向的值,但是 p 可以改指向
int* const p;          // p 保存的地址不能改,但是可以通过 p 修改它指向的值
const int* const p;    // p 指向的值不能改,p 保存的地址也不能改

也就是说,const 修饰指针时,不能只看有没有 const,还要看 const 放在什么位置。


3.1 const int* x:不能修改指向的数据,但可以修改指针指向

代码中写的是:

cpp 复制代码
void TestParaPtr(const int* x, const int* y)
{
    cout << *x << endl;
    cout << *y << endl;
}

其中:

cpp 复制代码
const int* x

表示:

复制代码
x 指向的是一个不能被修改的 int 数据

所以函数内部不能写:

复制代码
*x = 100;   // 错误,不能通过 x 修改它指向的数据

例如:

cpp 复制代码
int a = 10;
int b = 20;

TestParaPtr(&a, &b);

调用时:

cpp 复制代码
TestParaPtr(&a, &b);

本质上是把 a 的地址传给形参 x

如果函数内部允许:

复制代码
*x = 100;

就相当于把外面的 a 改成了 100

但是由于形参写成了:

复制代码
const int* x

所以编译器不允许通过 x 修改它指向的数据。

也就是说:

复制代码
const int* x;

保护的是:

复制代码
*x

不是:

复制代码
x

所以下面这种写法是可以的:

cpp 复制代码
void TestParaPtr(const int* x, const int* y)
{
    int temp = 999;

    x = &temp;   // 正确,可以修改 x 自己保存的地址
}

为什么 x = &temp; 可以?

因为函数参数 x 本身也是一个局部变量。

调用时:

复制代码
TestParaPtr(&a, &b);

可以理解为:

复制代码
const int* x = &a;
const int* y = &b;
  1. 函数只是把 a 的地址复制一份给形参 x
  2. 所以在函数内部修改 x 的指向,只是修改形参指针变量自己保存的地址,不会改变外面的 a

因此:

复制代码
const int* p = &a;

*p = 100;  // 错误,不能修改 p 指向的数据
p = &b;    // 正确,可以让 p 指向 b

总结一句话:

const int* p 表示不能通过指针 p 修改它指向的数据,但是指针变量 p 自己保存的地址可以改变。


3.2 int* const x:不能修改指针保存的地址,但可以修改指向的数据

如果想让指针变量本身保存的地址不能改变,可以把 const 放在指针变量名前面:

复制代码
int* const x

这种写法表示:

x 是一个固定指向的指针

也就是说,x 一旦指向某个变量,就不能再指向其他变量。

例如:

cpp 复制代码
void TestParaPtr(int* const x, int* const y)
{
    *x = 100;    // 正确,可以修改 x 指向的数据

    int temp = 999;
    // x = &temp;   // 错误,不能修改 x 自己保存的地址
}

假设调用:

cpp 复制代码
int a = 10;
int b = 20;

TestParaPtr(&a, &b);

那么进入函数后,可以理解为:

cpp 复制代码
int* const x = &a;
int* const y = &b;

这里的 x 始终保存 a 的地址,不能再改成其他地址。

所以这句代码错误:

复制代码
x = &temp;   // 错误

因为这相当于想让 x 从指向 a 改成指向 temp

但是这句代码是正确的:

复制代码
*x = 100;

因为 int* const x 限制的是 x 这个指针变量不能改地址,并没有限制 x 指向的数据不能改。

所以:

cpp 复制代码
int* const p = &a;

*p = 100;  // 正确,可以修改 a 的值
p = &b;    // 错误,不能修改 p 保存的地址

总结一句话:

int* const p 表示指针变量 p 自己保存的地址不能改变,但是可以通过 p 修改它指向的数据。


3.3 const int* const x:既不能修改值,也不能修改地址

如果希望:

复制代码
不能通过指针修改外部变量的值;
也不能在函数内部改变指针自己的指向;

可以写成:

复制代码
const int* const x

例如:

cpp 复制代码
void TestParaPtr(const int* const x, const int* const y)
{
    // *x = 100;    // 错误,不能修改 x 指向的数据

    int temp = 999;
    // x = &temp;  // 错误,不能修改 x 自己保存的地址

    cout << *x << endl;
    cout << *y << endl;
}

这里:

复制代码
const int* const x

可以拆开看:

复制代码
const int*

表示:

复制代码
x 指向的数据不能被修改

后面的:

复制代码
const x

表示:

复制代码
x 自己保存的地址不能被修改

不过在普通函数参数中,最常用的还是:

复制代码
const int* p

因为大多数情况下,我们主要关心的是:

复制代码
这个函数不能修改外部传进来的数据。

至于形参指针变量自己在函数内部能不能改指向,一般影响不大,因为形参本身只是地址的一份拷贝。


3.4 三种写法对比总结

可以用一张表总结:

写法 能否修改 *p 指向的值 能否修改 p 保存的地址 含义
const int* p 不能 指向的数据不能改
int* const p 不能 指针自己的地址不能改
const int* const p 不能 不能 值和地址都不能改

用代码再看一遍:

cpp 复制代码
int a = 10;
int b = 20;

// 1. 指向的数据不能改,指针可以改指向
const int* p1 = &a;
// *p1 = 100;   // 错误
p1 = &b;        // 正确

// 2. 指针不能改指向,指向的数据可以改
int* const p2 = &a;
*p2 = 100;      // 正确
// p2 = &b;     // 错误

// 3. 指向的数据不能改,指针也不能改指向
const int* const p3 = &a;
// *p3 = 100;   // 错误
// p3 = &b;     // 错误

可以简单记忆为:

cpp 复制代码
const int* p;          // const 在 * 左边,限制的是 *p
int* const p;          // const 在 p 左边,限制的是 p
const int* const p;    // 两边都有 const,*p 和 p 都限制

3.5 const int& x:不能修改引用绑定的变量

引用参数中也可以加 const

cpp 复制代码
void TestParaRef(const int& x, const int& y)
{
    // x++;
    cout << x << " " << y << endl;
}

这里的:

复制代码
const int& x

表示:

复制代码
x 是外部变量的引用,但是不能通过 x 修改外部变量。

例如:

复制代码
int a = 10;

const int& r = a;

此时:

复制代码
r = 100;   // 错误,不能通过 r 修改 a

但是要注意,引用和指针有一个区别:

  1. 指针可以改变指向;
  2. 引用一旦绑定某个变量后,就不能再改成引用其他变量。

例如:

复制代码
int a = 10;
int b = 20;

int& r = a;

此时 ra 的别名。

如果写:

复制代码
r = b;

这不是让 r 改成引用 b,而是把 b 的值赋给 a

也就是说:

复制代码
r = b;

等价于:

复制代码
a = b;

引用本身没有"重新指向"的说法。

所以对于引用来说:

复制代码
int& r = a;        // 可以通过 r 修改 a
const int& r = a;  // 不能通过 r 修改 a

引用不像指针那样分成:

复制代码
能不能改地址
能不能改值

因为引用一旦绑定后,本来就不能再改绑定对象。


3.6 指针和引用中 const 的最终理解

这一部分可以这样总结:

对于指针来说,要区分两个东西:

复制代码
p   :指针变量自己保存的地址
*p  :指针指向的数据

所以:

复制代码
const int* p;

而:

复制代码
int* const p;

限制的是:

复制代码
p

如果写成:

复制代码
const int* const p;

则表示:

复制代码
p 不能改;
*p 也不能改。

对于引用来说:

复制代码
const int& r;

表示不能通过引用修改它绑定的变量。

最终记住这几句话即可:

cpp 复制代码
const int* p;          // 不能改值,可以改地址
int* const p;          // 可以改值,不能改地址
const int* const p;    // 值和地址都不能改
const int& r;          // 不能通过引用修改绑定的变量

放到函数参数中,可以这样选择:

cpp 复制代码
void Func(int* p);                 // 可以修改外部变量,也可以改形参指针指向
void Func(const int* p);           // 不能修改外部变量,但可以改形参指针指向
void Func(int* const p);           // 可以修改外部变量,但不能改形参指针指向
void Func(const int* const p);     // 不能修改外部变量,也不能改形参指针指向

void Func(int& x);                 // 可以修改外部变量
void Func(const int& x);           // 不能修改外部变量

实际开发中最常见的是:

cpp 复制代码
void Func(const int* p);
void Func(const int& x);
void Func(const string& str);

因为它们表达的意思很清楚:

函数只读取传入的数据,不会修改原始变量,同时还能减少复制。


四、使用指针和引用减少对象复制

4.1 普通值传参会产生复制

代码中有这个函数:

cpp 复制代码
void TestString(string str)
{
    cout << "TestString " << str << endl;
    cout << &str << endl;
}

调用:

cpp 复制代码
string str = "test string";
TestString(str);

这里是普通值传参。

也就是说,函数会重新创建一个形参变量 str,然后把外面的字符串内容复制一份进来。

可以理解为:

复制代码
外面的 string str
        ↓ 复制一份
函数里面的 string str

所以函数内部打印的:

复制代码
&str

函数内部形参的地址,不是外面那个 str 的地址。

对于 intdouble 这种小数据,复制成本很低。

但是对于:

复制代码
string
vector
结构体
类对象

如果数据比较大,复制成本就会增加。


4.2 使用 const string& 避免复制

代码如下:

cpp 复制代码
void TestStringRef(const string& str)
{
    cout << "TestStringRef " << str << endl;
    cout << &str << endl;
}

调用:

cpp 复制代码
TestStringRef("test");

这里使用的是:

复制代码
const string& str

它的作用有两个:

  1. & :使用引用接收,避免复制
  2. const :只读取,不修改原始数据

所以对于较大的对象,如果函数内部只是读取,不修改,推荐写法是:

cpp 复制代码
void Func(const string& str);
void Func(const vector<int>& v);
void Func(const Student& stu);

这样既能减少复制,又能防止函数内部误修改数据。


4.3 const char* 接收 C 风格字符串

代码如下:

cpp 复制代码
void TestStringPara(const char* str)
{
    cout << "TestStringPara " << str << endl;
    cout << static_cast<const void*>(str) << endl;
}

调用:

cpp 复制代码
TestStringPara("test");

这里的 "test" 是字符串常量。

形参:

cpp 复制代码
const char* str

表示:

  1. str 保存字符串首字符的地址;
  2. 不能通过 str 修改字符串内容。

注意这句:

cpp 复制代码
cout << static_cast<const void*>(str) << endl;

为什么要转成**const void*?**

因为如果直接输出:

cpp 复制代码
cout << str << endl;

cout 会把 char* 当成字符串输出,而不是输出地址。

如果想打印字符串的地址,需要写成:

cpp 复制代码
cout << static_cast<const void*>(str) << endl;

4.4 右值引用 string&&

代码如下:

cpp 复制代码
void TestStringRight(string&& str)
{
    cout << "TestStringRight " << str << endl;
    cout << &str << endl;
}

调用:

cpp 复制代码
TestStringRight("test string");
TestStringRight(string("test"));

这里的:

复制代码
string&&

右值引用,主要用于接收临时对象。

例如:

复制代码
string("test")

就是临时创建出来的 string 对象。

本节先简单理解为:

复制代码
string&& 可以接收临时对象,为后续移动语义做准备。

后面学习移动构造、移动赋值、完美转发时,还会继续用到右值引用。


五、指针和引用作为参数返回多个值,以及作为函数返回值

5.1 指针作为参数返回多个值

函数正常情况下只能直接返回一个值。

但是如果希望一个函数返回多个结果,可以通过指针参数修改外部变量。

代码如下:

cpp 复制代码
void GetPosPtr(int* x, int* y)
{
    *x = 800;
    *y = 600;
}

调用:

cpp 复制代码
int x{ 99 };
int y{ 88 };

GetPosPtr(&x, &y);

cout << "x:" << x << " y:" << y << endl;

输出结果:

复制代码
x:800 y:600

原因是:

复制代码
GetPosPtr(&x, &y);

把外面变量的地址传进函数。

函数内部:

复制代码
*x = 800;
*y = 600;

通过地址找到外面的变量,并修改外面的变量。

所以指针参数不仅可以减少复制,还可以作为输出参数,让函数修改外部数据。


5.2 引用作为参数返回多个值

代码如下:

cpp 复制代码
void GetPosRef(int& x, int& y)
{
    x = 640;
    y = 480;
}

调用:

cpp 复制代码
GetPosRef(x, y);

cout << "x:" << x << " y:" << y << endl;

输出结果:

复制代码
x:640 y:480

引用方式看起来更简单。

指针写法:

复制代码
GetPosPtr(&x, &y);

引用写法:

复制代码
GetPosRef(x, y);

指针函数内部要写:

复制代码
*x = 800;
*y = 600;

引用函数内部直接写:

复制代码
x = 640;
y = 480;

所以引用作为输出参数时,写法更接近普通变量。

但是引用传参有一个问题:

复制代码
GetPosRef(x, y);

从调用处不一定能直接看出 xy 会被修改。

而指针传参:

复制代码
GetPosPtr(&x, &y);

因为传入了地址,所以修改意图更加明显。


5.3 指针作为函数返回值

代码如下:

cpp 复制代码
int* GetPosPtr()
{
    static int pos{ 0 };
    cout << "GetPosPtr pos:" << pos << endl;
    return &pos;
}

调用:

cpp 复制代码
auto res = GetPosPtr();
(*res) += 10;
GetPosPtr();

第一次调用:

复制代码
auto res = GetPosPtr();

函数返回的是:

复制代码
&pos

也就是 pos 的地址。

所以:

复制代码
res

保存的是 pos 的地址。

然后:

复制代码
(*res) += 10;

表示通过指针找到 pos,并让 pos10

再次调用:

复制代码
GetPosPtr();

会发现 pos 的值已经变成了 10

这里为什么可以返回 pos 的地址?

因为**pos 是静态局部变量:**

复制代码
static int pos{ 0 };

静态局部变量不会在函数结束后销毁,它的生命周期会持续到程序结束。

所以可以返回它的地址。


5.4 引用作为函数返回值

代码如下:

cpp 复制代码
int& GetPosRef()
{
    static int pos{ 0 };
    cout << "GetPosRef pos:" << pos << endl;
    return pos;
}

调用:

cpp 复制代码
auto& r2 = GetPosRef();
r2 += 20;
GetPosRef();

这里:

复制代码
int& GetPosRef()

表示函数返回一个 int 类型的引用。

函数内部:

复制代码
static int pos{ 0 };
return pos;

返回的是静态局部变量 pos 的引用。

调用时:

复制代码
auto& r2 = GetPosRef();

这里一定要写成:

复制代码
auto& r2

表示 r2 是返回值的引用。

也就是说:

复制代码
r2 是 pos 的别名

所以:

复制代码
r2 += 20;

就相当于:

复制代码
pos += 20;

再次调用:

复制代码
GetPosRef();

就能看到 pos 已经变成了 20


5.5 不能返回普通局部变量的地址或引用

虽然指针和引用可以作为返回值,但不能随便返回。

错误写法一:

复制代码
int* ErrorPtr()
{
    int pos = 0;
    return &pos;   // 错误
}

错误写法二:

复制代码
int& ErrorRef()
{
    int pos = 0;
    return pos;    // 错误
}

原因是:

复制代码
int pos = 0;
  1. 这是普通局部变量,存放在栈区。
  2. 函数结束后,pos 的生命周期结束,这块空间就不再属于 pos
  3. 此时返回出去的地址或引用已经失效。

这种问题叫:

复制代码
悬空指针
悬空引用

所以要记住:

复制代码
不能返回普通局部变量的地址;
不能返回普通局部变量的引用。

如果要返回指针或引用,必须保证返回的数据在函数结束后仍然存在。

例如:

复制代码
static 局部变量
全局变量
堆区对象
类成员变量

六、完整代码与本节总结

6.1 完整代码

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>
using namespace std;

// 1. 指针和引用作为参数,减少复制,不修改
void TestParaPtr(const int* x, const int* y)
{
    cout << "TestParaPtr " << *x << " " << *y << endl;
    cout << x << ":" << y << endl;
}

void TestParaRef(const int& x, const int& y)
{
    // x++;
    cout << "TestParaRef " << x << " " << y << endl;
    cout << &x << ":" << &y << endl;
}

void TestStringPara(const char* str)
{
    cout << "TestStringPara " << str << endl;
    cout << static_cast<const void*>(str) << endl;
}

void TestStringRef(const string& str)
{
    cout << "TestStringRef " << str << endl;
    cout << &str << endl;
}

void TestString(string str)
{
    cout << "TestString " << str << endl;
    cout << &str << endl;
}

void TestStringRight(string&& str)
{
    cout << "TestStringRight " << str << endl;
    cout << &str << endl;
}

// 2. 指针和引用作为参数,返回多个值
void GetPosPtr(int* x, int* y)
{
    *x = 800;
    *y = 600;
}

void GetPosRef(int& x, int& y)
{
    x = 640;
    y = 480;
}

// 3. 指针和引用在返回值中的作用
int* GetPosPtr()
{
    static int pos{ 0 };
    cout << "GetPosPtr pos:" << pos << endl;
    return &pos;
}

int& GetPosRef()
{
    static int pos{ 0 };
    cout << "GetPosRef pos:" << pos << endl;
    return pos;
}

int main()
{
    int x{ 99 };
    int y{ 88 };

    TestParaPtr(&x, &y);
    TestParaRef(x, y);

    GetPosPtr(&x, &y);
    cout << "x:" << x << " y:" << y << endl;

    GetPosRef(x, y);
    cout << "x:" << x << " y:" << y << endl;

    string str = "test string";

    TestStringPara("test");
    TestStringRef("test");
    TestString(str);
    TestStringRight("test string");
    TestStringRight(string("test"));

    auto res = GetPosPtr();
    (*res) += 10;
    GetPosPtr();

    auto& r2 = GetPosRef();
    r2 += 20;
    GetPosRef();

    return 0;
}

6.2 本节核心总结

本节可以总结为以下几点。

(1)指针作为函数参数时,调用需要传地址:

cpp 复制代码
TestParaPtr(&x, &y);

函数内部通过解引用访问或修改数据:

复制代码
*x
*y

(2)引用作为函数参数时,调用直接传变量:

cpp 复制代码
TestParaRef(x, y);

函数内部直接使用变量名:

复制代码
x
y

(3)如果函数内部只读取数据,不修改外部变量,建议加 const

cpp 复制代码
void Func(const int* p);
void Func(const int& x);
void Func(const string& str);

(4)const int* p 限制的是 *p,不是 p

也就是说:

复制代码
*p = 100;  // 错误,不能修改指向的数据
p = &b;    // 正确,可以改变指针自己的指向

如果想让值和地址都不能改,需要写成:

cpp 复制代码
const int* const p = &a;

**(5)对于 stringvector、结构体、类对象等较大的数据,推荐使用:**引用

cpp 复制代码
const string& str
const vector<int>& v
const Student& stu

这样可以减少复制,提高效率。

(6)指针和引用可以作为返回值,但要注意生命周期。

正确写法:

cpp 复制代码
int& Func()
{
    static int x = 10;
    return x;
}

错误写法:

cpp 复制代码
int& Func()
{
    int x = 10;
    return x;   // 错误,不能返回局部变量引用
}

最后用一句话总结:

  1. 指针和引用作为函数参数,可以减少对象复制,也可以让函数修改外部变量;
  2. 如果只读取不修改,应加 const
  3. 指针和引用作为返回值时,必须保证返回的数据在函数结束后仍然有效,不能返回栈区局部变量的地址或引用。
相关推荐
L_09072 小时前
【C++】面向对象三大特性之多态
开发语言·c++
小张成长计划..2 小时前
【C++】33:反向迭代器的实现(扩展)
c++
小明同学012 小时前
C++后端项目:统一大模型接入 SDK(五)
服务器·c++·后端·计算机网络·语言模型
Hua-Jay3 小时前
OpenCV联合C++/Qt 学习笔记(二十四)----差值法检测移动物体、稠密光流法跟踪移动物体及稀疏光流法跟踪移动物体
c++·笔记·qt·opencv·学习·计算机视觉
郭老二3 小时前
【C++】RPC:远程程序调用
c++·rpc
承渊政道3 小时前
【贪心算法】(经典实战应用解析(六):整数替换、俄罗斯套娃信封问题、可被三整除的最⼤和、距离相等的条形码、重构字符串)
c++·算法·leetcode·贪心算法·排序算法·动态规划·哈希算法
宠..3 小时前
VS Code SSH 远程连接 Ubuntu 并实现快速运行(C/C++示例)
java·运维·c语言·开发语言·c++·ubuntu·ssh
闻缺陷则喜何志丹3 小时前
【图论 树 启发式合并】P7165 [COCI2020-2021#1] Papričice|普及+
c++·算法·启发式算法·图论··洛谷
alexwang2113 小时前
AT_abc458_d [ABC458D] Chalkboard Median题解
c++·算法·题解·atcoder