zoukankan      html  css  js  c++  java
  • 关于内存及其相关

    C程序的存储空间布局
    1.正文段
    也叫代码段,这个不多赘述,就是用来存放 程序执行代码 的一块内存区域。这部分区域的大小在程序运行前就已经确定
    2.初始化数据段
    c程序中出现在函数之外的定义
    int max =99;
    3.非初始化数据段(bss段)
    c程序中出现在函数之外的声明
    int arr[10]; int *p ; 内核将此段中的数据初始化为0或者空指针
    2、3统一为全局变量区(静态区),函数内的static声明的变量也放在此区中
    4.栈
    自动变量及每次函数调用时保存的信息都放在此段,值传递这种会将返回值存放在寄存器中,使用时再传递下去,而指针传递这种需要注意栈区指针空间的释放,栈的大小以M为单位
    5.堆
    动态存储分配,区域位于非初始化数据段和栈之间,分配时注意手动释放,并分配足够空间, 堆的大小理论上大概等于进程虚拟空间大小-内核虚拟内存大小,以G为单位
     
    6.进程虚拟地址空间
    我们知道,在IA-32体系结构中,任何一个进程都能够访问4GB的内存空间;在这4GB内存空间中,高1GB是内核的空间,而低3GB的内存空间(我们成为用户虚拟内存空间)中,也需要通过一定的布局来进行管理。用户虚拟内存空间至少需要分为三个部分:堆空间、栈空间以及MMAP空间,MMAP空间主要是将文件映射到进程的虚拟内存空间时,对应虚拟内存空间的位置。注意这里指的“文件”是Linux中宽泛概念的文件,包括块设备(硬盘等)上的文件、设备文件、虚拟文件系统的文件等等。关于内存映射和页管理,这个写到比较详细,https://www.cnblogs.com/xelatex/p/3491305.html
    7.关于数据长度的api
    strlen能返回字符串的长度是因为它认为到''就是结束的地方
    如下的字符型指针
    char*p1="hello world"; 若要输出字符串
    printf("%s",*p1); 这种是错误的,因为“%s”的格式化输出与strlen结束的方式相同,都是寻找指
    针内容的“”,我们要这样输出,只能如下这样输出一个字符
    printf("%c",*p1); 得到h
    或者
    printf("%s",p1); 得到字符串 hello world
    sizeof和内存无关,只根据数据类型来判断,而数据类型的长度和操作系统有关,通过size可以使
    得分配的空间长度刚好满足存放的要求,也不浪费空间
    unsigned int my_buf[1024 * 1024];
    memset(my_buf, 0, sizeof(my_buf));
    它是对较大的结构体数组进行清零操作的一种最快方法,而我们只需要对my_buf起始地址的后
    sizeof(my_buf)个字节清零,包含在<string.h>c头文件中的很多接口memcpy、strncpy等均会
    用到sizeof()
     
    8.关于指针
    void main()
    {
    int a = 10;
    int b = 11;
    int c =12;
    int* p = &a;
    int*p1 =&b;
    int*p2 = &c;
    int** (pp) = &p;
    int** (pp1) = &p1;
    int** (pp2) = &p2;
    printf("pp:%p,p:%p,a:%d ",pp,p,*(*pp));
    printf("pp1:%p,p1:%p,b:%d ",pp1,p1,*(*pp1));
    printf("pp2:%p,p2:%p,c:%d ",pp2,p2,*(*pp2));
    cin.get();
    }
    想象每一块内存我们都进行了编号,这个编号就是地址。指针实际也是一块内存存储的变量,内存内放的变量是地址,地址指向另一块内存编号,指向的内存中放在我们定义的数据,指针的4个字节存放在特定的内存区域,上述程序可以看到其指针的地址(内存编号)就跟在真正存储数据内存的后面。
     
    9.值传递与指针引用传递
    值传递 传进函数的值不能被修改而导致外部变化
    指针传递 指针内容可被修改,传入的是地址
    引用传递 传入的形参通过间接寻址实际对应外部的变量地址,不产生临时拷贝,所有引用传递实际是一种效率更高的传值方式
    egg2:
    void defineNed(int * p)
    {
    p +=1;
    printf("指针传递p1:%p : %d ",p,*p);
    }
    void defineFunc(int & p)
    {
    p +=1 ;
    printf("引用传递p2:%p :%d ",&p,p);
    }
    void main()
    {
    int a = 1;
    printf("a:%p ",&a);
    int & p2 = a;
    int * p1 = &a;
    printf("before p2:%p:%d ",&p2,p2);
    defineFunc(p2);
    printf("after p2:%p:%d ",&p2,p2);
    printf("before p1:%p:%d ",p1,*p1);
    defineNed(p1);
    printf("after p1:%p:%d ",p1,*p1);
    cin.get();
    }
    运行后
     
    传入的指针地址在返回后地址并未发生变化,和引用一样只能操控地址内空间的内容,而不能改变主函数传入实参的地址。
    C++引用产生的意义和指针类似,实际还是为了解决某些大型数据值传递带来的数据或大的对象拷贝副本,导致效率低下的问题,而指针存在需要判空和一些其它不太好用的地方,而引用在运算符重载等场景时又使用时存在一些便利,所以引入引用,渐渐可以替代一些使用指针的地方。
    比较想写下这个,因为困扰了我很久,除了copy的部分,其余的可能有问题,因为都是我瞎想的,每个字都是一段工作之余又没下班闲的蛋疼的岁月。
  • 相关阅读:
    ES6-->ECMAScript 6.0 新增方法,一些基本语法
    初识 Nodejs (了解Nodejs)
    Vue框架初识
    python语法入门之流程控制
    python中基本运算符
    格式化输出
    基本数据类型
    变量,解释器,垃圾回收机制,小整数池总结
    编程语言发展史
    计算机基础
  • 原文地址:https://www.cnblogs.com/doulcl/p/9817427.html
Copyright © 2011-2022 走看看