目录
1.malloc (void* malloc (size_t size);)
③注意事项:malloc函数是需要进行内存释放的,虽然在程序结束后内存会自动释放,但是如果程序一直没有结束那么需要自己先释放
2.free函数(void free (void* ptr);)
③注意事项:如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。如果参数 ptr 是NULL指针,则函数什么事都不做。
3. calloc函数(void* calloc (size_t num, size_t size);//开辟num个大小为size 的空间)
①calloc函数介绍(void* realloc (void* ptr, size_t size);):
(一)这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。realloc在调整内存空间的是存在两种情况:
一、 为什么存在动态内存分配
二、动态内存函数的介绍
这些函数都是在堆区存放的,使用时需要stdlib.h
1.malloc (void* malloc (size_t size);)
①malloc 函数介绍:
-
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。如果开辟成功,则返回一个指向开辟好空间的指针。
-
如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
-
返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
-
如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
②malloc函数的使用:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{
//申请40个字节用来存放10个整型,需强制类型转换因为malloc返回的是void*
int* p = (int*)malloc(40);
//需要判断是否申请成功
if (p == NULL)
{
printf("%s\n", strerror(errno));
}
//存放1~10
for (int i = 0; i < 10; i++)
{
*(p + i) = i + 1;
printf("%d ", *(p + i));
}
}
③注意事项:malloc函数是需要进行内存释放的,虽然在程序结束后内存会自动释放,但是如果程序一直没有结束那么需要自己先释放
2.free函数(void free (void* ptr);)
①free函数介绍:
②free函数的使用:
#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{
//申请40个字节用来存放10个整型,需强制类型转换因为malloc返回的是void*
int* p = (int*)malloc(40);
//需要判断是否申请成功
if (p == NULL)
{
printf("%s\n", strerror(errno));
retrurn 1;
}
//存放1~10
for (int i = 0; i < 10; i++)
{
*(p + i) = i + 1;
printf("%d ", *(p + i));
}
free(p);
p = NULL;//在释放p地址对应的后面的空间后,p地址空间还没有释放,为了防止p被非法访问,需要将p置为空
}
③注意事项:如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。如果参数 ptr 是NULL指针,则函数什么事都不做。
3. calloc函数(void* calloc (size_t num, size_t size);//开辟num个大小为size 的空间)
①calloc函数介绍(void* realloc (void* ptr, size_t size);):
②calloc函数的使用:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include<errno.h>
int main()
{
int* p = (int*)calloc(10, sizeof(int));
if (NULL == p)
{
perror("calloc");
return 1;
}
for (int i = 0; i < 10; i++)
{
*(p + i) = i;
printf("%d " ,*(p + i));
}
free(p);
p = NULL;
return 0;
}
malloc申请到空间,没有初始化,直接返回起始地址
callloc申请好后,,会把空间初始化为0,然后返回起始地址
③注意事项:
(一)这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。realloc在调整内存空间的是存在两种情况:

首先看下面代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include<errno.h>
int main()
{
int* p = (int*)malloc(10, sizeof(int));
if (NULL == p)
{
perror("calloc");
return 1;
}
for (int i = 0; i < 10; i++)
{
*(p + i) = i;
printf("%d " ,*(p + i));
}
//假如空间不够了,需要增加五个整型的空间
int* ptr = (int*)realloc(p, 10 * sizeof(int));
if (ptr != NULL)
{
p = ptr;
}
free(p);
p = NULL;
return 0;
}

三、常见的动态内存错误
1.解引用空指针
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p = (int*)malloc(100);
for (int i = 0; i < 20; i++)
{
*(p + i) = 0;
}
free(p);
p = NULL;
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include<errno.h>
int main()
{
int* p = (int*)malloc(100);
//malloc 返回值一定要判断
if (p == NULL)
{
printf("%s", strerror(errno));
}
for (int i = 0; i < 20; i++)
{
*(p + i) = 0;
}
free(p);
p = NULL;
return 0;
}
2 对动态开辟空间的越界访问
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include<errno.h>
int main()
{
int* p = (int*)malloc(100);
//malloc 返回值一定要判断
if (p == NULL)
{
printf("%s", strerror(errno));
return 1;
}
for (int i = 0; i < 100; i++)
{
*(p + i) = 0;
}
free(p);
p = NULL;
return 0;
}
写的100个字节结果要访问100*sizeof(int)(400)个字节的空间
3 对非动态开辟内存使用free释放
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include<errno.h>
int main()
{
int a = 10;//栈区
int* p = &a;
free(p);
p = NULL;
return 0;
}
4 使用free释放一块动态开辟内存的一部分
void test()
{
int *p = (int *)malloc(100); p++;
free(p);
}
此时的p不再指向动态内存的起始位置
5 对同一块动态内存多次释放
void test()
{
int *p = (int *)malloc(100); free(p);
free(p);//重复释放
}
6 动态开辟内存忘记释放(内存泄漏)
void test()
{
int *p = (int *)malloc(100); if(NULL != p)
{
*p = 20;
}
}
int main()
{
test();
while(1);
}
四、几个经典的动态内存分配的笔试题
下面代码运行后会有什么样的结果?
(一)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void GetMemory(char* p)
{
p = (char*)malloc(100);
}
void test()
{
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
int main()
{
test();
return 0;
}
答:什么都不会打印
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
void test()
{
char* str = NULL;
GetMemory(&str);
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
}
int main()
{
test();
return 0;
}
(二)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
void test()
{
char* str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
test();
return 0;
}
str为数组首元素的地址,但是在出函数后内容被销毁,再printf后就非法访问空间
这类问题被称为返回栈空间的地址问题
修改:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* GetMemory(void)
{
static char p[] = "hello world";
return p;
}
void test()
{
char* str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
test();
return 0;
}
(三)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* GetMemory(char **p,int num)
{
*p = (char*)malloc(num);
}
void test()
{
char* str = (char *)malloc(100);
strcpy(str, "hello");
free(str);
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main()
{
test();
return 0;
}
野指针非法访问,当cpy world的时候,那块空间已经释放了
修改:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* GetMemory(char **p,int num)
{
*p = (char*)malloc(num);
}
void test()
{
char* str = (char *)malloc(100);
strcpy(str, "hello");
free(str);
str = NULL;
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main()
{
test();
return 0;
}
五、C/C++程序的内存开辟
六、柔性数组
C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
例如:
typedef struct st_type
{
int i;
int a[];//柔性数组成员
}type_a;
1.柔性数组的特点:
//code1
typedef struct st_type
{
int i;
int a[0];//柔性数组成员
}type_a;printf("%d\n", sizeof(type_a));//输出的是4
2 柔性数组的使用
//code1
typedef struct st_type
{
int i;
int a[0];//柔性数组成员
}type_a;printf("%d\n", sizeof(type_a));//输出的是4
int i = 0;
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));//业务处理
p->i = 100;
for(i=0; i<100; i++)
{
p->a[i] = i;
}
free(p);
这样柔性数组成员a,相当于获得了100个整型元素的连续空间。
3 柔性数组的优势
上述的 type_a 结构也可以设计为:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct st_type
{
int i;
int* p_a;
}type_a;
int main()
{
type_a* p = (type_a*)malloc(sizeof(type_a));
p->i = 100;
p->p_a = (int*)malloc(p->i * sizeof(int));
//业务处理
for (int i = 0; i < 100; i++)
{
p->p_a[i] = i;
}
//增容
type_a *ptr=(type_a*)realloc(p, sizeof(type_a) + 20 * sizeof(char));
if (ptr != NULL)
{
p = ptr;
}
else
{
return 1;
}
//释放空间
free(p->p_a);
p->p_a = NULL;
free(p);
p = NULL;
return 0;
}