1、动态内存申请的API
NAME
malloc, free, calloc, realloc - allocate and free dynamic memory
SYNOPSIS
#include <stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
DESCRIPTION
The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not
initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be
successfully passed to free().
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call
to malloc(), calloc(), or realloc(). Otherwise, or if free(ptr) has already been called before, undefined
behavior occurs. If ptr is NULL, no operation is performed.
The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer
to the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either
NULL, or a unique pointer value that can later be successfully passed to free().
The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents
will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If
the new size is larger than the old size, the added memory will not be initialized. If ptr is NULL, then the
call is equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL,
then the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call
to malloc(), calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
malloc申请堆区空间
#include <stdlib.h>
void *malloc(size_t size);
//因为不知道要申请的是哪种类型的空间(char、int等等),所以使用万能指针方便匹配,得到系统分配的空间起始地址
//size代表的是要申请的字节数
//函数的返回值:
//成功:返回空间的起始地址
//失败:返回NULL
free释放堆区空间
#include <stdlib.h>
void free(void *ptr); //ptr需要释放的堆区空间的起始地址
malloc和free的使用
#include <stdio.h>
#include <stdlib.h>
void test()
{
int *p = NULL;
p = (int *)malloc(sizeof(int)); // 返回一个万能指针,因为malloc返回值是一个地址,为 void *,所以要将void *强转为 int *
if (p == NULL){
return; //防止发生段错误
}
*p = 100;
printf("*p = %d\n", *p);
free(p); // 释放堆区空间
}
int main(int argc, char const *argv[])
{
test();
return 0;
}
申请堆区空间之后一定要释放
malloc函数的特点
malloc申请的堆区空间不自动清零 ,也就是说申请的堆区空间中还存有上次申请保存的数据,如果这样操作申请的堆区空间,那么操作得到的结果是不确定的
memset内存设置函数
s 是空间起始地址
c 是每一个字节需要填充的值
n 是空间的字节宽度
malloc申请数组空间
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test()
{
int n = 0;
printf("请输入 int 类型元素的个数:");
scanf("%d", &n);
int *p = NULL;
// 申请堆区空间
p = (int *)malloc(n * sizeof(int)); // 返回一个万能指针,因为malloc返回值是一个地址,为 void *,所以要将void *强转为 int *
if (p == NULL)
{
// 防止申请失败
return;
}
memset(p, 0, n * sizeof(int)); // 手动清零,将每一个元素设置为 0
printf("请输入 %d 个元素:", n);
for (int i = 0; i < n; i++)
{
scanf("%d", (p + i));
}
for (int i = 0; i < n; i++)
{
printf("%d\t", *(p + i));
}
free(p); // 释放堆区空间
printf("\n");
}
int main(int argc, char const *argv[])
{
test();
return 0;
}
calloc函数
#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);
//nmemb:内存的块数
//size:每一块的字节数,所以是一个总的地址连续空间,为 nmemb * size
//返回值:成功是堆区空间的起始地址,失败为NULL
//mallo会对申请的空间自动清零
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *get_addr(int n, int elem_size)
{
// 堆区空间申请
return calloc(n, elem_size);
}
void input_int_arr(int n, int *p)
{
printf("请输入 %d 个元素:", n);
for (int i = 0; i < n; i++)
{
scanf("%d", (p + i));
}
}
void printf_int_arr(int n, int *p)
{
for (int i = 0; i < n; i++)
{
printf("%d\t", *(p + i));
}
}
void test()
{
int n = 0;
printf("请输入 int 类型元素的个数:");
scanf("%d", &n);
int *p = NULL;
// 申请堆区空间
p = (int *)get_addr(n, sizeof(int)); // 返回一个万能指针,因为malloc返回值是一个地址,为 void *,所以要将void *强转为 int *
if (p == NULL)
{
// 防止申请失败
return;
}
//获取键盘输入
input_int_arr(n, p);
//输入数组
printf_int_arr(n, p);
free(p); // 释放堆区空间
printf("\n");
}
int main(int argc, char const *argv[])
{
test();
return 0;
}
realloc 函数 追加空间
追加空间只能对堆区空间追加,也即是只能对 mollc和calloc申请的堆区进行追加(追加是既可以减少也可以增加)
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
必须使用指针变量 获取 realloc 的返回值(返回值是新开辟空间的起始地址)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *get_addr(int n, int elem_size)
{
// 堆区空间申请
return calloc(n, elem_size);
}
void input_int_arr(int n, int *p)
{
printf("请输入 %d 个元素:", n);
for (int i = 0; i < n; i++)
{
scanf("%d", (p + i));
}
}
void printf_int_arr(int n, int *p)
{
for (int i = 0; i < n; i++)
{
printf("%d\t", *(p + i));
}
}
void realloc_fun(int n, int *p)
{
printf("\n");
printf("请输入要新增的元素个数:");
int new_num = 0;
scanf("%d", &new_num);
// 追加空间
p = (int *)realloc(p, (n + new_num) * sizeof(int));
printf("请输入 %d 个新增加元素:", new_num);
for (int i = n; i < n + new_num; i++)
{
scanf("%d", (p + i));
}
// 输出数组
printf_int_arr(n + new_num, p);
}
void test()
{
int n = 0;
printf("请输入 int 类型元素的个数:");
scanf("%d", &n);
int *p = NULL;
// 申请堆区空间
p = (int *)get_addr(n, sizeof(int)); // 返回一个万能指针,因为malloc返回值是一个地址,为 void *,所以要将void *强转为 int *
if (p == NULL)
{
// 防止申请失败
return;
}
// 输入数组
input_int_arr(n, p);
// 输出数组
printf_int_arr(n, p);
// 追加空间
realloc_fun(n, p);
free(p); // 释放堆区空间
printf("\n");
}
int main(int argc, char const *argv[])
{
test();
return 0;
}
void realloc_fun(int n, int *p)
{
printf("\n");
printf("请输入要新增的元素个数:");
int new_num = 0;
scanf("%d", &new_num);
// 追加空间
p = (int *)realloc(p, (n + new_num) * sizeof(int));
printf("请输入 %d 个新增加元素:", new_num);
for (int i = n; i < n + new_num; i++)
{
scanf("%d", (p + i));
}
// 输出数组
printf_int_arr(n + new_num, p);
}
2、内存泄露
申请的内存,首地址丢了,找不了,再也没法使用,也没法释放了,这叫做内存泄露
案例一
案例二
函数结束,局部指针变量要释放,但是堆区空间此时还没有释放,所以造成了没有人知道申请的堆区空间了,所以在函数调用结束的时候要人为释放堆区空间或者通过返回值知道堆区空间的起始地址吗,一直使用,不让丢失。每调用一次泄露一次
3、内存回顾
// 64位平台
void test05()
{
// 字符数组 在栈区 开辟12字节 存放hello world
char str[] = "hello world";
// 字符指针变量 在栈区 4B 保存文字常量区 hello world的首元素地址
char *str1 = "hello world";
// 字符指针变量 在栈区 4B 保存堆区空间的起始位置
char *str2 = (char *)malloc(128);
// 将字符串拷贝到str2指向的堆区空间
strcpy(str2, "Hello world");
printf("str2 = %s\n", str2);
}
char a;
int b;
// void fun(char str4[128])
void fun(char *str4)
{
printf("%lu\n", sizeof(str4)); // 将字符数组优化为指针,所以为 4
return;
}
void test06()
{
char str[] = "hello";
char *str1 = "hello";
char *str2 = (char *)malloc(128);
printf("%lu\n", sizeof(a)); // 1
printf("%lu\n", sizeof(b)); // 4
printf("%lu\n", sizeof(str)); // 6
printf("%lu\n", sizeof(str1)); // 8 指针变量
printf("%lu\n", sizeof(str2)); // 8 指针变量
fun(str);
}
int main(int argc, char const *argv[])
{
test05();
test06();
return 0;
}