内存分配
1. 引入
int nums[10] = {0}; //对int len = 10;
int nums[len] = {0}; //错是因为系统的内存分配原则导致的
2. 概述
在程序运行时,系统为了 更好的管理进程中的内存
,所以有了 内存分配机制
。
分配原则:
2.1 静态分配
静态分配原则:
特点:
1、在程序编译过程中,按事先规定的大小 分配内存空间的分配方式;
2、必须事先知道所需空间的大小;
3、分配在 栈区或全局变量区,一般 以数组的形式;
4、按计划分配。
2.2 动态分配
特点:
1、在程序运行过程中,根据需要大小自由分配所需空间;
2、按需分配;
3、分配在堆区,一般 使用特定的函数进行分配。
案例:
需求:1、班级有15个学员,定义数组记录学员成绩double score[15] = {0};2、记录学员成绩- 输入学员数量- 在堆区申请- 扩展- 释放
注意:
在c语言中提供了一系列动态分配内存的函数
这些函数大部分都在stdlib.h头文件中声明free 释放
malloc 申请空间,默认值随机
calloc 申请空间,默认值为0
realloc 扩展空间string.h中提供的函数
memset 将malloc中的随机数设为0
3. 动态分配函数
3.1 memset 函数
作用:重置
语法:
#include <string.h>void *memset(void *s, int c, size_t n);参数:s: 开始的位置c: 重置后的数据n: 重置的数量从s开始, 将n个字节的数据, 设置为c
示例:
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{char str[10] = {0};memset(str, 'a', 10);for (char i = 0; i < 10; i++){printf("%c ", str[i]);}printf("\n");// a a a a a a a a a a int nums[5] = {1,2,3,4,5};memset(nums, 0, 20);for (int i = 0; i < 5; i++){printf("%d ", nums[i]);}printf("\n");//0 0 0 0 0 return 0;
}
3.2 free 函数
作用:释放内存
语法:
#include <stdlib.h>void free(void *ptr);参数:ptr: 指针
注意:
ptr 指向的内存必须是
malloc
、calloc
、relloc
动态申请的内存
3.3 malloc 函数
作用:在堆内存中开辟空间
语法:
void *malloc(size_t size)参数:size_t: 可以理解为无符号int;size: 开辟空间大小,单位字节。返回值:开辟的空间的地址开辟失败返回NULL
注意:
- 在使用malloc时,需要 判断是否开辟成功;
- 如果多次 malloc 申请的内存,第 1 次和第 2 次申请的内存不一定是连续的;
malloc的返回值
在使用中 记得 强制类型转换 (因为该函数原型返回 void*指针 );- malloc从堆区申请空间后 空间的内容中的值是
随机的
(与局部变量一样大概率为0),可以使用memset函数对空间中的数据进行置0。
示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{//1、申请空间//申请一个可以存储10个int数据的空间int *nums = (int *)malloc(10 * sizeof(int));//2、判断是否开辟失败if(nums == NULL){printf("内存开辟失败\n");return 0;}//置0memset(nums, 0, 10*sizeof(int));//3、使用空间for (int i = 0; i < 10; i++){printf("请输入第%d个数\n", i+1);scanf("%d", &nums[i]);}for (int i = 0; i < 10; i++){printf("%d ", nums[i]);}printf("\n");//4、释放空间free(nums);return 0;
}
3.4 calloc 函数
作用:在堆内存中开辟空间
语法:
void *calloc(size_t nmemb, size_t size);参数:nmemb: 申请的块数size: 每块的大小返回值:开辟的空间的地址开辟失败返回NULLint *p = malloc(10 * sizeof(int));
int *p = calloc(10, sizeof(int));
示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{//1、申请空间//申请一个可以存储10个int数据的空间// int *nums = (int *)malloc(10 * sizeof(int));int *nums = (int *)calloc(10, sizeof(int));//2、判断是否开辟失败if(nums == NULL){printf("内存开辟失败\n");return 0;}//3、使用空间for (int i = 0; i < 10; i++){printf("请输入第%d个数\n", i+1);scanf("%d", &nums[i]);}for (int i = 0; i < 10; i++){printf("%d ", nums[i]);}printf("\n");//4、释放空间free(nums);return 0;
}
3.5 realloc 函数
作用:扩展空间,其实是重新申请内存
语法:
void *realloc(void *ptr, size_t size);参数:ptr:原指针size:从新开辟的大小,原大小+新开的大小返回值:开辟成功返回新地址开辟失败返回NULL
注意:
新地址不一定等于原地址,但是大概率相同
在原先 ptr 指向的内存基础上
重新申请内存
,新的内存的大小为 size 个字节,如果原先内存后面有足够大的空间,就追加,如果后边的内存不够用,则 relloc 函数会在堆区找一个 size 个字节大小的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新内存的地址。
示例:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{char * strs = (char *)calloc(3, sizeof(char));strs = realloc(strs, 2*sizeof(char));for (int i = 0; i < 5; i++){scanf("%s", &strs[i]);}for (int i = 0; i < 5; i++){printf("%c ", strs[i]);}printf("\n");free(strs);return 0;
}
4. 内存泄漏
4.1 概念
申请的内存,首地址丢了,找不了,再也没法使用了,也没法释放了,这块内存就被泄露了。
4.2 记录申请内存的指针变量指向别的地方
int *p = (int *)malloc(40);
int nums[10] = {};
p = nums; //p 指向别的地方了
//从此以后,再也找不到申请的 40 个字节了。 则动态申请的 40 个字节就被泄露了
4.3 在函数中申请空间,使用完毕没有释放
void test()
{int *p = (int *)malloc(40);
}
test(); //每调用一次 test 泄露 40 个字节
5. 防止多次释放
多次释放示例:
int *p = (int *)malloc(40);
free(p);
free(p);//注意多次释放会报错
防止多次释放:
释放前判断,释放后置NULL
示例:
int *p = (int *)malloc(40);
if(p != NULL)
{free(p);p = NULL;
}
if(p != NULL)
{free(p);p = NULL;
}
6. 练习
设计函数,接收一个字符串,返回这个字符串的逆向内容
#include <stdio.h>
#include <stdlib.h>int my_strlen(char *str)
{int len = 0;while (*str != '\0'){str++;len++;}return len;
}char * my_strrev(char *str)
{int len = my_strlen(str);char *new_str = (char *)calloc((len+1), sizeof(char));for (int i = 0; i < len; i++){new_str[i] = str[len-i-1];}new_str[len] = '\0';return new_str;
}int main(int argc, char const *argv[])
{char *str = "helloworld";char *new_str = my_strrev(str);printf("%s\n", new_str);if (new_str != NULL){free(new_str);new_str = NULL;}return 0;
}
// dlrowolleh