链表和动态申请内存空间

🌞欢迎来到C语言的世界 
🌈博客主页:卿云阁

💌欢迎关注🎉点赞👍收藏⭐️留言📝

🌟本文由卿云阁原创!

🌠本阶段属于锻体阶段,希望各位仙友顺利完成突破

📆首发时间:🌹2021年1月20日🌹

✉️希望可以和大家一起完成进阶之路!

🙏作者水平很有限,如果发现错误,请留言轰炸哦!万分感谢!


目录

0️⃣动态申请内存空间

1️⃣链表的基本介绍,建立与访问

2️⃣创建动态链表

0️⃣✨✨✨动态申请内存空间✨✨✨  

C程序使用malloc、realloc等内存申请函数在堆上分配和释放内存的。

程序在执行期间有两个内存区域,一个是内存区域是栈(stack),另一个是堆(heap)。栈中的空间分配给函数的参数和本地变量,执行完该函数后,存储的参数和本地变量的内存空间就会自动释放。在堆上分配的内存,在不需要的时候要用free释放空间,由程序员控制。

malloc函数经常使用,其函数原型为

void *malloc(size_t  size);

这里size指定要申请的空间大小,以字节为单位。这个函数的功能是申请大小为size且逻辑上连续的内存空间,并返回该空间的首地址,如果不成功返回NULL。malloc函数本身并不清楚申请的空间存放什么类型的数据,所以给定的返回类型为void*型,编程人员申请这个空间需要存放什么数据可以应用强制类型转换。

例如malloc(100);,就是申请100个字节大小的空间。malloc函数如果申请成功,就可以用这些内存空间来存放数据。例如,申请100字节的空间来存放int型的数据,可以写成:

int *p;
p=(int *)malloc(sizeof(int)*10);
for(int i=0;i<=9;i++)
  p[i]=i+1;
free(p);  //释放空间
p=NULL;

malloc和realloc函数申请的空间不能被系统自动释放,因此,即使这些空间在程序中已经不用,别的程序也不能用。所以C中提供了一个专门的函数free(地址)来释放这些空间。例如free(ptr);,就释放了ptr指向的空间。为防止出现野指针,最好再加上ptr=NULL

​ 

malloc函数必须提供要申请的字节数,而编程人员一般都知道要存放多少个数据,却并不很清楚一个数据占多少个字节 

用malloc函数申请空间时,一般应用sizeof运算符获得数据对象的数据类型所占的字节数,然后再乘以数据对象个数以获取应该申请的字节数。

例如要申请能存k个int型数据的内存空间,就可以写成: 

p=(int *)malloc(sizeof(int)*k);

在实际应用的过程中,就很难确定一个k值,所以在程序执行过程中,如果发现用malloc申请的空间不够使用或者多了,可以利用realloc函数来调整空间大小。realloc的函数原型为:

void *realloc(void *ptr, size_t size);

第一个参数ptr是重新申请空间的首地址size是字节数。即从ptr这个地址开始重新申请大小为size字节的空间。用realloc重新申请的空间并不损害原来空间上已存放的数据

这个函数一般用于调整malloc申请的空间大小,所以ptr一般就设定为malloc函数返回的地址,然后,size设定为更大或更小的数。例如,原来已经使用malloc申请了能存k个int型数据的空间,由于数据量的增加,这个空间不够,可以用

p=(int *)realloc(p,sizeof(int)*(k+n));

对空间进行扩展,此时,空间就可以存放k+n个int型数据值得注意的是realloc得到的内存空间可能不是malloc原申请的空间(原来空间的值可能被释放了),因此,“p=”不能丢。

有了realloc函数,就可以不用先确定非常大的空间,而是先申请少量的空间,等空间不够时,再用realloc来增加。

例在上面例子的基础上我们再增加10个int型空间

#include <stdio.h>
int main() {
int *p;
p=(int *)malloc(sizeof(int)*10);
printf("Previous address=%ld\n",p);
for(int i=0;i<=9;i++)
  p[i]=i+1;
p=(int *)realloc(p,sizeof(int)*(10+10));
printf("Current address=%ld\n",p);
for(int j=9;j<=19;j++)
   p[j]=j+1;
free(p);  //释放空间
p=NULL;
return 0;
}

free时候怎么知道malloc申请的大小?

                                                  

例.写一个程序,功能是在某单位登记来人姓名、进入时间和电话号码等信息,并可以输出所有来人信息。

分析:可以定义一个结构体类型,把来人需登记的信息作为成员变量。因为来人的个数事先不能确定,所以就可以先用malloc申请能存放n(例如10)个人信息的内存空间,当空间不够时,再用realloc在原有基础上增加能存m个人(如5个)信息的空间。处理完成后,释放malloc或realloc申请的空间。


1️⃣✨✨✨ 链表的基本介绍,建立与访问✨✨✨

单链表是以结点方式存放数据的,一个结点由两部分组成,一部分存放元素数据,称为数据域,另一部分存放它的后一个结点的指针,称为地址域。后续没有结点时,地址域的值为0。它们在内存中存放的顺序是不连续的.

建立

#include <stdio.h>
typedef struct student
{
  int num; 
  float score;          //数据域
  struct student *next ;//地址域
} Student;
int main(void)
{
Student stu1,stu2,stu3,*head;
stu1.num=1001;stu1.score=98;
stu2.num=1002;stu2.score=85;
stu3.num=1003;stu3.score=90;
head=&stu1;//把stu1的地址给head.
stu1.next=&stu2; //把第二个结点的地址赋给第一个结点的next。
stu2.next=&stu3; //把第三个结点的地址赋给第二个结点的next。
stu3.next=NULL;//把第三个结点的next赋成0,链表结束。
printf("stu1 address=%ld\n",head);
printf("stu2 address=%ld\n",stu1.next);
printf("stu3 address=%ld\n",stu2.next);
return 0; 
}

总结:物理上是不连续的,逻辑上是连续的。

 访问

通常用一个指针变量存放指向单链表第一个结点的指针,称头指针。如果知道头指针值,就可以得到第一个结点,应用它的地址域值就可得到此结点的后一个结点,依次类推,可以顺序访问所有结点。

Student *p=head;  //初始化p为head的值,即指向第一个结点。
   while(p!=0)  
   {
      printf("%d,%5.1f\n",p->num,p->score);  //输出结点成员的值。
      p=p->next;  // 把p指向下一个结点。
}

2️⃣✨✨✨创建动态链表✨✨✨  

    所谓动态创建链表是指在程序执行过程中从无到有建立起一个链表,即一个一个地申请结点空间并输入各结点数据,然后建立结点间的前后相连关系,形成一个链表。

要创建这样的链表,就要不断用malloc申请内存空间以存放结点的值,一个结点申请内存空间完成后,可以为相应的数据赋值,然后把结点接入链表中。因此整个创建链表的过程可用一个循环来处理。

以建立两个结点为例

#include <stdio.h>
#include<stdlib.h>
struct student
{
   long num;
   float score; 
   struct student *next;
};
int main()
{
   struct student *head=0,*p1,*p2;  //这里head的初始值要赋0。
   int tempnum,tempnum1;
   float tempscore,tempscore1;
   tempnum=202018080;
   tempscore=98.5;
   //第一个结点
   head=p1=p2=(struct student *)malloc(sizeof(struct student));
   if(NULL==p1)return 0;    
    p1->num=tempnum;  //把输入的数据赋给相关成员变量。
    p1->score=tempscore; //把输入的数据赋给相关成员变量。
    p1->next=0;
    //第二个结点。
    //新开结点空间,并赋给成员变量值。
   tempnum1=202018081;
   tempscore1=98.5;
    p1=( struct student *)malloc(sizeof(struct student));
    if(NULL==p1)return 0;
    p1->num=tempnum;
    p1->score=tempscore;
    p1->next=0;
    p2->next=p1;  //把新结点和上一个结点连起来。
    p2=p1; //把p2指向新建结点,为下次链接作准备。
    free(p1);     //释放p1指向的空间。
    p1=NULL;
    free(p2);     //释放p1指向的空间。
    p2=NULL;
   return 0; 
}

创建动态链表完整代码

#include<stdio.h>
#include<stdlib.h>
struct student
{
	int num;//学号
	float sore;//分数
	struct student *next;//指针 
};
struct student *creat()
{
	int tempnum;//学号
	float tempsore;//分数
	struct student *head=0,*p1,*p2;//指针 
	int n=1;
	printf("请输入学号和分数(学号=0时结束)\n"); 
	scanf("%d%f",&tempnum,&tempsore);
	while(0!=tempnum)
	{
		if(1==n)
		{
			head=p1=p2=(struct student*)malloc(sizeof(struct student));
			p1->num=tempnum;
			p1->sore=tempsore;
			p1->next=0;
			n++;
		}
		else
		{
			p1=(struct student*)malloc(sizeof(struct student));
			p1->num=tempnum;
			p1->sore=tempsore;
			p1->next=0;
			p2->next=p1;
			p2=p1;
			n++;
		}
	
	printf("请输入学号和分数(学号=0时结束),建立第%d个节点\n",n); 
	scanf("%d%f",&tempnum,&tempsore);
	}
	return head;
}
void print(struct student *head)
{
	struct student *p=head;
	while(0!=p)
	{
		printf("%d,%5.1f\n",p->num,p->sore);
 		p=p->next;   //p指向下一个结点。
	}
}
int main()
{
	struct student *head,*p,*p1;//指针 
	p=head=creat();
	print(head);
	while(0!=p)
	{
		p1=p;
		p=p->next;
		free(p1);
		p1=NULL;
	}
	return 0;
}

  • 9
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卿云阁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值