zoukankan      html  css  js  c++  java
  • C++---指针和引用

    指针

    基本使用

    • 指针是一个值为内存地址的变量.

    image-20200502162555918

    语法: 数据类型 * 指针变量名;
    
    int * ptr_num;
    char* ptr_name;
    float* money_ptr;
    double* p_price;
    
    • 注意:
      • int* p 的写法偏向于地址, 即p就是一个地址变量, 表示一个十六进制的地址
      • int *p 的写法偏向于值, *p是一个整型变量, 能够表示一个整型值
      • 声明中的* 和使用中的 * 含义完全不一样.

    取地址符&

    image-20200502163046800

    int num = 1024;
    int* ptr_num;
    //取num变量的地址复制给ptr_num
    ptr_num = #
    

    间接运算符*

    image-20200502163220991

    int num = 1024;
    int* ptr_num;
    ptr_num = #
    *ptr_num = 1111;    //等价于 num = 1111;
    
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        double num = 1024.5;
        //定义一个指针, 并指向num变量
        double* ptr_num = &num;
        cout << "ptr_num的值: " << ptr_num << "	" << &num << endl;
        cout << "ptr_num指向空间的值:" << *ptr_num << endl;
    
        char ch = 'a';
        char* ptr_ch = &ch;
        cout << "ptr_ch的值: " << (void *)ptr_ch << "	" << "ptr_ch指向空间的值:" << *ptr_ch << endl;
        return 0;
    }
    

    空指针

    • 空指针不指向任何对象, 在试图使用一个指针之前可以首先检查是否为空
    • 尽量在定义了对象之后再定义指向它的指针
    int *ptr1 = nullptr;  //等价于 int *ptr1 = 0;
    int *ptr2 = 0;
    
    //需要包含cstdlib
    int *ptr3 = NULL;	  //等价于 int *ptr3 = 0;
    

    void * 指针

    • 一种特殊的指针类型, 可以存放任意对象的地址
    • void *指针存放一个内存地址, 地址指向的内容是什么类型不能确定
    • void *类型指针一般用来: 和别的指针比较, 作为函数的输入和输出, 赋值给另一个void *指针
    double obj_num = 3.14;
    double *ptr_obj = &obj_num;
    
    cout << boolalpha;
    void *vptr_obj = &obj_num;
    cout << (ptr_obj == vptr_obj) << endl;
    

    小结

    • 指针是一个变量, 存储的是另一个对象的内存地址
    • 如果一个变量存储了另一个对象的地址, 则称该变量指向这个对象
    • 指针变量可以赋值, 指针的指向在程序执行中可以改变
    • 指针变量的命名规则和其他变量的命名规则一样, 不能与现有变量同名
    • 若指针已声明指向某种类型数据的地址, 则不能用于存储其他类型数据的地址

    引用

    • 为对象起的另外一个名字, 引用即别名
    • 引用并非对象, 只是为已经存在的对象起的别名
    • 引用只能绑定在对象上, 不能与字面值或某个表达式的计算结果绑定在一起
    • 引用必须初始化, 所以使用引用之前不需要测试其有效性, 因此使用引用可能会比使用指针效率高.
    int value = 1024;
    int& ref_value = value;
    
    //错误, 引用必须初始化
    int& ref_value2;
    

    指针与引用

    • 引用对指针进行了简单的封装, 其底层仍然是指针

    • 获取引用地址时, 编译器会进行内部转换

      image-20200502182443969

    指针与数组

    • 数组, 存储在一块连续的内存空间中

    • 数组名就是这块连续内存空间的首地址

      image-20200502182627627

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        double score[] {11, 22, 33, 44, 55};
        double * ptr_score = score;
        
        // 40   4
        cout << sizeof(score) << '	' << sizeof(ptr_score) << endl;
    }
    

    指针的算术运算

    • 一个类型为T的指针的移动, 以sizeof(T)为移动单位

    image-20200502183052628

    小结

    • 数组名就是这块连续内存单元的首地址
      • int num[50]; num是数组名, 也是数组的首地址
      • num的值与&num[0]的值相同
      • 数组的第i+1个元素的地址可表示为 num+i 或者 &num[i+1]
      • 数组的第i+1个元素的值可表示为 num[i] 或者 *(num+i)
      • 指针变量可以指向数组元素, int* ptr_num = &num[4] 或者 int * ptr_num = num + 4.

    动态分配内存

    使用new分配内存

    • 指针的真正用武之地是在运行阶段分配未命名的内存以存储值
    • 在这种情况下, 只能通过指针来访问内存

    使用delete释放内存

    • 与new配对使用
    • 不要释放已经释放的内存
    • 不能释放声明变量分配的内存
    //在运行阶段为int值分配未命名的内存, 使用指针来访问这个值
    int* ptr_int = new int;
    
    //释放由new分配的内存
    delete ptr_int;
    
    //注意: 不要创建两个指向同一内存块的指针, 有可能误删两次
    int * ptr = new int;
    int * ptr1 = ptr;
    delete ptr;
    delete ptr1;
    

    动态分配数组

    • 使用new创建动态分配的数组, new运算符会返回第一个元素的地址

    • 使用delete[]释放内存, []表示释放整个数组

      int * ptr_int = new int;
      short * ptr_short = new short[500];
      delete ptr_int;
      delete [] ptr_short;
      
    • 注意:

      • 不要使用delete释放不是new分配的内存
      • 不要使用delete释放同一内存两次
      • 如果使用new[]为数组分配内存, 则对应delete[]释放内存
      • 对空指针使用delete是安全的
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int num[5];						//栈内存
        double* nums = new double[5];	//堆内存
        
        //  20    4
        cout << sizeof(num) << '	' << sizeof(nums) << endl;
    }
    

    程序的内存分配

    • 栈区
      • 由编译器自动分配释放, 一般存放函数的参数值, 局部变量的值
      • 操作方式类似数据结构中的栈, 先进后出
    • 堆区
      • 一般由程序员分配释放, 若程序不释放, 程序结束时可能会由操作系统回收
      • 注意, 与数据结构中的堆是两回事, 分配方式类似链表
    • 全局区(静态区)
      • 全局变量和静态变量存储在一起的
      • 程序结束后由系统释放
    • 文字常量去
      • 常量字符串就存放在这里, 程序结束由系统释放
    • 程序代码区
      • 存放函数体的二进制代码
    //栈区
    int num;
    
    //栈区
    char str[] = 'hello';
    
    //栈区
    char* ptr;
    
    //hello以及在常量去, ptr2在栈区
    char* ptr2 = "hello";
    
    //全局初始化区
    static inr num2 = 100;
    
    //分配的内存在堆区, 但是ptr本身在栈区
    ptr = new char[10];
    

    小结

    • 指针是一个变量, 存储另一个对象的内存地址

    • 指针的声明由基本类型, 星号*和变量名组成

    • 为指针赋值, 赋值运算符右侧必须是一个地址

      • 如果是普通变量需要在前面加取地址运算符&
      • 如果是另一个指针变量或者一个数组, 不需要加&
    • 运算符*用于返回指针指向地址的内存地址中存储的值

    • 使用指针可以访问一维数组和二维数组的元素

    //二维数组的创建和遍历
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        //使用指针创建二维数组
        int arrays[5][3] = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9},
            {10, 11, 12},
            {13, 14, 15},
        };
        int (*p)[3] = arrays;
    
        for(int i = 0; i < 5; i++){
            for(int j = 0; j < 3; j++){
    //            cout << *(*(p+i) + j) << ',';
                cout << *(*(p+i)+j) << ',';
            }
            cout << endl;
        }
    }
    
  • 相关阅读:
    【心情】codeforces涨分啦!
    redis
    rabbitmq
    lucene
    MongoDB
    负载均衡
    分布式存储
    Memcache
    websocket
    Remoting
  • 原文地址:https://www.cnblogs.com/KX-Lau/p/12857542.html
Copyright © 2011-2022 走看看