C语言的内存管理分析 栈区 代码区 堆区 静态区 常量区

系统为了管理内存 把内存划分了几个区域

1>
栈区

栈区之中的数据在栈区之中以栈的形式进行存储.

栈区的特点:数据是先进后出,

放在栈区里面存放的是局部变量.(例如定义在函数内部的变量)

栈区之中的数据(局部变量)的作用范围过了之后,系统就会回收自动管理栈区的内存(分配内存
, 回收内存),不需要开发人员来手动管理

2>
堆区

高效的使用内存

这里的内存可以由程序员自己手动管理
高效的使用内存  例如:
申请内存 释放内存.优化内存 ARC

申请内存的函数 malloc()  memary alloc 
申请内存空间

void *mallc(size_t);

函数名:malloc

返回值: void *   (泛指针类型
可以轻松的转换为任意类型的指针)

返回一个指向新开辟的的存空间的首地址

类型是一个泛指针(可以根据接受者
动态的转换).

参数: size_t 
申请动态空间的字节数的大小. 即:你要开辟多大的空间.
例如开辟一个整形的变量的存储空间(在堆区之中)  malloc(4);

int *p = malloc(4);

释放内存的函数 free(p);// p 是你 刚刚使用 开辟空间函数返回的内存空间首地址的的指针接受者

最后还要将 p = NULL; 否则会出现野指针错误!

void *calloc(unsigned n,unsigned size);(10 * 4)

申请 count * size
个字节  count 是个数 size
是每一个占用的字节数

并且将申请到的内存之前的残留数据清空,效率比malloc
要低,但是更安全.

例如 :开辟十个整型数据的空间

int *p = calloc(10,sizeof(int));

void * realloc(<#void *#>, <#size_t#>); 
重新分配内存空间.

realloc(p, size);

从指针p的位置
重新申请size个字节.
返回一个 泛类型的指针.

从p的位置开始申请,如果后面有size
个字节可以使用,就直接申请;如果没有,就去内存之中找一块连续的size字节,找到就直接申请,并且在申请之前,释放掉以前申请到的内存.
返回新的指针.

memset(void *,int ,size_t);

memset(p,c,n);

从指针的p的位置开始,初始化n个字节的内容并且把内容改为 C;

//memccpy(<#void *#>, <#const void *#>, <#int#>, <#size_t#>)

memccpy(dest, source, <#int#>, <#size_t#>)

memcpy(dest, source, n);

从指针source
的位置开始,向指针dest的位置,拷贝n个字节的内容.

3>
静态区(全局区)

静态区存放的是:
全局变量(定义在函数外部的变量
例如在主函数上面 定义的变量)
和 静态变量

static
类型的变量有什么特点:(只初始化一次(初始化是 在定义的时候辅助),不初始化的话,默认为零.)

静态区内存是由系统管理的.

一旦静态区的内存被分配,
静态区的内存直到程序全部结束之后才会被释放

4>
常量区

常量区存放:
常量(程序在运行的期间不能够被改变的量
例如: 10 ‘a‘ 1.12 "ios", 数组的名字)

常量区的内容是只能读的
不能被修改的的.

区别一下下面的代码:

char *p = "kpkoj";

等价于 char *p; p = "kpkoj";

此时char类型的指针p存放的是常量字符串的首地址 ("kpkoj"(存放在常量区)的首地址)

所以此时p指向的内容不能够被修改,只能被读取 
即*p的值只能被读取,不能被修改.但是可以重新的将指针变量p指向新得地址.

例如在上面这个的操作的基础之上
在将p赋上新的值 p = "ddvdd";(拷贝的是地址此时又指向了一个新的常量的首地址)

这个情况:  char str[] = "iOS";

这个是字符数组
是将常量字符串"iOS"的内容拷贝到栈区的字符数组之中 ,所以
可以修改数组内的内容.例如: str[0]= ‘d‘;

但是str(数组名)
是一个常量的地址已经初始化,就不能被重定向(更改他的指向),所以只能通过下标或者什么的对其数组中的某个元素进行修改,区别上面的的指针情况.

常量的内存也是由系统管理的.

5>
代码区

内存还是由系统控制的

代码区的存放 :程序中的函数编译后cpu指令

代码区的地址:函数的地址,程序的入口地址.程序的名字.

栈区内存地址编号由高到低(栈区 ->
代码区).

//    int *h = malloc(4);//开辟一个堆区的地址
大小为 4

//    *h = 1024;//向堆区内存空间之中写入数据 1024

//

//    printf("堆区的地址%p,  %d\n" , h , *h);

//    //在堆区之中
存入 "iphone 6s";

//

//    char *ch = malloc(sizeof("iphone 6s"));

////    ch = "iphone 6s";

////    ch = "dddd";//这样只是将指针重新指向.而,新开辟的内存空间已经没有指向,造成内存没有指向 
内存泄露

//    strcpy(ch , "iphone 6s");//将常量区的内容拷贝到指向的刚刚开辟的内存区域!.

////    ch[0] = ‘1‘;//这里可以被修改
因为他指向的内存区域是栈区 不是 
常量区域

////    ch = "iphone 6s";//指向常量区的地址.

////    ch[0] = ‘1‘;//这样就不能修改 ch[0]的内容
因为 ch指向的是一块常量地址,不能被修改.
上面已经有详细的阐述了.

//    printf("%s \n" , ch);

//

//

//

//    strcpy(ch, ch + 2);

//    printf("%s\n",ch);

//

//

//    int *p3 = malloc(4);

//    printf("%p\n" , p3);//申请内存的堆区地址.

//    printf("%p\n" , &p3);//指针变量的栈区的地址

//

//    //同样的
开辟内存之后一定要记得释放 否则容易造成
内存泄露

//    //内存泄露:
内存一直被占用 得不到释放.

//    free(p3);//内存释放函数 free(开辟的内存的首地址) 
只是将内存标记为可用而没有将里面的内容抹掉

//    p3 = NULL;//记得安全的做法
将指针指向空 NULL
要不是就是野指针了.错误了

//    // 使用动态内存分配的知识,在内存存放10个整数,随机数范围[2 , 399];

//

//    int *open = malloc(sizeof(int) * 10);//分配一段连续的空间.

//    int *lh = open;

//    for (int i = 0; i < 10; i++)

//    {

//    *(open + i) = arc4random() % (399 - 2 + 1) + 2;//向下偏移就可以了,因为下面的也是开辟的动态内存空间
open++;

//        open[i] = arc4random() % (399 - 2 + 1) + 2;

//

//        printf("%d  ",*(open + i));

//    }

//    printf("\n");

//

//    BOOL flags = YES;

//    int temp;

//    for (int o = 0; o < 9 && flags; o++)

//    {

//        flags = NO;

//        for (int i = 0; i < 9 - o; i++)

//        {

//            if (*(open + i) > *(open + 1 + i) )

//            {

//                temp = *(open + i);

//                *(open + i) = *(open + 1 + i );

//                *(open + i + 1) = temp;

//                flags = YES;

//            }

//        }

//    }

//    for (int i = 0; i < 10; i++)

//    {

//        printf("%d  " , open[i]);

//    }

//    printf("\n");

//    free(open);

//    open = NULL;

//    const int b = 0;

//    char *p = "iOS"; //定义了一个栈区的指针变量
存放着
常量区的地址.

////    p[0] = ‘f‘;

////    *p = ‘m‘;

//    p = "ddd";

//    puts(p);

//    printf("常量去的地址%p \n",p);

//    int a = 10;

//    static int k = 20;//静态变量.

//    printf("静态变量的地址  p   %p\n" , &k);

//    printf("静态区的地址:%p\n" , &b);

//    printf("栈区的地址:%p\n" , &a);

//    printf("代码区的地址:%p\n" , main);

//    for(int i = 0 ; i < 100 ; i++ )

//    {

////        int n = i;

////        static int n = 1; //只能被
定义和初始化一次.  存放在静态区  
没有赋初值. 而且初始化的时候一定要
赋一个常量 不能赋值一个
变量.

////        printf("%d \n",n);

//    }

//    char ch[] = "jkjl3jo342pook25l414fe4op0kfe1";

//    int i , sum;

//    i = sum = 0;

//    while (ch[i] != ‘\0‘)

//    {

//        if (ch[i] >= ‘0‘ && ch[i] <= ‘9‘)

//        {

//            sum++;

//        }

//        i++;

//    }

//    printf("%d\n\n" , sum);

//    //数组定义的时候,元素的个数必须是确定的值 
不能出现变量的不确定

//    char *p = malloc(sum + 1);

//    i = sum = 0;

//    while (ch[i] != ‘\0‘)

//    {

//        if (ch[i] >= ‘0‘ && ch[i] <= ‘9‘)

//        {

//            *(p + sum) = ch[i];

//            sum++;

//        }

//        i++;

//    }

//    p[sum] = ‘\0‘;

//    printf("%s \n" , p);

//    free(p);

//    p = NULL;

//    memccpy(<#void *#>, <#const void *#>, <#int#>, <#size_t#>)

//    memcpy(<#void *#>, <#const void *#>, <#size_t#>)

//    char *p = malloc(4);

//    memset(p, 66, 2);

//    printf("%s \n",p);

//    char str1[] = "sdfsafdaf";

//    char str2[] = "564545121";

//    memcpy(str1, str2, 3);

//    printf("%s \n" ,str1);

//    memcmp(p1, p2, n);

//    内存的比较.
比较p1和p2
指向的内存之中的内容是否相等 ,比较n个字节的长度
相同的返回0,不同的返回差值.

//    int *p1 = malloc(4);

//    *p1 = 8 ;

//    int *p2 = malloc(4);

//    *p2 = 3;

//    int result = memcmp(p1, p2, 1);

//    printf("%d \n",result);

int *p1 , *p2;

p1 = malloc(3 * sizeof(int));

p2 = calloc(3 , sizeof(int));

memset(p1, 0, 3*sizeof(int));

for (int i = 0; i < 3; i++)

{

*(p1 + i) = arc4random()%(3 - 1 + 1) + 1;

*(p2 + i) = arc4random()%(3 - 1 + 1) + 1;

printf("%d  %d",*(p1 + i),*(p2 + i));

//        *(p1 + i) = 1;

//        *(p2 + i) = 1;

printf("\n");

}

if (memcmp(p1, p2, 16)==0)

{

printf("good\n");

}

else

printf("Failed\n");

free(p1);

free(p2);

p1 = p2 = NULL;

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

时间: 2024-10-21 05:03:12

C语言的内存管理分析 栈区 代码区 堆区 静态区 常量区的相关文章

Swift语言的内存管理哦,还等什么?点进来!

//*********Swift语言的内存管理基础************* //内存管理:针对的是实例的内存占用的管理(放在堆里面) //实例:1,由class类型构建的实例 2.闭包对象 /* 内存管理技术:ARC:Automatic Reference Count 自动:由于语言本身帮我们管理内存,不需要我们手机去管理 比如在c中就调用dealloc() 引用:let p = Person() p就是对Person()这个对象的一个引用 计数: let p = Person()   +1

cocos2d-x与ios内存管理分析(在游戏中减少内存压力)

Cocos2d-x与ios内存管理分析(在游戏中减少内存压力) 猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网--Cocos2Dev.com,谢谢! 年 原文地址: http://www.cocos2dev.com/?p=281 注:自己以前也写过Cocos2d-x如何优化内存的使用,以及内存不足的情况下怎么处理游戏.今天在微博中看到有朋友介绍了下内存,挺详细的.不知道是谁写的,我记录下. 一,iOS与图片内存 在iOS上,图片会被自动缩放到2的N次方大小.比如一张1024*102

C语言动态内存管理

1-概述 动态存储管理的基本问题是:系统如何按请求分配内存,如何回收内存再利用.提出请求的用户可能是系统的一个作业,也可能是程序中的一个变量. 空闲块 未曾分配的地址连续的内存区称为"空闲块". 占用块 已分配给用户使用的地址连续的内存区称为"占用块". 系统刚刚启动时,整个内存可看做一个大的"空闲块",随着用户请求的进入,系统依次分配相应的内存. 在系统运行过程中,内存被分为两大部分:低地址区(若干占用块)和高地址区(空闲块). 经过一段时间后

小白学开发(iOS)OC_ set方法的内存管理分析(2015-08-04)

// //  main.m //  set方法的内存管理分析 // //  Created by admin on 15/8/5. //  Copyright (c) 2015年 admin. All rights reserved. // #import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { @autoreleasepool { //p 

JVM内存管理------JAVA语言的内存管理概述

引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓狂的内存溢出和泄露的问题. 可怕的事情还不只如此,有些使用其它语言开发的程序员,给JAVA程序员扣上了一个"不懂内存"的帽子,这着实有点让人难以接受.毕竟JAVA当中没有malloc和delete.没有析构函数.没有指针,刚开始接触JAVA的程序员们又怎么可能接触内存这一部分呢,更何况有不

多个对象的内存管理分析

// //  main.m //  03-多个对象的内存管理分析 // //  Created by apple on 14-3-17. // // #import <Foundation/Foundation.h> //人拥有一辆汽车 #import "Person.h" //1.野指针问题 //2.内存泄漏问题 int main(int argc, const char * argv[]) { @autoreleasepool { // 1 Person * p = [

内存管理:栈区,堆区,全局区,文字常量区,程序代码区

一.预备知识-程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)- 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其 操作方式类似于数据结构中的栈. 2.堆区(heap) - 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回 收 .注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵. 3.全局区(静态区)(static)-,全局变量和静态变量的存储是放在一块的,初始化的 全局变量和静态变量在一块区域, 未初始化的全局变

Android内存管理分析

大部分因为工作任务繁重,一般我们很少关心内存的事,只知道先把任务完成.只有真正到了发现UI卡顿 或者APP实在跑不下去了(一点一卡),才会考虑到内存优化.或者你所在的大公司比较关心手机运行流利程度,也需要对内存进行管理. 1.内存管理的基础知识 因为安卓的顶层也是 Java来实现的,作为客户顿的程序员应该懂得如何去管理内存. 又因为Java不像C语言可以执行free去主动释放内存,而是提供了一套Java的垃圾处理器.但是该处理器并不能时刻盯着内存,在内存不需要的时候直接清理(程序员比较方便,但是

FreeRTOS高级篇7---FreeRTOS内存管理分析

内存管理对应用程序和操作系统来说都非常重要.现在很多的程序漏洞和运行崩溃都和内存分配使用错误有关.        FreeRTOS操作系统将内核与内存管理分开实现,操作系统内核仅规定了必要的内存管理函数原型,而不关心这些内存管理函数是如何实现的.这样做大有好处,可以增加系统的灵活性:不同的应用场合可以使用不同的内存分配实现,选择对自己更有利的内存管理策略.比如对于安全型的嵌入式系统,通常不允许动态内存分配,那么可以采用非常简单的内存管理策略,一经申请的内存,甚至不允许被释放.在满足设计要求的前提