动态内存分配, C语言,动态内存分配,栈区,堆区,静态区,常量区,代码区

动态内存分配

系统为了有效地管理内存,把内存划分为:

1.栈区

2.堆区

3.静态区(全局区)

4.常量区

5.代码区

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

1.栈区

栈区的数据以栈的形势存储

,先进后出

栈区存放的数据:局部变量(定义在函数内部的变量)

栈区的内存油系统自动管理的(分配内存,回收内存),不需要开发人员管理

栈区只有8MB,容易出现栈溢出

stackoverflow网站

栈区的内存,函数结束时,被收回

int a = 10;//栈区分配4个字节 printf("栈区地址: %p\n", &a);

2.堆区

由开发人员手动管理(申请内存,释放内存)

堆区空间比较大

申请内存函数

void*malloc(<#size_t#>)

返回值类型:void*,空指针类型(泛指针类型),可以转化成任意的指针类型

函数名: malloc

参数: size_t,unsignedlong,申请的字节数

 //从堆区申请4个字节的内存, 并返回首地址
    int *p1 = malloc(4);
    //向堆区存入数据1024
    *p1 = 1024;
    printf("%d\n", *p1);
    printf("堆区地址: %p\n", p1);
    
    //在堆区存入"iPhone 6s"
    char *p2 = malloc(10);
    strcpy(p2, "iPhone 6s");
    printf("%s\n", p2);
    printf("堆区地址: %p\n", p2);
    
    
    *p2 = 68;
    printf("%s\n", p2);
    
    
    p2[3] = '\0';
    printf("%s\n", p2);

    strcpy(p2 + 2, "abcd");//字符串最后一个是'\0', 会一起拷贝进去, 字符串结束
    printf("%s\n", p2);
    
    strcpy(p2, p2 + 2);
    printf("%s\n", p2);
    printf("%c\n", p2[5]);

内存泄露:内存一直被占用,而得不到释放

内存释放的函数

voidfree(<#void *#>)

int *p3 = malloc(4);//定义一个栈区指针变量, 存放栈区的首地址
    *p3 = 123;//把常量区的数据123, 拷贝到堆区
    free(p3);//把堆区的空间, 标记释放
    p3 = NULL;//因为指针p3存放有堆区的地址, 还可以通过地址访问堆区, 为了安全起见, 把指针p3置空
    
    //使用动态内存分配的知识, 在内存中存10个整数, 随机赋值[2, 10]
    int *p4 = malloc(sizeof(int) * 10);
    for (int i = 0; i < 10; i++) {
        //1
        *(p4 + i) = arc4random() % 9 + 2;
        printf("%d ", *(p4 + i));
        //2
//         p4[i] = arc4random() % 9 + 2;
//         printf("%d ", p4[i]);
        //3.
//          *p4 = arc4random() % 9 + 2;
//          p4++;
//          printf("%d ", *p4);

    }
    printf("\n");
    //冒泡排序
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9 - i; j++) {
            if (p4[j] > p4[j + 1]) {
                int temp = p4[j];
                p4[j] = p4[j + 1];
                p4[j + 1] = temp;
            }
        }
    }
    
    for (int i = 0; i < 10; i++) {
        printf("%d ", p4[i]);
    }
    free(p4);
    p4 = NULL;
    printf("\n");

3.静态区(全局区)

存放数据:全局变量(定义在函数外部的变量)静态变量(static修饰的变量)

静态区的内存由系统控制

静态区的内存,一旦分配,就一直占用,直到程序结束

#import <Foundation/Foundation.h>
int d = 50;
int main(int argc, const char * argv[]) {
 printf("静态区地址: %p\n", &d);
    
    static int e = 70;//静态变量
    //a.存在静态区内
    printf("静态区地址: %p\n", &e);
    
    //b.只会被初始化一次
    for (int i = 0; i < 10; i++) {
        static int n = 100;//只执行一次
        printf("%d ", n++);
    }
    printf("\n");
    
    //c.不赋初值, 默认0
    static int f;
    printf("%d\n", f);
    return 0;
}

4.常量区

存放数据:常量(1,3.14,'a',"iOS")

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

常量区由系统管理

    char *p = "iOS";
    printf("常量区地址: %p\n", p);
    
    //*p = 'm';//error
    printf("%s\n", p);

//函数名就是函数的首地址 printf("代码区地址: %p\n", hello);

5.代码区

存放数据:程序中的函数编译后的指令

代码区由系统控制

//函数名就是函数的首地址
    printf("代码区地址: %p\n", hello);

把字符串"1ab2c3d45e67g8h9"中的数字提取出来,形成新的字符串,新的字符串要求存放在堆区

提示:先求数字的个数,再根据个数开辟内存空间

char str[] = "1ab2c3d45e67g8h9";
    int count = 0;
    int i = 0;
    while (str[i] != '\0') {
        //判断字符是不是数字字符
        if (str[i] >= '0' && str[i] <= '9') {
            count++;
        }
        i++;
    }
    printf("count = %d\n", count);
    
    //在堆区申请空间
    char *p5 = malloc(count + 1);
    //遍历字符串
    int j = 0;
    int k = 0;
    while (str[j] != '\0') {
        //判断字符是不是数字字符
        if (str[j] >= '0' && str[j] <= '9') {
            *(p5 + k) = str[j];
            k++;
        }
        j++;
    }
    //最后补上'\0'
    p5[k] = '\0';
    printf("%s\n", p5);
    free(p5);
    p5 = NULL;

处理内存函数

void*calloc(n, size)

1.申请n * size个字节,并返回内存的首地址,申请到内存后,会把内存中的数据清空

2.比起maloc,效率低,安全性高

int *p6 = calloc(10, sizeof(int));
    free(p6);
    p6 = NULL;

void*realloc(p, size)

1.从指针p的位置,重新申请size个字节

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

int *p7 = malloc(4);
    printf("%p\n", p7);
    int *p8 = realloc(p7, 800);
    printf("%p\n", p8);

memset(p, c, n)

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

char *p9 = malloc(4); memset(p9, 66, 2); printf("%s\n", p9);

memcpy(p1, p2, n)

从指针p2的位置开始,向指针p1的位置,拷贝n个字节的内容

    char str1[] = "ABCDEFG";
    char str2[] = "1234567";
    memcpy(str1 + 3, str2 + 4, 3);
    printf("%s\n", str1);
    printf("%s\n", str2);

memcmp(p1, p2, n)

比较p1p2指向的内存中的内容是否相等,比较n个字节

    int *q = malloc(4);
    *q = 259;
    int *r = malloc(4);
    *r = 13;
    int result = memcmp(q, r, 2);
    printf("result = %d\n", result);

定义两个整型指针,分别用malloccalloc对其分配空间保存3个元素,malloc分配的空间用memset清零,随机对数组进行赋值随机范围1-3,赋值后用memcmp比较两个数组。如果相同打印Good!否则打印Failed...

//定义两个整型指针,分别用malloc、calloc对其分配空间保存3个元素
    int *m = malloc(sizeof(int) * 3);
    int *n = calloc(3, sizeof(int));
    
    //malloc分配的空间用memset清零
    memset(m, 0, sizeof(int) * 3);
    
    //随机对数组进行赋值随机范围1-3
    for (int i = 0; i < 3; i++) {
        *(m + i) = arc4random() % 3 + 1;
        *(n + i) = arc4random() % 3 + 1;
    }
    
    //打印数组m
    printf("\n数组m:\n");
    for (int i = 0; i < 3; i++) {
    printf("%d ", *(m + i));
    }
    
    //打印数组n
    printf("\n数组n:\n");
    for (int i = 0; i < 3; i++) {
        printf("%d ", *(n + i));
    }
    printf("\n");
    
    //赋值后用memcmp比较两个数组
    int result1 = memcmp(m, n, sizeof(int) * 3);
    //如果相同打印Good, 否则打印Failed
    if (result1 == 0) {
        printf("Good!");
    } else {
        printf("Failed...");
    }