内存布局和堆的分配释放

1.代码区

代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也叫代码段,这块内存是不可以在运行期间修改的。
代码区中所有的内容在程序加载到内存的时候就确定了,运行期间不可以修改,只可以执行。

2.静态区

静态区是程序加载到内存的时候就确定了,程序退出的时候从内存消失。所有的全局变量和静态变量在程序运行期间都占用内存。
所有的全局变量以及程序中的静态变量和常量(const)都存储到静态区

3.栈区

stack是一种先进后出的内存结构,所有的自动变量,函数的形参,函数的返回值都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出。
不同的系统栈的大小是不一样的,即使相同的系统,栈的大小也是不一样的,windows程序在编译的时候就可以指定栈的大小,linux栈的大小是可以通过环境变量设置的。

3.1静态区、代码区、栈区

静态区和代码区的大小受到物理内存大小的限制
栈区的大小一般很小,单位一般是k,所以栈中不能有太多变量


内存说明.png

4.堆区

堆heap和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。
堆是一个大容器,它的容量要远远大于栈,但是在C语言中,堆内存空间的申请和释放需要手动通过代码来完成。

1.png
2.png

5.堆的分配和释放

1.malloc

void * malloc(size_t _Size);

malloc函数在堆中分配参数_Size指定大小的内存,单位:字节,函数返回void*指针

2.free

void free(void *p);

free负责在堆中释放malloc分配的内存。参数p为malloc返回的堆中的内存地址

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

int main()
{
    char *p;
    p = malloc(100);//在堆中分配了一个100字节的内存
    //p指向了堆的内存首地址
    //变量p在哪里?p在栈里面,但p的值是堆地址编号
   free(p);
//为什么要写free?因为p可以自动销毁,但是malloc产生的堆内存并不会自动销毁,所以要free函数清理


  //在堆中分配一个int
    int *p1 = (int*)malloc(sizeof(int));
   *p1 = 0;//在堆中的int的值设置为0
    printf("%d\n",*p1);
    
    free(p1);
    p1 = NULL;//避免野指针
  //在堆中分配一个int[10]
   int *p2 = malloc(sizeof(int) * 10);
   memset(p2,0,sizeof(int)*10);
   for(int i = 0; i<10;i++{
      printf("%d\n",p2[i]);
   }
   free(p2);
    p2 = NULL;//避免野指针
   /*
    *堆内存有一个最小单位,叫内存页
    *一个内存页的大小也不是固定的,在测试的机器里面是4k为一个单位变化的
    *当我们要堆里面一个内存的时候,总是4k为一个单位
    */

   return 0;
}

内存分配例子1

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

char *test()
{
    char *p = malloc(100);//在堆中分配了100个char,假设堆地址为0x123
    strcpy(p,"hello");
    //free(p);//p就成了野指针
    return p;

char *test1()//错误的代码
{
       (auto) char p[] = "hello";
       return p;
}

char *test2()
{//不要通过函数的返回值返回一个自动变量的地址(返回堆地址可以!)
    (auto) char a = 'a';//栈!
     return &a;
}

char *test3()//正确
{
    static char a = 'a';
    return &a;//返回一个静态变量的地址是有效的,因为静态变量的内存一直存在
}

const char *test4()//和const没有关系,都是栈!
{
     char a[] = "hello world";
     return a;
}

const char *test5()//正确的,参数const表示常量,常量在静态区,静态区可读写,可以返回!
{
     const char *s = "hello world";
     return s;
}

const char *test6()
{
      return "abc";//和test5道理一样
}

int main()
{
    char *p2 = test2();//返回了野指针!
    *p2 = 'b';

    char *str1 = test1();//test1这个函数调用完成后,test1里面的自动变量地址都已经从栈中弹出了!
   //所以,str1是一个无效的地址
    
    char *str = test();
     str[0] = 'a';//str指向的不是代码区(代码区只读),而是指向的堆内存,所以可以改!
     printf("%s\n",str);
     free(str);
    return 0;
    

}

内存分配例子2

void test2(char *s)//错误的,形参的值改变了,但实参没有改变,见图1!
{//s是栈区的
    s = malloc(100);
    strcpy(s,"hello");
   //由于s在栈里面,test2这个函数执行完后,s就从栈中弹出了!
   //结果是malloc分配的内存再也没有机会free了!
}

void test3(char **s)//正确,见图2
{
    *s = malloc(100);
    strcpy(*s,"hello");
}

char *test4()//这里没问题
{
     char *s = malloc(100);
     strcpy(s,"hello");
     return s;
}

int main()
{

   char *p = NULL;
   test3(&p);
   printf("%s\n",p);
   free(p);
   return 0;
  /*
  总结:如果通过一个函数内部给一个
实参指针分配堆内存,一定是二级指针
*/



    char *p = NULL;
    test2(p);//p没有分配到堆的内存
    printf("%p\n",p);//p还是空指针
    return 0;

}
gcc调试
gcc -o a a.c -g
a
gdb a
where
形参实参分析1.png

p是实参,s是形参,p的值会给到s,所以s的值是NULL
此时创建了堆内存空间,地址是0x123,那么s的值就是0x123
往堆内保存"hello",也没有出错。
但是p地址存值没有变化!!!!
形参的值改变了,但是实参没有改变

形参实参分析2.png

用二级指针 **s 的话(如test3(&p))
假设变量的地址是0x100,那么传到**s中,s的值是0x100
malloc创建堆内存,地址是0x123
*s的地址就是0x123,*s是什么,是0x100里面的值,所以*p=0x123

内存分配例子3

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

const char *test1()//错误的
{
    char a[] = "hello";
    return a;//a的值是一个自动变量的地址
}
const char *test2()//对的
{
    char *a = "hello";
    return a;//a的值是一个常量的地址
}
const char *test3()//对的
{
    static char a[] = "hello";
    return a;//a是静态变量
}
const char *test4()//对的
{
    char a[] = malloc(100);
    strcpy(a,"hello");
    return a;
}

int main()
{
   return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容