《C语言笔记:三种内存来源》

一,三种内存来源(程序可以操控的内存空间)

  1,在一个C程序中,能够获取的内存就是三种情况:栈(stack)、堆(heap)、数据区(.data)。

二,栈的详解

  1,栈的内存空间,程序运行时自动分配&自动回收,栈是自动管理的,程序员不需要手工干预。

  2,栈内存在程序中就是那一块大小有限的内存空间,程序反复使用这一块空间。不断的在这一块空间中自动分配&“自动回收”。

  3,由于栈内存反复使用,并且每次使用后程序不会去清理之间使用的空间,因此分配到时保留原来的值,是一块脏内存。所以在定义一个分布在栈上的局部变量时,一定要先初始化,不然其值就是随机的。

  4,函数不能返回一个栈变量的指针,因为这个空间时临时的。

  5,栈会溢出,因为操作系统事先给定了栈的大小,如果在函数中无穷尽的分配栈内存总能用完。

三,堆内存的详解

  1,操作系统堆管理器管理堆内存,堆管理器是操作系统的一个模块,堆管理内存分配灵活,按需分配。

  2,程序手动申请和释放,需要程序员用malloc申请,free释放。

  3,堆内存也是反复使用的,而且使用者用完释放前不会清除,因此也是脏的。

  4,堆内存只在malloc和free之间属于一个进程,可以访问,在malloc之前和free之后都不能访问,否则会出现不可与预料的错误。

四,堆内存使用    void *malloc(size_t size);  void free(void *ptr);

  1,malloc返回的是一个void * 类型的指针,实质上malloc返回的时堆管理器分配的本次申请的那段内存空间的首地址(返回的值其实是一个数字,这个数字表示一个内存地址)。

  2,为什么要使用void *类型呢?

    主要原因是:malloc帮我们分配内存时只是分配了内存空间,至于这段空间被用来存储什么类型的元素malloc是不关心的,由程序自己决定。

  3,什么是void *类型?

    void 类型不表示没有类型,而表示万能类型。void的意思是这个数据的类型当前是不确定的,在需要的时候可以再去指定它的具体类型。void *类型是一个指针类型,这个指针本身占四个字节,但是指针指向的类型是不确定的,换句话说,这个指针在需要的时候可以被强制转化成任何一种确定类型的指针,也就是说这个指针可以指向任何类型的变量。

  4,malloc的返回值:成功申请空间后返回这个内存空间的指针,申请失败时返回NULL。所以malloc获取的内存使用前一定要先检验是否为NULL。

  5,malloc申请的内存用完后要free释放。free会告诉堆管理器这段内存我用完了你可以回收了,堆管理器回收了这段内存后这段内存当前进程就不应该再使用了。因为释放后堆管理器就可能把这段内存分配给其他进程。

  6,在调用free释放这段内存前,指向这段内存的指针一定不能丢(也就是不能给p赋其他值)。因为一旦p丢失,这段malloc来的内存就永远的丢失了,直到当前程序结束时,操作系统才能回收这段内存。

五,malloc的一些细节

  1,malloc(0);返回的时NULL还是一个有效的指针?

    实际分配了32字节的一段内存,并且返回了这段内存的地址。这个答案是不确定的,因为C语言并没有明确规定malloc(0)的具体表现,由各个平台malloc函数库的实现者来定义。

  2,malloc(4);gcc中malloc默认最小是以32字节为单位分配的。如果malloc小于32B大小时,会返回一个32字节大小的内存。malloc实现时没有实现任意自己的分配,而是允许一些大小的块内存的分配。也就是以某个字节的块内存为单位分配。

  64位平台

#include<stdio.h>
#include<stdlib.h>


#pragma pack(4)
int main(void)
{
    #if 0
    char *p = malloc(0);
    char *a = malloc(1);
    if(NULL == p)
    {
        printf(" malloc error \n");
    }

    printf("  p = %p \n",p);       //p = 0xc73010
    printf("  a = %p \n",a);       //a = 0xc73030

    printf("  p size = %d \n",a-p);    //32
    #else
    char *p = malloc(4);
    char *a = malloc(1);
    if(NULL == p)
    {
        printf(" malloc error \n");
    }

    printf("  p = %p \n",p);       //p = 0x2497010
    printf("  a = %p \n",a);       //a = 0x2497030

    printf("  p size = %d \n",a-p);  //32
    #endif


}

#pragma pack()

六,代码段、数据段、bss段

  1,编译器在编译程序的时候,将程序中所有的元素分成了一些组成部分,各部分构成一个段,所以说段是可执行程序的组成部分。

  2,代码段:代码段就是程序中的可执行部分,就是函数堆叠组成的,里面是一个个的函数定义。char *p = "linux;定义字符串时,字符串”linux“实际上被分配在代码段。const型常量,有时也是被放在代码段。

  3,数据段(也被称为数据区、静态数据区、静态区):数据段就是程序中的数据。显示初始化为非零的 全局变量和static修饰的静态局部变量放在数据段。

  4,.bss段:未初始化或显示初始化为零的 全局变量和静态局部变量放在.bss段。

七,const常量

  1,C语言种使用const关键字来定义常量,常量就是不能被改变的量。

  2,const的实方法至少有两种:

    第一种,就是编译时将const修饰的变量放在代码段,以实现不能修改(常见于各种单片机的编译器)。

    第二种,就是由编译器来检查以确保const型的常量不能被修改,实际上const型常量还是和普通变量一样放在数据段中(gcc中就是这样实现的),这个时候const 常量实际上是可以被修改掉的,只要骗过编译器的类型检查。

八,总结

  1,相同点:三种获取内存的方法,都可以给程序提供内存,都可以用来定义变量给程序用。

  2,不同点:栈内存对应的是C种普通的局部变量(别的变量还用不了栈,而且栈是自动的,由编译器和运行时的环境共同来提供服务,程序员无法手工控制),堆内存完全是独立于程序存在和管理的(通过API由堆管理器管理),程序需要内存时可以手工申请malloc,使用完成后要free;数据段对于程序来说对应程序中的全局变量和静态局部变量。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程界的小学生、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值