1.结构体类型数据的动态存储分配
一.前言
c语言提供了一些内存管理函数,用于动态分配内存空间(堆区).可以根据需要开辟内存的单元,在程序执行时,需要多少空间就分配多少内存空间,且当空间不再使用还可以释放
二.关于内存空间的函数
在有操作系统和虚拟地址管理情况下,一次malloc的内存虚拟地址是连续的,物理地址不连续,连续多次malloc的内存之间不连续,应该说不一定连续
1.分配内存空间函数malloc
(类型说明符*)mallloc(size)
功能:在内存的动态存储区中分配一片长度为size字节的连续区域.如果分配成功,就返回所分配空间的起始地址;如果分配失败,就返回空指针NULL。
说明
- “类型说明符” 表示该区域
- (类型说明符*)表示把返回值强制转换为该类型指针。
- size是一个无符号整数
例如
pc=(char *)malloc(80);
表示分配80个字节的内存空间,空间首地址强制转换为指向字符的指针,并赋予指针变量pc.
2.释放内存空间函数calloc
调用形式为
free §;
功能:释放p指向的内存空间,由系统回收。
2.链表实例
#include<stdio.h>
#include<stdlib.h>
struct student
{
long num;
float score;
struct student *next;
};
struct student *creat(int n); //创建链表
//这里struct student是类型,*表示是指针,也就是说函数create()返回值是一个struct student
类型的指针。
void print(struct student *head);//链表遍历
struct student *del(struct student *head,int num); //删除链表中的一个节点
//这里struct student是类型,*表示是指针
//也就是说函数create()返回值是一个struct student类型的指针。
struct student *insert(struct student *head,struct student *stud);//链表的插入
int main(void)
{
//创建一个链表
struct student *phead=NULL;
phead=creat(3);
print(phead);//遍历链表
//链表中节点删除一个节点
printf("Please enter the num to delete:");
int n=0;
scanf("%d",&n);
print(del(phead,n)); //删除一个节点后并遍历
//链表中插入一个节点
struct student stud;
printf("\nPlease input the num to insert: ");
scanf("%d,&stud",&stud.num);
printf("Please input the score:");
scanf("%f",&stud.score);
print(insert(phead,&stud));//节点插入并遍历
}
struct student *creat(int n)//创建链表
//这里struct student是类型,*表示是指针,也就是说函数create()返回值是一个struct student
类型的指针。
{
struct student *head=NULL,*p1,*p2;
head=p2=(struct student *)malloc(sizeof(struct student));//101开辟第一个节点,并使p2和head都指向它
printf("请输入学号 分数\n");
scanf("%ld %f",&p2->num,&p2->score);
for(int i=2;i<=n;i++)
{
p1=(struct student *)malloc(sizeof(struct student));
//for语句第一轮循环相当于开辟第二个节点
scanf("%ld %f",&p1->num,&p1->score);
p2->next=p1; //与上一节点相连
p2=p1; //使p2指向新连节点
}
p2->next=NULL;
return(head);
}
void print(struct student *head)//链表遍历
{
struct student *p;
p=head;//先使p指向结构体指针
while(p!=NULL)
{
printf("%d %f\n",p->num,p->score);
p=p->next;//巧妙转换先使p指向结构体指针,再让p访问结构体成员变量指针其保留下一个指向结构体的指针,然后再让其访问结构体成员指针
}
}
struct student *insert(struct student *head,struct student *stud)//链表的插入
//待会完成
//第一个参数需要被插入的链表 第二个参数待插入的结构的地址
{
struct student *p1,*p2=NULL,*ptr;
p1=head;
ptr=stud;
if(head==NULL)//如果链表是空表
{
head=ptr;
ptr->next=NULL;
}
else
{
while((ptr->num>p1->num)&&(p1->next!=NULL))
//两种情况退出循环while
{
p2=p1;
p1=p1->next;
}
if(ptr->num<=p1->num)
{
if(head==p1)//节点插入到表头
{
head=ptr;
}
else
{
p2->next=ptr;//节点插到表中间;
}
ptr->next=p1;
}
//第二种情况p0的num最大 ,插入到尾部
else//节点插入链表尾部
{
p1->next=ptr;
ptr->next=NULL;
}
}
return(head);
}
struct student *del(struct student *head,int num)//删除链表中的一个节点
{
struct student *p1,*p2=NULL;
if(head==NULL)//如果头节点指向NULL,这是一个空链表.纯属忽悠
printf("\nlist null!\n");
else
{
p1=head;
while(num!=p1->num&&p1->next!=NULL)
//前者保证num是否为我所想删除的num
//后者遍历整个链表是否能找到(找不到的情况)
{
p2=p1;
p1=p1->next;
}
if(num==p1->num)
{
if(p1==head)//如果删除的是第一个头节点
{
head=p1->next;
}
else//非头节点
{
p2->next=p1->next;
}
printf("\nDelete No:%d succeed!\n",num);
free(p1);//释放空间
}
else
{
printf("%d not been found!\n",num); //找不到要删除的节点
}
return(head);
}
} ``