目录
一,为什么用动态内存分配
在C语言中,我想要创建一个个可变长度的的数组, 那我该怎么做呢?
试着创建一个可变大小的结构体数组。
代码:
struct S {
char name[20];
int age;
};
int main() {
int n = 0;
scanf("%d", &n);
struct S arr[n];
return 0
}
结果VS编译器报了错误
这难道是编译器的问题?
在linux环境下我继续尝试了上面的代码
代码运行成功了!!
这是为什么呢?
原来C语言C99标准中增加了 linux支持,在linux是可以创建变长数组(数组长度可变的).
如果我们一定要在VS中使用可变数组呢?那么得用使用动态内存分配函数了!!
二.malloc函数
(1)malloc函数介绍
malloc的参数是一个int类型,指的是所需开辟内存的字节大小
malloc会返回一个指向开辟空间的指针.如果开辟失败,会返回空指针
malloc的返回类型是void*,返回的是内存起始地址
举例:
使用malloc函数向内存申请10个整形的空间,
#include<stdilb.h>
#include<string.h>
#include<errno.h>
int* p=(int*) malloc(10*sizeof(int));
if (p==NULL)
{
printf("%s\n", strerror(errno));
}
由于malloc函数返回值是void*,如果是需要一个整形指针接收,要使用(int*)进行强制类型转换,
如果开辟失败,则打印出出错信息,
如果开辟成功,则创建这个内存,p指针指向了这段内存的起始地址
画画图:
内存布局:
可以看到,生成的都是cd cd的内存地址
用这段内存打印出0-9:
int main() {
int* p=(int*) malloc(10*sizeof(int));
if (p==NULL)
{
printf("%s\n", strerror(errno));
}
else
{
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
*(p + 1) = 1;
}
free(p);
return 0;
}
妥妥的打印了出来
(2)注意事项
1.开辟的内存不能超过最大空间,否则会返回空指针!
试下开辟INT_MAX个字节的空间, 这个数字是几十亿级的
尝试下,结果是失败的,报错信息是空间不够足
说明开辟空间时,内存需要足够的大,而且判断是否开辟成功能让代码变的更加的安全!!
2. 当动态申请的空间不再使用的时候,应该还给操作系统
也就是在使用完内存后,需要用free函数,释放出去.
三.calloc函数
(1)calloc函数介绍
calloc的第一个参数是元素的个数,第二个参数是每个元素的长度
calloc开辟空间,但是各个字节初始化都是0
calloc会返回一个指向开辟空间的指针.如果开辟失败,会返回空指针
calloc的返回类型是void* ,返回的是内存起始地址
举例:
使用calloc函数向内存申请10个整形的空间.并打印出存放的元素.
#include<stdilb.h>
#include<string.h>
#include<errno.h>
int* p = (int*)calloc(10, sizeof(int));
if (p==NULL)
{
printf("%s\n", strerror(errno));
}
else
{
int i = 0;
for ( i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
}
可以看到,打印出的都是0
内存布局:
四.realloc函数
(1)realloc函数介绍
调整动态开辟内存空间的大小
第一个参数是开辟内存对应的指针,第一个参数是添加需要调整的大小
举例:
我需要用内存分配打印出0-9的数字,而我只开辟了20字节的大小的空间
int *p=(int*)malloc(20);
if (p==NULL)
{
printf("%s\n", strerror(errno));
}
else
{int i = 0;
for ( i = 0; i < 5; i++)
{
*(p + i) = i;
}
}
假设这里,20个字节不能满足我们的使用了,希望我们能够有40个字节的空间,这里就可以使用realloc来调整动态开辟的空间
打印出来,后面五个为随机值
我们用realloc调整空间
p = realloc(p, 40);
if (p != NULL)
{
int i = 0;
for (i = 5; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
}
打印出来
(2)注意事项
1.如果p指向空间之后有足够的内存空间可以追加,则直接追加,后返回p
比如,我们要开辟了这个20个字节的空间
开辟成功后地址是0x00945f68
可以看到,调整内存大小后,地址还是0x00945f68,则说明realloc返回的还是p原来的地址
2.如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一个新的内存区开辟一块满足需求的空间,并且把原来内存中的数据拷贝回来,释放旧的内存空间,返回新开辟空间的内存地址.
00c55f68
继续开辟20个字节的空间,不过这块空间准备调整成4000个字节
执行后,可以看到内存地址已经发生了变化!!这说明函数已经开辟了另一块空间,指针p指向了该空间
可以看到,原来的数据是没有发生变化的
3.得用新的变量来接收realloc函数的返回值,以免p被丢弃
int* ptr = realloc(p, 4000);
if (ptr != NULL)
{
p = ptr;
int i = 0;
for (i = 5; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
}