• 【C++基础】10. 指针


    • 指针的作用:通过指针,可以简化一些 C++ 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。
    • 内存和指针的关系:每一个变量都有一个内存位置(理解为:每一个变量在内存中都占有一个位置 / 占用一定内存空间),每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。 内存位置相当于房间,地址相当于门牌号

    【 1. 指针的定义 】

    • 指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
    • 不同数据类型的指针都是一个代表内存地址的长的十六进制数 。唯一的不同是,指针所指向的变量或常量的数据类型不同。
    • 指针变量声明的一般形式为:
      • type 是指针的基类型,它必须是一个有效的 C++ 数据类型;
      • 用来声明指针的星号 * 与乘法中使用的星号是相同的,但在这个语句中,星号用来指定一个变量是指针;
      • var-name 是指针变量的名称。
    type *var-name;
    
    • 1
    • 实例:有效的指针声明:
    int    *ip;    /* 一个整型的指针 */
    double *dp;    /* 一个 double 型的指针 */
    float  *fp;    /* 一个浮点型的指针 */
    char   *ch;    /* 一个字符型的指针 */
    
    • 1
    • 2
    • 3
    • 4

    【 2. 指针的调用 】

    • 使用指针时会频繁进行以下几个操作:① 定义一个指针变量② 把变量地址赋值给指针③ 访问指针变量中可用地址的值。这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。
    #include 
    using namespace std;
    
    int main ()
    {
       int  var = 20;   // 实际变量的声明
       int  *ip;        // 指针变量的声明
    
       ip = &var;       // 在指针变量中存储 var 的地址
    
       cout << "Value of var variable: ";
       cout << var << endl;
    
       // 输出在指针变量中存储的地址
       cout << "Address stored in ip variable: ";
       cout << ip << endl;
    
       // 访问指针中地址的值
       cout << "Value of *ip variable: ";
       cout << *ip << endl;
    
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    【 3. NULL 空指针 】

    • 在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值(即指向地址为0的内存)是一个良好的编程习惯。赋为 NULL 值的指针被称为 空指针
    • NULL 指针是一个定义在标准库中的值为零的常量。
    • 地址为0的内存 在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而 指向内存地址 0的NULL空指针表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
    • 实例:
    #include 
    
    using namespace std;
    
    int main ()
    {
       int  *ptr = NULL; // ptr为NULL指针,指向地址为0的内存
       cout << "ptr 的值是 " << ptr ;
       if 0  // 测试查看ptr指向的值,报错说明地址为0的内存不可访问
          cout << "*ptr 的值是 " << *ptr ;
       end
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    • 检查一个指针是否是空指针:
    if(ptr)     /* 如果 ptr 非空,则完成 */
    if(!ptr)    /* 如果 ptr 为空,则完成 */
    
    • 1
    • 2
    • NULL指针的意义:很多时候,未初始化的变量存有一些垃圾值,导致程序难以调试。因此, 如果所有未使用的指针都被赋予空值,同时避免使用空指针,就可以 防止误用一个未初始化的指针

    【 4. 指针的算术运算 】

    • 指针的值表示地址,但归根到底还是一个变量。因此,我们可以对指针执行算术运算。
    • 可以对指针进行四种算术运算:++、- -、+、-。
    • 指针运算的基本单元 = 指针指向变量的数据类型所占字节大小
    • 假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,我们对该指针执行下列的算术运算:ptr++;
      在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 个字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。
    • 如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。

    4.1 指针的递加

    • 实例:下面的程序递增变量指针,以便顺序访问数组中的每一个元素
    #include 
    
    using namespace std;
    const int MAX = 3;
    
    int main ()
    {
       int  var[MAX] = {10, 100, 200};
       int  *ptr;
    
       // 指针中的数组地址
       ptr = var;
       for (int i = 0; i < MAX; i++)
       {
          cout << "Address of var[" << i << "] = ";
          cout << ptr << endl;
    
          cout << "Value of var[" << i << "] = ";
          cout << *ptr << endl;
    
          // 移动到下一个位置
          ptr++;
       }
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    4.2 指针的递减

      • 实例:下面的程序递减变量指针,以便顺序访问数组中的每一个元素。
    #include 
    
    using namespace std;
    const int MAX = 3;
    
    int main ()
    {
       int  var[MAX] = {10, 100, 200};
       int  *ptr;
    
       // 指针中最后一个元素的地址
       ptr = &var[MAX-1];
       for (int i = MAX; i > 0; i--)
       {
          cout << "Address of var[" << i << "] = ";
          cout << ptr << endl;
    
          cout << "Value of var[" << i << "] = ";
          cout << *ptr << endl;
    
          // 移动到下一个位置
          ptr--;
       }
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    4.3 指针的比较

    • 指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。
    • 下面的程序修改了上面的实例,只要变量指针所指向的地址小于或等于数组的最后一个元素的地址 &var[MAX - 1],则把变量指针进行递增:
    #include 
    
    using namespace std;
    const int MAX = 3;
    
    int main ()
    {
       int  var[MAX] = {10, 100, 200};
       int  *ptr;
    
       // 指针中第一个元素的地址
       ptr = var;
       int i = 0;
       while ( ptr <= &var[MAX - 1] )
       {
          cout << "Address of var[" << i << "] = ";
          cout << ptr << endl;
    
          cout << "Value of var[" << i << "] = ";
          cout << *ptr << endl;
    
          // 指向上一个位置
          ptr++;
          i++;
       }
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

    【 5. 指针与数组 】

    5.1 通过指针操作数组

    • 我们经常在程序中使用指针存储数组首元素的地址,即指针指向数组首元素。这是因为 指针作为一个变量可以递增,而 数组名本身就是一个常指针,不能赋值
    #include 
    
    using namespace std;
    const int MAX = 3;
    
    int main ()
    {
       int  var[MAX] = {10, 100, 200};
       int *ptr;
       ptr= var;
    	
       for (int i = 0; i < MAX; i++)
       { 
    	 if (1) // 正确的 
    	 {
    	 	cout<< *ptr <<endl;
    	 	ptr++;
    	 }
    	 else // 错误的
    	 {
    	 	cout<< *var  <<endl; 
    	 	//var++; // 数组名是常指针,不能被赋值
    	 }
       }
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    • 通过指针修改数组元素值
    *(var + 2) = 500;
    
    • 1

    5.2 指针数组、数组指针

    【 6. 指向指针的指针(多级间接寻址)】

    • 指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时, 第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的地址
    • 一个指向指针的指针变量必须如下声明,即 在变量名前放置两个星号。如下声明了一个指向 int 类型指针的指针:
    int **var;
    
    • 1
    • 实例:当一个目标值被一个指针间接指向到另一个指针时,访问这个值需要使用两个星号运算符:
    #include 
    
    using namespace std;
    
    int main ()
    {
        int  var;
        int  *ptr;
        int  **pptr;
    
        var = 3000;
    
        // 获取 var 的地址
        ptr = &var;
    
        // 使用运算符 & 获取 ptr 的地址
        pptr = &ptr;
    
        // 使用 pptr 获取值
        cout << "var 值为 :" << var << endl;
        cout << "*ptr 值为:" << *ptr << endl;
        cout << "**pptr 值为:" << **pptr << endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    【 7. 传递指针给函数 】

    • C++ 允许我们传递指针给函数,只需简单地声明函数参数为指针类型即可。
    • 指针作为函数形参时,若在函数内部改变了指针所指向变量的值,则调用完该函数后该变量的值也会变化,因为这是直接对指针所指向的内存地址中的数据进行操作的。
    • 实例
    #include 
    #include 
    
    using namespace std;
    void getSeconds(unsigned long *par)
    {
       // 获取当前的秒数
       *par = time( NULL );
       return;
    }
    
    int main ()
    {
       unsigned long sec;
    
    
       getSeconds( &sec );
    
       // 输出实际值
       cout << "Number of seconds :" << sec << endl;
    
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    • 实例:数组名作为函数形参
    #include 
    using namespace std;
    
    // 函数声明
    double getAverage(int *arr, int size);
    
    int main ()
    {
       // 带有 5 个元素的整型数组
       int balance[5] = {1000, 2, 3, 17, 50};
       double avg;
    
       // 传递一个指向数组的指针作为参数
       avg = getAverage( balance, 5 ) ;
    
       // 输出返回值
       cout << "Average value is: " << avg << endl; 
    
       return 0;
    }
    
    double getAverage(int *arr, int size)
    {
      int    i, sum = 0;       
      double avg;          
    
      for (i = 0; i < size; ++i)
      {
        sum += arr[i];
       }
    
      avg = double(sum) / size;
    
      return avg;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在这里插入图片描述

    【 8. 函数返回指针 】

    • 从函数返回指针,一般形式:
    int * myFunction()
    {
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量
    • 实例:生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下:
    #include 
    #include 
    #include 
    
    using namespace std;
    
    // 要生成和返回随机数的函数
    int * getRandom( )
    {
      static int  r[10];
    
      // 设置种子
      srand( (unsigned)time( NULL ) );
      for (int i = 0; i < 10; ++i)
      {
        r[i] = rand();
        cout << r[i] << endl;
      }
    
      return r;
    }
    
    // 要调用上面定义函数的主函数
    int main ()
    {
       // 一个指向整数的指针
       int *p;
    
       p = getRandom();
       for ( int i = 0; i < 10; i++ )
       {
           cout << "*(p + " << i << ") : ";
           cout << *(p + i) << endl;
       }
    
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    在这里插入图片描述

  • 相关阅读:
    tk跨境电商好做吗?有什么技巧吗?
    react前端优化小结笔记
    【零基础学QT】第九章 窗口美化QSS的使用
    华为设备配置CPU防攻击命令
    VMware虚拟机安装CentOS6.9设置静态ip
    腾讯JAVA后端秋招面试总结
    Kotlin 协程 - 多路复用 select()
    基于STAN的风力发电预测(Python代码实现)
    详解深度学习中,如何进行反向传播
    使用 AutoGen 的 AI 智能体设计模式
  • 原文地址:https://blog.csdn.net/qq_44431690/article/details/133847007