c语言十七:动态内存申请

一 动态内存申请

  1. 数组的长度是预先定义好的,在整个程序中固定不变;
  2. 但在实际应用中,往往有这种情况,所需要的内存空间取决于实际输入的数据,而无法预先确定
  3. 为了解决上面的问题,C语言提供了一些内存管理函数,这些内存管理函数可以安装需要动态的分配内存空间,也可以把不再使用的内存空间回收再利用

二 静态分配内存和动态分配内存

2.1 静态分配内存

  1. 在程序编译或运行过程中,按事先规定好的大小分配内存空间的分配方式;
  2. 必须事先知道所需空间的大小;
  3. 空间是分配在栈区或全局变量区的;
  4. 按计划分配

2.2 动态分配内存

  1. 在程序运行过程中按需要自由分配所需空间;
  2. 按需分配;
  3. 空间是分配在堆区的,一般使用特点函数来分配

三 动态内存申请的相关函数

3.1 分配内存空间函数 malloc

函数功能: 在内存的动态存储器(堆区)中分配一块长度为size字节的连续内存空间,用来存放类型说明符指定的数据类型
函数原型: void *malloc(unsigned int num_bytes);
				形参num_bytes是需要申请内存空间的字节数
调用形式: (类型说明符*) malloc(size)
返回值:
		分配成功:分配的内存空间的起始地址
		分配失败:NULL
注意事项:
		1. 对malloc的返回值一定要强制类型转换;
		2. malloc申请的内存空间的内容不确定,一般需要使用memset进行清空;
		3. 调用malloc后,一定要判断一下,是否申请内存成功;
		4. 如果多次malloc申请的内存,第一次和第二次申请的内存不一定连续;

3.2 free函数 (释放内存函数)

函数说明:free函数释放ptr指向的内存
函数定义:void free(void *ptr)
注意事项:ptr指向的内存必须是malloc,calloc,relloc动态申请的内存

3.3 案例一:从堆区申请一个int类型的空间

[root@ansible9 ~]# cat  test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{
	int *p=NULL;
	p=(int *)malloc((int)sizeof(int));
	if(p==NULL)
	{
		printf("malloc err\n");
		return 1;
	}
	printf("用malloc申请的内存空间中的内容是不确定的:%d\n",*p);
	memset(p,0,(int)sizeof(int));
	printf("用memset清0后的内存空间中的内容是:%d\n",*p);
	printf("请输入一个int数值:");
	scanf("%d",p);
	printf("%d\n",*p);
	free(p);
}
[root@ansible9 ~]# ./a.out 
用malloc申请的内存空间中的内容是不确定的:0
用memset清0后的内存空间中的内容是:0
请输入一个int数值:111
111

3.4 案例二:从堆区申请一个数组,数组的大小由用户决定

步骤:

  1. 从键盘获取要申请的数组的大小;
  2. 根据大小,从内存堆区申请空间;
  3. 对空间读写操作;
  4. 释放该空间;
[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{
	printf("请输入数值元素的个数:");
	int n=0;
	scanf("%d",&n);
	printf("将要为元素个数为%d个的数组申请内存空间\n",n);
	int *p=NULL;
	p=(int *)malloc(n*(int)sizeof(int));
	if(p==NULL)
	{
		perror("malloc error!");
		return 1;
	}
	memset(p,0,n*(int)sizeof(int));
	int i=0;
	printf("请输入%d个int数组",n);
	for(i=0;i<n;i++)
	{
		scanf("%d",p+i);
	}
	for(i=0;i<n;i++)
	{
		printf("%d\n",p[i]);
	}
	free(p);
}
[root@ansible9 ~]# ./a.out 
请输入数值元素的个数:5
将要为元素个数为5个的数组申请内存空间
请输入5个int数组10 20 30 40 50 60 70 80 
10
20
30
40
50

3.5 calloc函数

函数原型:void * calloc(size_t nmemb, size_t size);
			参数: size_t是无符号整形,是在头文件中用typeof定义出来的
			返回值:申请失败:返回NULL;申请成功:返回申请的内存的首地址
函数功能:在内存的堆区,申请nmemb块,每块大小为size字节的连续内存空间
注意事项:
			1. calloc函数申请的内存空间已经自动被清0了,不用再用memset清0;
			2. calloc函数申请的内存空间字节数为nmemb和size的乘积;
[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{
	printf("请输入数值元素的个数:");
	int n=0;
	scanf("%d",&n);
	printf("将要为元素个数为%d个的数组申请内存空间\n",n);
	int *p=NULL;
	p=(int *)calloc(n, (int)sizeof(int));
	if(p==NULL)
	{
		perror("calloc error!");
		return 1;
	}
	int i=0;
	printf("请输入%d个int数组",n);
	for(i=0;i<n;i++)
	{
		scanf("%d",p+i);
	}
	for(i=0;i<n;i++)
	{
		printf("%d\n",p[i]);
	}
	free(p);
}
[root@ansible9 ~]# ./a.out 
请输入数值元素的个数:5
将要为元素个数为5个的数组申请内存空间
请输入5个int数组10 20 30 40 50 60 70
10
20
30
40
50

3.5 realloc函数(重新申请内存空间)

函数原型:void* realloc(void* s, unsigned int newsize);
形参:s原先开辟内存的地址           newsize:新申请内存的大小
返回值:新申请内存的首地址
函数功能:在原先s执行的内存基础上重新申请内存,新的内存大小为newsize字节,如果原先内存后面有足够大的空间就追加;如果没有则realloc函数会在内存堆区找一个newsize字节大小的空间来申请,将原先内存中的数据拷贝过来,然后释放原先的内存,最后返回新内存的地址
[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{
	printf("请输入数值元素的个数:");
	int n=0;
	scanf("%d",&n);
	printf("将要为元素个数为%d个的数组申请内存空间\n",n);
	int *p=NULL;
	p=(int *)calloc(n, (int)sizeof(int));
	if(p==NULL)
	{
		perror("calloc error!");
		return 1;
	}
	int i=0;
	printf("请输入%d个int数组元素",n);
	for(i=0;i<n;i++)
	{
		scanf("%d",p+i);
	}
	for(i=0;i<n;i++)
	{
		printf("%d\n",p[i]);
	}
	printf("想要为数组增加几个元素:");
	int m=0;
	scanf("%d",&m);
	printf("您想要增加%d个元素\n",m);
	p=(int *)realloc(p,(n+m)*(int)sizeof(int));
	if(p==NULL)
	{
		perror("calloc error!");
		return 1;
	}
	printf("请输入%d个新int数组元素",m);
	for(i=n;i<(m+n);i++)
	{
		scanf("%d",p+i);
	}
	for(i=0;i<(n+m);i++)
	{
		printf("%d\n",p[i]);
	}
	printf("数组现有%d个元素\n",(n+m));
	int h=0;
	printf ("想减少几个元素:");
	scanf("%d",&h);
	printf("您想减少%d个元素\n",h);
	p=(int *)realloc(p,(n+m-h)*(int)sizeof(int));
	if(p==NULL)
	{
		perror("calloc error!");
		return 1;
	}
	for(i=0;i<(n+m-h);i++)
	{
		printf("%d\n",p[i]);
	}
	free(p);
}
[root@ansible9 ~]# ./a.out 
请输入数值元素的个数:3
将要为元素个数为3个的数组申请内存空间
请输入3个int数组元素10 20 30
10
20
30
想要为数组增加几个元素:2
您想要增加2个元素
请输入2个新int数组元素40 50
10
20
30
40
50
数组现有5个元素
想减少几个元素:4
您想减少4个元素
10

四 动态内存申请的注意事项

4.1 指向堆区的指针变量不要随意更改指向,会导致calloc申请的内存空间泄漏

[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{
	int *p = (int *)malloc(4*(int)sizeof(int));
	int num=10;
	p=&num;
}

4.2 不要操作已经释放的空间,因为该空间内容已经不能确定了

[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{
	int *p = (int *)malloc((int)sizeof(int));
	memset(p,0,(int)sizeof(int));
	*p=100;
	free(p);
	printf("%d\n",*p);
}

4.3 不要对堆区空间重复释放

[root@ansible9 ~]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg, char *argv[])
{
	int *p = (int *)malloc((int)sizeof(int));
	memset(p,0,(int)sizeof(int));
	*p=100;
	free(p);
	free(p);
}
[root@ansible9 ~]# gcc -Wall test.c
[root@ansible9 ~]# ./a.out 
free(): double free detected in tcache 2
Aborted (core dumped)

4.4 如何防止对堆区空间重复释放?

在这里插入图片描述

五 从堆区中给各个数据类型申请内存空间

5.1 为int变量在堆区申请内存空间

int main(int arg, char *argv[])
{
        int *p = (int*)calloc(1,(int)sizeof(int));
        *p=100;
        printf("%d\n",*p);
        if(NULL!=p)
        {
                free(p);
                p=NULL;
        }
}

5.2 为char*变量在堆区申请内存空间

int main(int arg, char *argv[])
{
        char **p = (char**)calloc(1,(int)sizeof(char*));
        *p = (char*)calloc(1,(int)sizeof(char));
        printf("%p\n",p);
        printf("%p\n",*p);
        **p='A';
        printf("%c\n",**p);
}

5.3 为char数组变量在堆区申请内存空间

int main(int arg, char *argv[])
{
        char*p = (char*)calloc(5,(int)sizeof(char));
        int n=0;
        for(n=0;n<5;n++)
        {
                printf("请输入第%d个字符:",n+1);
                scanf("%c%*c",p+n);
        }
        printf("%s\n",p);
        free(p);
}

5.4 为结构体变量在堆区申请内存空间

struct stu
{
        int num;
        char name[32];
        int age;
};


int main(int arg, char *argv[])
{
        struct stu* p = (struct stu*)calloc(1,(int)sizeof(struct stu));
        p->num=100;
        strcpy(p->name,"andy");
        p->age=18;
        printf("num=%d\n",p->num);
        printf("name=%s\n",p->name);
        printf("age=%d\n",p->age);
}

struct stu
{
        int num;
        char name[32];
        int age;
};

void my_set_stu(struct stu* p)
{
        printf("请输入学生的信息 num name age\n");
        scanf("%d %s %d",&p->num,p->name,&(*p).age);
}
void my_print_stu(const struct stu* p)
{
        printf("num=%d\n",p->num);
        printf("name=%s\n",p->name);
        printf("age=%d\n",p->age);
}
int main(int arg, char *argv[])
{
        struct stu* p = (struct stu*)calloc(1,(int)sizeof(struct stu));
        my_set_stu(p);
        my_print_stu(p);
        free(p);
}

5.5 为结构体变量数组在堆区申请内存空间

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stu 
{
	int num;
	char name[32];
	int age;
};

void my_set_stu(struct stu* p, int n)
{
	int i=0;
	for(i=0;i<n;i++)
	{
		printf("请输入第%d个学生的信息 num name age\n", i+1);
		scanf("%d %s %d",&(p+i)->num,(p+i)->name,&(*(p+i)).age);
	}
}
void my_print_stu(const struct stu* p, int n)
{
	int i=0;
	for(i=0;i<n;i++)
	{
		printf("第%d个学生的信息: ",i+1);
		printf("num=%d ",(p+i)->num);
		printf("name=%s ",(p+i)->name);
		printf("age=%d\n",(p+i)->age);
	}
}
int main(int arg, char *argv[])
{
	int n=0;
	printf("请输入学生个数:");
	scanf("%d",&n);
	struct stu* p = (struct stu*)calloc(n,(int)sizeof(struct stu));
	my_set_stu(p,n);
	my_print_stu(p,n);
	free(p);
}
  • 10
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值