一、malloc()函数
函数原型 voidmalloc(size_t);
因为返回值未void类型,所以在接受malloc()返回值时应该加上强转类型,在c语言中无所谓,但是还是应保持好一点的习惯
malloc()开辟的空间不会对所开辟的空间的数据进行初始化,开辟出来的数据就是随机值
malloc()必须与free()一起出现,不能不释放开辟出的空间,但是若程序结束,其开辟的空间也会随着程序结束一起释放了。
free()过后的需不需要将原指针置空(指向NULL值)?
需要:1.可以避免用户错误使用释放的空间 2.避免二次释放带来的错误,将同一空间释放两次,因为free(NULL)值是不会报错的
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
//函数原型 void*malloc(size_t);
//因为返回值未void*类型,所以在接受malloc()返回值时应该加上强转类型,在c语言中无所谓,但是还是应保持好一点的习惯
//malloc()开辟的空间不会对所开辟的空间的数据进行初始化,开辟出来的数据就是随机值
//malloc()必须与free()一起出现,不能不释放开辟出的空间,但是若程序结束,其开辟的空间也会随着程序结束一起释放了。
//free()过后的需不需要将原指针置空(指向NULL值)?
//需要:1.可以避免用户错误使用释放的空间 2.避免二次释放带来的错误,将同一空间释放两次,因为free(NULL)值是不会报错的
struct student
{
int id;
char name[15];
int age;
double score;
};
void test01()
{
struct student* t1 = (struct student*)malloc(sizeof(struct student));
//判断开辟成功的两种方法
//1.采用if语句
if (t1 == NULL)
{
perror(" ");//打印错误信息
return;
}
//2.采用断言函数
assert(t1 != NULL);
t1->age = 18;
t1->id = 18060102;
strcpy(t1->name, "张三");
t1->score = 90.0;
printf("姓名%s\t学号%d\t年龄%d\t成绩%f\n", t1->name, t1->id, t1->age, t1->score);
free(t1);
t1 = NULL;
}
int main(void)
{
test01();
system("pause");
return EXIT_SUCCESS;
}
二、realloc()函数
realloc()函数原型 voidrealloc(voidspace,size_t size);//参 1:原空间 参2:新的需要申请的空间
三步走: 1.申请size个空间2.对原空间的值进行拷贝,拷贝 size个大小,(确认拷贝正确性),3.free掉原空间 4.返回新开辟空间地址
注意:realloc()函数既可以将原空间增大,也可以减小。
realloc()开辟的两种情况:1.直接在其后面空间申请 2.若后面空间不大,则新开辟一个空间,同时释放原来占用的空间
realloc()函数实现:因为无法实现在其内存后开辟的情况,故只提供一种方法
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
void* my_realloc(void* des, size_t size)
{
void* new_space = malloc(size);//1.申请空间
memcpy(new_space, des, size);//2.对原空间size大小个数据复制,此时size为新开辟的空间大小
free(des);//3释放原空间
des = NULL;
return new_space;//返回新开辟的空间
}
void test01()
{
int* arr = (int*)malloc(sizeof(int) * 5);
if (arr == NULL)
{
return;
}
for (size_t i = 0; i < 5; i++)
{
arr[i] = i + 1;
}
for (size_t i = 0; i < 5; i++)
{
printf("%d\t", arr[i]);
}
printf("\n");
arr =(int *) realloc(arr, sizeof(int) * 10);
for (size_t i = 5; i < 10; i++)
{
arr[i] = i + 1;
}
for (size_t i = 0; i < 10; i++)
{
printf("%d\t", arr[i]);
}
printf("\n");
free(arr);
arr = NULL;
}
int main(void)
{
test01();
system("pause");
return EXIT_SUCCESS;
}
三、calloc()函数
函数原型 voidcalloc(size_t num,size_t ele_size);//num为元素个数,ele_size为元素大小
其实这边的num.ele_size的值在满足numele_size=你需要的大小 其组合来说,可以是任意的,但必须是整数
与malloc异同
同:都是开辟空间的函数,都需要手动释放。
不同:开辟语法不同,calloc函数在开辟成功后会将开辟出来的数据初始化,而malloc不会
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
void test01()
{
int* p = (int*)calloc(1, 40);
if (p == NULL)
{
return;
}
for (size_t i = 0; i < 10; i++)
{
p[i] = i * 10;
}
for (size_t i = 0; i < 10; i++)
{
printf("%d\t", p[i]);
}
printf("\n");
free(p);
p = NULL;
}
int main(void)
{
test01();
system("pause");
return EXIT_SUCCESS;
}
四、柔性数组
柔性数组特点:
结构中的柔性数组成员前面必须至少一个其他成员。
sizeof 返回的这种结构大小不包括柔性数组的内存。
包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
用途: 长度为0的数组的主要用途是为了满足需要变长度的结构体
用法 : 在一个结构体的最后, 申明一个长度为0的数组, 就可以使得这个结构体是可变长的.对于编译器来说, 此时长度为0的数组并不占用空间, 因为数组名本身不占空间, 它只是一个偏移量, 数组名这个符号本身代表了一个不可修改的地址常量
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
struct student
{
int age;
char name[15];
char str[0];//这个即为柔性数组 1.不占空间 2.必须置于所有变量之后,而且只能存在一个
};
void test01()
{
const char* str = "hello world";
int len = strlen(str);
struct student* t1 = (struct student*)malloc((sizeof(struct student) + len + 1));//实质:仍需要在定义时开辟空间,
//可以让其适应不同长度类型的大小的数组
t1->age = 10;
strcpy(t1->str, "张三");
strcpy(t1->name, "李四");
}
int main(void)
{
system("pause");
return EXIT_SUCCESS;
}
五、是不是所有的内存开辟都需要手动释放?
答案是不是的,calloc()、malloc()、realloc()都需要手动开辟,手动释放,但有一个函数alloca()函数
函数原型:void*alloca(size_t size);
目的:在栈上开辟内存,并返回首地址
不可使用free()释放,其生命周期从创建开始,到程序运行结束,由程序自动释放。