第十课 指针与引用

指针和引用是C++的特色,掌握它们能让你更好地理解C++的内存管理,初学略有难度。(注:工程项目中,指针与引用普遍使用;算法竞赛一般较少使用,用数组代替。)

一、指针基础

  • 指针是存储变量地址的变量
  • 使用 * 定义指针
  • 使用 & 获取变量地址
  • 指针有类型(指向什么类型的变量)

指针定义和使用

#include <iostream>
using namespace std;

int main() {
    int a = 10;

    // 定义指针:类型 * 指针变量名
    int *p = &a;  // &获取a的地址

    cout << "a的值:" << a << endl;      // 10
    cout << "a的地址:" << &a << endl;    // 0x...(地址)
    cout << "p的值:" << p << endl;       // 0x...(a的地址)
    cout << "*p的值:" << *p << endl;     // 10(解引用)

    // 通过指针修改值
    *p = 20;
    cout << "a的新值:" << a << endl;     // 20

    return 0;
}

二、各种类型的指针

#include <iostream>
using namespace std;

int main() {
    int a = 10;
    double b = 3.14;
    char c = 'A';

    int *p1 = &a;
    double *p2 = &b;
    char *p3 = &c;

    cout << "int指针:" << *p1 << endl;     // 10
    cout << "double指针:" << *p2 << endl;  // 3.14
    cout << "char指针:" << *p3 << endl;    // A

    return 0;
}

三、空指针和野指针

#include <iostream>
using namespace std;

int main() {
    // 空指针:不指向任何地址
    int *p1 = NULL;        // C风格
    int *p2 = nullptr;      // C++11推荐

    // 野指针:未初始化的指针(危险!)
    // int *p3;  // 错误:野指针,指向未知地址

    // 使用前一定要初始化
    int a = 10;
    int *p4 = &a;  // 正确

    // 判断指针是否为空
    if (p1 != nullptr) {
        cout << "指针有效" << endl;
    } else {
        cout << "指针为空" << endl;  // 输出这个
    }

    return 0;
}

四、引用基础

  • 引用是变量的别名
  • 使用 & 定义引用
  • 引用必须在定义时初始化
  • 引用不可重新赋值

引用定义和使用

#include <iostream>
using namespace std;

int main() {
    int a = 10;

    // 定义引用:类型 & 引用名 = 变量名
    int &r = a;  // r是a的引用(别名)

    cout << "a的值:" << a << endl;   // 10
    cout << "r的值:" << r << endl;   // 10(和a一样)

    // 通过引用修改值
    r = 20;
    cout << "a的新值:" << a << endl;  // 20(a也变了)

    // 引用和原变量完全等价
    cout << "&a:" << &a << endl;     // 0x...
    cout << "&r:" << &r << endl;     // 0x...(同一个地址)

    return 0;
}

五、指针和引用的区别

#include <iostream>
using namespace std;

int main() {
    int a = 10, b = 20;

    // 指针可以为空,引用不能
    int *p = nullptr;     // 合法
    // int &r = nullptr;  // 错误

    // 指针可以重新赋值,引用不能
    int *p1 = &a;
    p1 = &b;             // 合法,指针指向b了
    // int &r1 = a;
    // r1 = b;             // 这是赋值,不是改变引用对象

    // 指针有多级指针,引用没有
    int **pp = &p1;      // 二级指针
    // int &&r2 = a;      // C++中&&是右值引用,不是二级引用

    // sizeof不同
    cout << "指针大小:" << sizeof(p1) << endl;   // 8(64位系统)
    cout << "引用大小:" << sizeof(r1) << endl;   // 4(和int一样)

    return 0;
}

六、函数参数传递

#include <iostream>
using namespace std;

// 值传递:复制一份,修改不影响原值
void byValue(int x) {
    x = 100;  // 只修改副本
}

// 指针传递:传地址,可以修改原值
void byPointer(int *p) {
    *p = 100;  // 修改原值
}

// 引用传递:传别名,可以修改原值
void byReference(int &r) {
    r = 100;  // 修改原值
}

int main() {
    int a = 10;

    // 值传递
    byValue(a);
    cout << "值传递后a:" << a << endl;  // 10(未改变)

    // 指针传递
    byPointer(&a);
    cout << "指针传递后a:" << a << endl;  // 100(改变了)

    a = 10;  // 恢复

    // 引用传递
    byReference(a);
    cout << "引用传递后a:" << a << endl;  // 100(改变了)

    return 0;
}

七、指针和数组

#include <iostream>
using namespace std;

int main() {
    int arr[5] = {1, 2, 3, 4, 5};

    // 数组名就是首元素地址
    int *p = arr;  // 等价于 int *p = &arr[0];

    // 方式1:下标访问
    for (int i = 0; i < 5; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    // 方式2:指针访问
    for (int i = 0; i < 5; i++) {
        cout << *(p + i) << " ";
    }
    cout << endl;

    // 指针算术运算
    int *p1 = &arr[0];
    int *p2 = &arr[4];
    cout << "p2-p1 = " << (p2 - p1) << endl;  // 4(元素个数差)

    return 0;
}

八、const指针

#include <iostream>
using namespace std;

int main() {
    int a = 10, b = 20;

    // 常量指针:不能通过指针修改值,但指针本身可以指向其他变量
    const int *p1 = &a;
    // *p1 = 30;  // 错误:不能通过p1修改a的值
    p1 = &b;     // 合法:p1可以指向其他变量

    // 指针常量:指针本身不能指向其他变量,但可以通过指针修改值
    int *const p2 = &a;
    *p2 = 30;    // 合法:可以通过p2修改a的值
    // p2 = &b;   // 错误:p2不能指向其他变量

    // 常量指针常量:都不能改
    const int *const p3 = &a;
    // *p3 = 40;  // 错误
    // p3 = &b;   // 错误

    return 0;
}

九、this指针

#include <iostream>
using namespace std;

class Person {
private:
    string name;
    int age;

public:
    void setInfo(string name, int age) {
        this->name = name;    // this指向当前对象
        this->age = age;
    }

    void show() {
        cout << "姓名:" << this->name << ",年龄:" << this->age << endl;
    }
};

int main() {
    Person p;
    p.setInfo("Tom", 18);
    p.show();

    return 0;
}

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注