zoukankan      html  css  js  c++  java
  • 指针系列——认识指针

    综述

    指针在c++学习中一直是难点和重点,由于在项目中指针应用比较灵活,所以指针所引发的问题比较多,最近针对指针进行重点学习。有人说,掌握指针,也就掌握c语言的精髓。c++中当然也有指针,同时还包括继承、多态等等。

    内存四区

    没有内存,就没有指针,在理解指针的开始阶段,先重点讲解内存五区。
    这里写图片描述
    如上图所示:一般下理解内存分为栈、堆、常量区、代码区、全局区。
    栈:程序中局部变量、参数包括形参、数组、指针存放在栈中,编译器在函数调用结束后,自动释放,所以注意指针的指向。
    堆:程序员手工申请的内存(molloc,new),一般堆内存比栈内存大,在大数据处理中,可以利用堆,进行数据存储、计算。
    常量区:包括常量、字符串常量,指针指向此区,不能修改常量值
    代码区:存放函数体的二进制代码。
    全局区:全局变量和静态变量存储放在一块,在程序结束后自动释放。

    int a = 0;//a全局初始化区
    char * p ;//全局未初始化区
    int main()
    {
        int b;//因为在函数中,在栈中申请内存
        int inum = 0;//首先在常量区分配内存存放0,然后在栈中分配内存存放inum,最后将0赋值给inum。0 在程序结束后自动释放。
        int a[10];//在栈中分配了一个数组,有连续的内存空间放int型数据,内存为40字节
        char *p1;//在栈分配内存,指针是四个字节,此时没有向指针变量中赋值,也就是没有指向内存,此时操作这个指针会报错。
        char *p3 = "1234124";//首先常量区分配内存存放字符串常量,用指针*p3,指向这块内存空间,只能访问。如果用 *p3 = "23";编译会报错,常量区不可修改啊
        static int a1 = 0;//全局去(静态区)
        p1 = new char();    //通过了new和molloc 了在分配字节在堆中,当然指针在栈中。
    
        int *p4 = new int[10];//在堆中分配内存为40字节。
    }
    View Code

    栈和堆

    堆和栈在程序到底有什么不同,当然从表面上可以看到两者因为申请方式不一样,可以清晰知道两者的区别。那在内存中具体的不同有哪些。
    这里写图片描述
    1. 管理方式不同
    栈是编译器自动管理,堆需要我们手工创建,手工释放。在程序中,一般通过内存的指针进行释放,所以指向堆的指针指向千万不能变化。要有一个指针保存申请内存的首地址。

    1. 空间大小不同
      一般在32位操作系统下,栈的内存一般都是一定的空间的大小的,在vc6下面默认的空间大小是1M,而堆的大小可以达到4G空间,从这个角度上讲堆内存几乎没有限制。
    2. 碎片问题
      对于堆来讲,因为经常new/delete操作,造成内存空间不连续,造成大量的内存碎片,使程序效率低下。栈就没有这种问题。
    3. 生长方向
      堆是向上生长,栈向下生长。意味在程序中申请栈和堆的内存时,内存地址变化方向不一样。栈中变量申请越往后,地址越小。
    4. 分配方式
      堆是动态分配,没有静态分配的堆。栈有2中分配方式,静态分配就是常见的局部变量声明。动态分配有alloca分配,系统自动回收。
    5. 分配效率
      栈由机器系统提供的数据结构,计算机底层对栈支持:专门的寄存器存放栈的地址,有压栈出栈指令执行,决定栈的效率较高。堆是由c++函数库提供,机制比较复杂,如果没有足够内存空间(碎片过多),极有可能调用系统功能去增加程序数据段的内存空间,然后再返回。显然堆的效率比较低下。

    在程序中大量使用new/delete,容易造成大量内存碎片,效率低下。栈在程序中应用最广泛,就是函数调用也是通过栈完成,函数调用过程的参数,返回地址和局部变量采用栈的方式存放。

    指针理解

    没有内存,就没有指针,这句话充分说明指针的本质和作用。在系统中如果指针指向的内存空间没有内存,肯定报错,另一方面,利用指针去修改只读内存的内容,也是报错的。如果理解指针,必须从四个方面理解:1、指针类型;2、指针指向变量的类型;3、指针的值或者说指向内存空间地址;4、指针本身占据的内存区。

    • 指针类型和指针指向的类型

    首先指针是变量,是一种特殊的变量,它里面存储的数值被解释为内存里的一个地址,在指针变量加*后,就可以获取或操作指向内存空间的值。这样通过指针操作内存中数据便很方便。
    下面举例说明下

    int* ptr;//指针的类型是:int*
    
    char* ptr;//指针的类型是:char*
    
    int ** ptr;//指针的类型是:int**
    
    int (*ptr)[];//指针的类型是:(*)[]
    
    int *(*ptr)[];//指针的类型是:*(*)[]

    找出指针的类型很简单,关键是指针指向的类型。当你同过指针来访问指针所指向的内存区时,指针指向的类型决定了编译器吧内存里内容当做什么看待。从语法看看,只需要把指针声明语句中*,去掉,便得知。

    int (*ptr)[3]//指针指向类型为int()[3],意味着*(ptr+1)时,内存跳转大小是3*sizeofint),而不是sizeof(int)了,这是指向数组的指针。

    指针的类型和指针指向的类型很不一样,我们常常关心指针指向的类型。

    • 指针的值和指针指向的值

    指针的值是指指针本身存储的数值,由于在32位程序中,指针的值就是个32位整数,所以指针占据4个字节。我们说指针的值是XX,就是指针指向了以XX为首地址的一片内存区域。
    指针指向的值就是指向内存空间中的值,也可以是函数指针奥。

    指针常量和常量指针

    在C/C++中关键字const用来定义一个只读的变量或者对象,有如下优点
    (1)便于类型检查,如函数的函数 fun(const int a) a的值不允许变,这样便于保护实参。
    (2)功能类似与宏定义,方便参数的修改和调整。如 const int max = 100;
    (3)节省空间,如果再定义a = max,b=max。。。就不用在为max分配空间了,而用宏定义的话就一直进行宏替换并为变量分配空间
    (4)为函数重载提供参考

    首先一定要明白哪种定义方式是常量指针,哪种是指针常量,这里可以记住三句话加深记忆:

    • (指针)和 const(常量) 谁在前先读谁 ;*象征着地址,const象征着内容;谁在前面谁就不允许改变。
    int a =3;
    int b = 1;
    int c = 2;
    int const *p1 = &b;//const 在前,定义为常量指针
    int *const p2 = &c;//*在前,定义为指针常量 

    常量指针p1:指向的地址可以变,但内容不可以重新赋值,内容的改变只能通过修改地址指向后变换。

    p1 = &a是正确的,但 *p1 = a是错误的。
    指针常量p2:指向的地址不可以重新赋值,但内容可以改变,必须初始化,地址跟随一生。
    p2= &a是错误的,而*p2 = a 是正确的。

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    2018 eclipse安装反编译插件
    Buffer flip()方法
    区块链2
    Mist 转移默认区块存储位置方法
    区块链1
    如何在Ubuntu下安装”.deb“、”.bin“、”.tar.gz“、”.tar.bz2“格式的软件包!
    eclipse 性能调优之内存分配
    linux中搭建java开发环境
    在 Ubuntu 14.04 上安装 Ubuntu Tweak 0.8.8
    Ubuntu各个版本的介绍
  • 原文地址:https://www.cnblogs.com/polly333/p/4705670.html
Copyright © 2011-2022 走看看