动态内存分配( 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]);
内存泄露: 内存一直被占用, 而得不到释放
内存释放的函数
void free(<#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)
比较p1和p2指向的内存中的内容是否相等, 比较n个字节
int *q = malloc(4); *q = 259; int *r = malloc(4); *r = 13; int result = memcmp(q, r, 2); printf("result = %d\n", result);
定义两个整型指针,分别用malloc、calloc对其分配空间保存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..."); }