指针

指针

为对象起了另外一个名字(引用即别名)

int int_value = 1024;

int& refValue = int_value; // refValue指向int_value,是int_value的一个别名

int& refValue2; // 错误:引用必须初始化

  • 注意:

    • 引用并非对象,只是为一个已经存在的对象起了一个别名

    • 引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定在一起

      • int &ref_value = 10; // 错误
        
    • 引用必须初始化,所以使用引用之前不需要测试其有效性,因此使用引用可能会比使用指针效率高。

  • 指向常量的引用是非法的

double& ref = 100; // 错误
const double& ref = 100;  // 表示一个常量的引用,所以我们也可以反推,没有const为变量,变量怎么能赋值呢。

指针和引用

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

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gEOgA3y7-1620553505413)(C:\Users\君莫笑\AppData\Roaming\Typora\typora-user-images\image-20210509153342118.png)]

指针和数组

  • 存储在一块连续的内存空间中
  • 数组名就是这块连续内存空间的首地址
int main(){
    double socre [] {11,22,33,44,55}
    double * prt_score = score; // 指向数组
    cout << prt_score[3] << endl; // 输出了 44 
    
    cout << sizeof(score) << '\t' << sizeof(prt_score) << endl;
    // 计算数据类型或对象的长度大小
    // 输出了 40   4
    // score数组为double类型数组,占8个字节,5个数组即40个字节大小
    // 指针是一个地址,他的大小一般为4个字节
}

指针运算

  • 指针的递增和递减(++、–)
int i;
double score[5]{98,87,65,43,76};
double * prt_score;
ptr_score = score;
for (i=0;i<5;i++){
    cout << *ptr_score << endl;
}

第一次取的地址为:
在这里插入图片描述

当++ 一次后,指针平移到下一个单位:

在这里插入图片描述

  • 注意:
    • 一个类型为T的指针的移动,以szieof(T)为移动单位
      • 当前的数组类型为double,所以移动一次8个字节

数组与指针小结

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

    • int num[50]; // num 是数组名,也可以理解成数组的首地址
      
    • num的值与&num[0] 的值是相同的

    • 数组到底 i+1 个元素可表示为:

      • 第 i + 1个元素的地址 : &num[i+1] 或 num + i + 1
      • 第 i + 1 个元素的值: num[i+1] 或 *(num+i+1)
    • 为指向数组的指针赋值

      • int * ptr_num = num; 或 int * prt_num = &num[0];
        
    • 指针变量可以指向数组元素

      • int * ptr_num = &num[4]; 或 int * ptr_num = num + 4;
        

内存中的栈区和堆区

其实前面有学,但是我基本忘光了。

下面的内存分类我从 蝶开三月 那里copy过来的。

**而C语言的内存模型分为5个区:栈区、堆区、静态区、常量区、代码区。**每个区存储的内容如下:

1、栈区:存放函数的参数值、局部变量等,由编译器自动分配和释放,通常在函数执行完后就释放了

其操作方式类似于数据结构中的栈。栈内存分配运算内置于CPU的指令集,效率很高,但是分配的内存量有限,比如iOS中栈区的大小是2M。

2、堆区:就是通过new、malloc、realloc分配的内存块,编译器不会负责它们的释放工作,需要用程序区释放。分配方式类似于数据结构中的链表。“内存泄漏”通常说的就是堆区。

3、静态区:全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后,由系统释放。

4、常量区:常量存储在这里,不允许修改。

5、代码区:顾名思义,存放代码。

动态分配内存

  • 使用new分配内存

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

    • 与new配对使用

    • 不要释放已经释放的内存

      • 注意

        • // 1.不要创建两个指向同一内存块的指针,有可能误删除两次
          int * ptr = new int;
          int * ptr1 = ptr;
          delete ptr; 
          delete ptr1;
          
    • 不能释放声明变量分配的内存

// 1. 在运行阶段为一个int值分配未命名的内存
// 2. 在使用指针来访问(指向)这个值(右 - > 左)
int * ptr_int = new int;

delete prt_int; // 释放由new 分配的内存

 //  创建和释放总是成对存在的
 p - 栈区    // 在堆区分配了一块int 类型空间 
 int * p = new int;  // 在这你让整型 p 指针 指向了在堆区新创建的int空间
 p++;        // 你在这里的++ 将指针位置移动了,而刚刚的分配的内存还在
			//  没有指针指向它了(没用到),你也没有删除,造成了内存泄露
  • 内存决策:

    • 编译时(包办婚姻)

      • int num[56];
        
    • 运行时

      • int* nums = new int[5];
        
    • cout << sizeof(num) << '\t' << sizeof(nums) << endl;
      
      // 输出的是  20   4
      //  szieo(num)是20(5*4)   sizeof(nums) 是 4 (1*4)
      // int的位数是32位,也就是4字节
      
      
      // num[5]的内存是在栈内存里的,
      // new int[5] 是在堆内存里的,而我们创建的指针也是存在栈内存中的
      // 而sizeof是取栈内存大小的
      
  • 使用new创建动态分配的数组

    • int * intArray = new int[10];

      • new运算符返回第一个元素的地址
    • 使用delete[] 释放内存

      • delete [] intArray;
        • [] 释放整个数组
    • int * ptr_int = new int;
      short * ptr_short = new short[500];
      delete ptr_int;
      delete [] prt_short;
      
  • 关于new和delete使用的规则:

    • 1.不要使用delete释放不是new分配的内存
      • 有时你释放的内存,由于没有其他东西来覆盖,那个值依然存放在那个内存。
    • 2.不要用delete 释放同一内存两次
    • 3.如果使用new[]为数组分配内存,则对应delete[]释放内存
    • 4.对空指针使用delete是安全的

补充:程序的内存分配

  • 栈区(stack)
    • 由编译器自动分配释放,一般存放函数的参数值,局部变量的值等
    • 操作方式类似数据结构中的栈–先进后出
  • 堆区(heap)
    • 一般由程序员分配释放,若程序不释放,程序结束时可能有操作系统回收
    • 注意:与数据结构的堆是两回事,分配方式类似链表
  • 全局区(静态区-static)
    • 全局变量和静态变量是储存在一起的
    • 程序结束后由系统释放
  • 文字常量区
    • 常量字符串就放在这里,程序结束由系统释放
  • 程序代码区
    • 存放函数体的二进制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值