17.指针的基础使用

17.指针-指针的基础使用


17.1 知识点

指针的声明

声明写法:

变量类型* 指针变量名;

或者:

变量类型 *指针变量名;

注意事项:

  • 任何变量类型都可以声明为指针变量类型,只需要在变量类型后面加上一个 *
  • 指针变量的常用命名规范:
    • 前缀法:使用 pptr 作为前缀。
    • 后缀法:使用 _p_ptr 作为后缀。
    • 指针类型变量名:ptr\p+变量类型+变量名,例如 ptrIntValuepIntValue

示例:

int* p_i;
char* ptr_c;
float* f_ptr;
unsigned* u_p;
string* str_ptr;
int* ptrIntValue;

指针的初始化

指针必须赋值为内存中的有效地址(已经分配给变量的地址)。也就是说,在使用指针变量时,必须让它指向一个已经声明的变量,并且该变量的类型需要和指针变量的类型一致。

示例:

int i = 10;
// 如果我们想声明一个指针指向i的内存地址,我们需要获取到i的地址
// 我们可以利用地址符号 &i 来获取
int* p_i2 = &i;
cout << p_i2 << endl; // 0000007AE415F734

int* p_i3;
p_i3 = &i;
cout << p_i3 << endl; // 0000007AE415F734

为什么要用相同的变量类型的指针去存储地址?

  • 主要是因为一个变量所占用的内存单元可能是多个,而指针变量存储的是它第一个内存单元的门牌号。如果指针变量类型和存储的变量类型不一致,那么之后就无法准确地读取对应的内存单元,从而获取其中的内容。

示例:

float f = 5.5f;
float* f_ptr2 = &f;
cout << f_ptr2 << endl; // 0000007AE415F794

指针的解引用操作符

所谓的指针解引用操作符其实就是 *。如果我们想要获取指针所指向的内存地址中存储的值,只需要在指针变量前加上解引用操作符,就可以得到其中存储的值。

示例:

cout << *p_i2 << endl; // 10
cout << *f_ptr2 << endl; // 5.5

我们还可以利用解引用操作符改变原有的值:

*p_i2 = 99;
cout << *p_i2 << endl; // 99
cout << i << endl; // 99

空指针和野指针

  • 空指针:不指向任何有效内存的指针。可以将指针赋值为 nullptrNULL(老版本)表示该指针为空指针。

示例:

int* ptr_i5; // = nullptr;
ptr_i5 = nullptr;
  • 野指针:指向无效或不可预知内存地址的指针。野指针会导致程序出现各种不可预料的错误,例如程序崩溃、数据损坏、访问非法内存等。

野指针的主要出现原因:

  • 未初始化的指针(目前主要遇到的为该种情况)。
  • 指向内存被释放后仍使用的指针。
  • 指向内存位置超出作用域的指针。
  • 指向未定义为分配的内存的指针。

为了避免出现问题:

  • 在声明指针时,如果不马上使用,建议将指针声明为空指针。

总结

  1. 指针是存储变量内存地址的变量。
  2. 想要获取某个变量的地址,使用地址符号 & 来获取。
  3. 想要获取指针指向的内存地址中存储的值,使用解引用操作符(取值操作符) *
  4. 在声明指针时,如果不马上使用该指针,建议将其声明为空指针 nullptr
  5. 野指针会对程序带来不可预估的问题,需要引起重视。

对于 *& 的记忆口诀:

  • 看见 & 想地址。取地址。
  • 看见 * 想内容。解引用,取地址中的值。

17.2 知识点代码

Lesson17_指针_指针的基础使用.cpp

#include <iostream>
using namespace std;
int main()
{
    std::cout << "指针的基础使用\n";

    #pragma region 知识点一 指针的声明

    //声明写法:
    //变量类型* 指针变量名;
    //或
    //变量类型 *指针变量名;
    //注意:
    //1.任何变量类型都可以声明为指针变量类型
    //  就是在变量类型后面加一个*
    //2.指针变量的常用命名规范
    //  前缀法:p或ptr作为前缀
    //  后缀法:_p或_ptr作为后缀 
    //  指针类型变量名:ptr\p+变量类型+变量名 => ptrIntValue、pIntValue
    //  等等

    int* p_i;
    char* ptr_c;
    float* f_ptr;
    unsigned* u_p;
    string* str_ptr;
    int* ptrIntValue;

    #pragma endregion

    #pragma region 知识点二 指针的初始化

    //指针必须赋值为内存中的有效地址(已经分配给变量的地址)
    //也就是说,根据我们目前学习的知识,我们在使用指针变量时
    //必须让他指向一个已经声明了的变量,并且该变量的类型需要和指针变量的变量类型一致
    int i = 10;
    //如果我们想声明一个指针指向i的内存地址,我们需要获取到i的地址
    //我们可以利用 地址符号 &i 来获取
    int* p_i2 = &i;
    cout << p_i2 << endl;//0000007AE415F734
    int* p_i3;
    p_i3 = &i;
    cout << p_i3 << endl;//0000007AE415F734

    //为什么要用相同的变量类型的指针去存储地址
    //主要是因为 一个变量它所占用的内存单元可能是多个 而指针变量存储的是它第一个内存单元的门牌号
    //如果指针变量类型和存储的变量类型不一致,那么之后就无法准确的读取对应个数个内存单元
    //来获取其中的内容
    float f = 5.5f;
    float* f_ptr2 = &f;
    cout << f_ptr2 << endl;//0000007AE415F794

    #pragma endregion

    #pragma region 知识点三 指针的解引用操作符

    //所谓的 指针解引用操作符 其实就是 *
    //如果我们想要获取到指针所指向的内存地址中存储的值
    //我们只需要在指针变量前加一个解引用操作符,便可以得到其中存储的值
    cout << *p_i2 << endl;//10
    cout << *f_ptr2 << endl;//5.5
    //并且我们还可以利用它改变原有的值
    *p_i2 = 99;
    cout << *p_i2 << endl;//99
    cout << i << endl;//99

    #pragma endregion
                     
    #pragma region 知识点四 空指针和野指针

    //空指针是
    //不指向任何有效内存的指针
    //给指针赋值为 nullptr 或 NULL(老版本) 表示该指针为空指针
    int* ptr_i5;// = nullptr;
    ptr_i5 = nullptr;

    //野指针是
    //指向无效或不可预知内存地址的指针
    //野指针会导致程序出现各种不可预料的错误
    //比如:程序崩溃、数据损坏、访问非法内存等等
    //主要出现的原因:
    //1.未初始化的指针(目前主要遇到的为该种情况)
    //2.指向内存被释放后仍使用的指针
    //3.指向内存位置超出作用域的指针
    //4.指向未定义为分配的内存的指针
    //等等

    //注意:
    //为了避免出问题
    //在声明指针时如果不马上使用
    //建议将指针声明为空指针

    #pragma endregion

    #pragma region 总结

    //1.指针就是存储变量内存地址的变量
    //2.想要获取某一个变量地址 使用 地址符号 &来获取
    //3.想要获取指针指向内存地址中存储的值 使用解引用操作符(取值操作符)*
    //4.在声明指针时,如果不马上使用该指针,建议大家将其声明为空指针 nullptr
    //5.野指针会对程序带来不可预估的问题,需要引起重视

    //对于*和&的记忆口诀
    //看见&想地址
    //看见*想内容

    #pragma endregion
}

17.3 练习题

请问以下代码是否正确,为什么?

int *p;
int a = 100;
p = 100;

不正确。指针应该指向地址而不是具体的值。

请问以下代码的打印结果是多少?

int a1 = 10;
int* p1 = &a1;
int a2 = *p1;
a2 = 20;
cout << *p1 << endl;
cout << a1 << endl;

都是10。a2 只是把值复制过来,不会影响到 a1p1a2 是自己新开的房间。

请问以下代码的打印结果的含义是什么?

int a = 10;
int* p = &a;
cout << p << endl;
cout << &p << endl;
cout << *p << endl;
  • 整型变量 a 的地址(在 p 中存储)
  • 指针型变量 p 的地址(指向指针变量的地址)
  • 整型变量 a 的值(10)

请利用指针知识比较两个数的大小

提示:指针 P1P2P1 始终要存储更大的值,P2 始终要存储最小的值。最后打印信息时利用指针变量打印结果。

int a = 10;
int b = 20;

int* p1 = &a; // -> 10
int* p2 = &b; // -> 20

// 检查交换
if (*p1 < *p2)
{
    int* p = p1;
    p1 = p2;
    p2 = p;
}

cout << *p1 << endl; // 20
cout << *p2 << endl; // 10

17.4 练习题代码

Lesson17_练习题.cpp

#include <iostream>
using namespace std;
int main()
{
    std::cout << "指针的基础使用 练习题\n";

    #pragma region 练习题一

    /*请问以下代码是否正确,为什么?
    注意:不要通过敲代码验证,直接回答
    int* p;
    int a = 100;
    p = 100;*/

    //不正确 指针应该指向地址而不是具体的值

    #pragma endregion

    #pragma region 练习题二

    /*请问以下代码的打印结果是多少
    注意:不要通过敲代码验证,直接回答
    int a1 = 10;
    int* p1 = &a1;
    int a2 = *p1;
    a2 = 20;
    cout << *p1 << endl;
    cout << a1 << endl;*/

    //都是10 a2只是把值复制过来 不会影响到a1和p1 a2是自己新开的房间

    #pragma endregion

    #pragma region 练习题三

    /*请问以下代码的打印结果的含义是什么?
    注意:不要通过敲代码验证,直接回答
    int a = 10;
    int* p = &a;
    cout << p << endl;
    cout << &p << endl;
    cout << *p << endl;*/

    //整型变量a的地址(在p中存储)
    //指针型变量p的地址(指向指针变量的地址) 
    //整型变量a的值(10)

    #pragma endregion

    #pragma region 练习题四

    /*请利用指针知识比较两个数的大小
    提示:指针P1和P2,P1始终要存储更大的值,P2始终要存储最小的值
    最后打印信息时利用指针变量打印结果*/

    int a = 10;
    int b = 20;

    int* p1 = &a;// ->10
    int* p2 = &b;// ->20

    //检查交换
    if (*p1 < *p2)
    {
        int* p = p1;
        p1 = p2;
        p2 = p;
    }

    cout << *p1 << endl; // 20
    cout << *p2 << endl; // 10

    #pragma endregion

}


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

×

喜欢就点赞,疼爱就打赏