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