🌞欢迎来到C语言的世界
🌈博客主页:卿云阁💌欢迎关注🎉点赞👍收藏⭐️留言📝
🌟本文由卿云阁原创!
🌠本阶段属于锻体阶段,希望各位仙友顺利完成突破
📆首发时间:🌹2021年1月20日🌹
✉️希望可以和大家一起完成进阶之路!
🙏作者水平很有限,如果发现错误,请留言轰炸哦!万分感谢!
目录
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; }