知识点一:申请和释放空间
malloc函数
用于申请一块连续的指定大小的内存空间(堆区),并返回一个指向它的指针
头文件:#include <stdlib.h>
void *malloc(unsigned int num_ size);
//形参: num_ size需要申请空间大小的字节数
返回值:
成功:返回空间的起始地址
失败: NULL
- 对于malloc的返回值一般要强制类型转换再赋值保存(返回值就是开辟对应的空间)
- malloc申请的空间内容不确定,一般使用
memset进行清空- 多次调用malloc第1次malloc 和 第2次malloc的地址不一定连续
free函数
void free(void *addr); ()里面是保存malloc保存返回值的指针变量名
//功能:释放堆区空间
从堆区申请 一个 int 空间
int get_n(void)
{
int n = 0;
printf("请输入元素的个数:");
scanf("%d", &n);
return n;
}
int* get_addr(int n)
{
return (int *)malloc(n*sizeof(int));
}
void my_input_array(int *arr, int n)
{
int i=0;
//记得将arr指向的空间清0
memset(arr, 0, n*sizeof(int));
//获取键盘输入
printf("请输入%d个int数据\n",n);
for(i=0;i<n; i++)
{
scanf("%d", arr+i);
}
}
void my_print_array(int *arr, int n)
{
int i=0;
for(i=0;i<n;i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main(int argc,char *argv[])
{
int *arr=NULL;
int n = 0;
//得到用户输入的元素个数
//1、获取用户大小
n = get_n();
//定义函数 给arr申请堆区空间
arr = get_addr(n);
if(arr == NULL)
{
perror("get_addr");
return;
}
//对空间读写操作
my_input_array(arr, n);
//对空间数组遍历
my_print_array(arr, n);
//释放空间
free(arr);
return 0;
}
知识点二:内存块清零
将指定的值 c 复制到 str 所指向的内存区域的前 n 个字节中,这可以用于将内存块清零或设置为特定值
#include <string.h>
void *memset(void *str, int c, size_t n)
形参:
str:指向要填充的内存区域的指针
c:要设置的值,通常是一个无符号字符
n:要被设置为该值的字节数
返回值:返回一个指向存储区 str 的指针
#include <stdio.h>
#include <string.h>
int main ()
{
char str[50];
strcpy(str, "This is string.h library function");
puts(str); //This is string.h library function
//将str前7个字符,替换成$''
memset(str, '$', 7); //$$$$$$$ string.h library function
puts(str);
return(0);
}
知识点二:calloc函数
申请的空间自动清零,不需要memset清零
头文件:#include<stdlib.h>
// (强转类型 *)calloc(n,sizeof(类型)) n:无符号整数,()里面的字节数是n乘类型的字节数
void * calloc(size_t nmemb,size_ t size);
参数:
1、nmemb:申请的数据块数
2、size:每一块大小
申请总大小 = nmemb*size
返回值:
成功:返回空问的起始地址
失败:返回NULL
void test04()
{
int n = 0;
int i = 0;
int *arr = NULL;
//1、获取用户大小
printf("请输入元素的个数:");
scanf("%d", &n);
//2、根据大小从堆区申请空间
#if 0
arr = (int *)malloc(n * sizeof(int));
if(NULL == arr)
{
//perror 错误输出
perror("mallac");
return;
}
memset(arr,0,n*sizeof(int)); //清零
#endif
#if 1
arr=(int *)calloc(n, sizeof(int)); //自动清零 不需要使用memset
if(NULL == arr)
{
//perror 错误输出
perror("calloc");
return;
}
#endif
//对arr的读写操作
printf("请输入%d个int数据\n",n);
for(i = 0; i < n; i++)
{
scanf("%d", arr+i);
}
//遍历数组
for(i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
//释放空间
free(arr);
}
知识点三:realloc动态追加或减少空间
在原先s指向的内存基础.上重新申请内存,新的内存的大小为new_ size 个字节,如果原先内存后面有足够大的空间,就追加,如果后边的内存不够用,则relloc函数会在堆区找一个newsize个字节大小的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新内存的地址
#include<stdlib.h>
//(强转类型 *)realloc(保存原先开辟内存的指针名, (原先空间+新增空间)*sizeof(类型))
void* realloc(void *S,unsigned int newsize);
参数:
s:原先开辟内存的首地址
newsize: 新申请的空间的总大小(原先+新增部分大小)(如果新申请的空间比原先大,则是追加,如果比原先小,则是减少)
返回值:新申请的内存的首地址
realloc的返回值一般要强制类型转换再赋值保存(返回值就是开辟对应的空间)
int main(int argc,char *argv[])
{
int *arr = NULL;
int n = 0;
int i=0;
int n_new = 0;
//1、获取用户大小
printf("请输入元素的个数:");
scanf("%d", &n);
arr = (int *)calloc(n, sizeof(int)); //自动清零 不需要使用memset
if(NULL == arr)
{
//perror 错误输出
perror("calloc");
return;
}
printf("请输入%d个int数据\n",n);
for(i = 0;i < n; i++)
{
scanf("%d", arr+i);
}
//遍历数组
for(i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
//再追加5个元素
printf("请输入新增的元素个数:");
scanf("%d", &n_new);
arr = (int *)realloc(arr, (n+n_new)*sizeof(int));
printf("请输入新增的%d个int数据\n",n_new);
for(i = n; i < (n+n_new); i++)
{
scanf("%d",arr+i);
}
for(i = 0; i < (n+n_new); i++)
{
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
return 0;
}
知识点四:堆区空间使用注意事项
void test1()
{
int *p2 = NULL;
int *p3 = NULL;
//1、指向堆区空间的指针变量不要随意的更改指向
int *p = (int *)calloc(1, sizeof(int)) ;
int num = 10;
p = # //p指向num导致calloc申请的空间泄露
//2、不要操作已经释放的空间
p2 = (int *)calloc(1,sizeof(int));
*p2 = 1000;
//释放该空间
free(p2) ;
printf("*p2 = %d\n, *p2); //不确定
//3、不要对堆区空间重复释放
p3 = (int *)calloc(1, sizeof(int));
free(p3);
free(p3); //多次释放
}
知识点五:防止多次释放
void test09 ()
{
int *p = (int *)calloc(1,sizeof(int));
if(p != NULL) //防止多次释放
{
free(p);
p=NULL;
}
if(p != NULL)
{
free(p);
p=NULL;
}
}