编程杂谈

栈相关概念什么是栈是限定仅在表尾(栈顶)进行插入和删除操作的线性表栈又称为后进先出(LastInFirstOut)的线性表,简称LIFO结构栈顶(top)我们把允许插入和删除的一端称为栈顶栈底(bottom)另一端称为栈底空栈不含任何任何数据元素的栈称为==空栈==栈的操作入栈入栈又称压栈,就是向栈中放数据,每次放入一个top指针就+1出栈取出栈中数据的操作,每取出一个top指针就-1清空栈清空栈,是把top指针直接指向bottom指针,原本物理空间上数据还存在栈的实现创建队列结构体#include<stdio.h>#include<stdlib.h>#defineSTACK_INIT_SIZE20//栈大小#defineSTACK_INCREMENT10//申请空间大小typedefcharElemType;//定义栈typedefstruct{ElemType*base;//栈低ElemType*top;//栈顶intstackSize;//当前栈容纳的大小}sqStack;初始化队列//初始化栈voidinitStack(sqStack*s){s->base=(ElemType*)malloc(STACK_INCREMENT*sizeof(ElemType));if(s->base==NULL)exit(-1);//空间申请失败s->top=s->base;s->stackSize=STACK_INIT_SIZE;printf("s->top:%p\n",s->top);printf("s->base:%p\n",s->base);}入栈(压栈)//压栈voidpush(sqStack*s,ElemTypee){//判断是否满栈,满栈则扩容if(s->top-s->base>=s->stackSize){s->base=(ElemType*)realloc(s->base,(s->stackSize+STACK_INCREMENT)*sizeof(ElemType));if(!s->base)exit(-1);}*(s->top)=e;//栈顶的值赋值es->top++;//栈顶地址向前推进}出栈//出栈voidpop(sqStack*s,ElemType*e){//判断下溢出if(s->top==s->base){return;}*e=*--s->top;//减之后赋值,*为取值,不是指针}当前栈长度//当前栈长度intsqStackLen(sqStack*s){returns->top-s->base;}主函数使用用户输入值,进行压栈,#号结束,输出栈内数据intmain(){sqStacks;initStack(&s);//初始化栈ElemTypec;printf("输入栈:");while((c=getchar())!='#'){getchar();push(&s,c);//压栈}getchar();//把\n从缓冲区去掉ElemTypee;while(sqStackLen(&s)){pop(&s,&e);//出栈printf("%c",e);}return0;}扩展(栈链)就是把栈和单链表结合,如下图一样栈链内元素是指针相连,而栈是顺序的地址队列概念什么是队列队列(queue)是只允许在一端进行插入的操作,而在另一端进行删除操作的线性表。队列主要特征是先进先出(FirstInFirstOut)队列操作队列的结构体#include<stdio.h>#include<stdlib.h>#defineElemTypechar//队列元素结构体(链表)typedefstructQNode{ElemTypedata;//队列节点数据structQNode*next;//队列指针}QNode,*QueuePrt;//队列头尾typedefstruct{QueuePrtfront,rear;//队头指针,队尾指针}LinkQueue;创建队列/*创建结构体在内存中创建一个头结点,将队列的头尾指针指向头结点,此时队列为空*/voidinitQueue(LinkQueue*q){q->front=q->rear=(QueuePrt)malloc(sizeof(QNode));if(!q->front)exit(-1);q->front->next=NULL;}入队列//入队列(下面是在从尾部入)voidinertQueue(LinkQueue*q,ElemTypee){QueuePrtnode=(QueuePrt)malloc(sizeof(QNode));if(!node)exit(-1);node->data=e;node->next=q->rear->next;q->rear->next=node;q->rear=node;}出队操作(取出队列的数据)//出队操作(下面是从队列头部取值)voidgetQueue(LinkQueue*q,ElemType*e){if(q->front==q->rear)return;//队列为空QueuePrtnode=q->front->next;*e=node->data;q->front->next=node->next;//队列头部向移动一位if(q->rear==node)q->rear=q->front;//队列最后数据被取出是,初始化为空free(node);};销毁队列//销毁队列voiddeleteQueue(LinkQueue*q){while(q->front){q->rear=q->front->next;free(q->front);q->front=q->rear;}}主函数使用intmain(){LinkQueueq;initQueue(&q);ElemTypee=0;printf("输入队列数据:");scanf("%c",&e);while(e!='#'){inertQueue(&q,e);scanf("%c",&e);}printf("队列中的数据:\n");while(q.rear!=q.front){getQueue(&q,&e);printf("%c",e);}return0;}

编程杂谈

常规想法遍历一遍单链表,记录长度再一次遍历,输出中间元素这样的效率不是最优另一种方式(来源于网络)search的速度是mid的两倍,search走完恰好mid走一半voidprintInt(intList*head){intList*mid,*search;//search的速度是mid的两倍,search走完恰好mid走一半mid=search=head;//保证midsearch启点一样while(search->next!=NULL){search=search->next;//search取下一个if(search->next!=NULL){search=search->next;//search再去下一个mid=mid->next;//mid就取一次}else{mid=mid->next;//search取到头,mid再往下取一位}}printf("\n%d",mid->num);}完整代码随机生成任意长度单链表输出单链表值输出位于中间的值奇数个是最中间值,偶数个是中间两个的前一个#include<stdio.h>#include<stdlib.h>#include<time.h>typedefstructIntList{intnum;structintList*next;}intList;intList*applyList();//生成随机长度单链表voidprintList(intList*head);//查看单链表voidprintInt(intList*head);//输出单链表中间值intList*applyList(){srand((unsigned)time(NULL));intlen=rand()%10+10;//10到20的随机数intList*head=(intList*)malloc(sizeof(intList));if(head==NULL)exit(-1);//链表头部申请失败head->next=NULL;while(len){intList*node=(intList*)malloc(sizeof(intList));node->num=rand()%10+20;node->next=head->next;head->next=node;len--;}returnhead;}voidprintList(intList*head){intList*t=head->next;while(t){printf("%d",t->num);t=t->next;}};voidprintInt(intList*head){intList*mid,*search;//search的速度是mid的两倍,search走完恰好mid走一半mid=search=head;//保证midsearch启点一样while(search->next!=NULL){search=search->next;//search取下一个if(search->next!=NULL){search=search->next;//search再去下一个mid=mid->next;//mid就取一次}else{mid=mid->next;//search取到头,mid再往下取一位}}printf("\n%d",mid->num);}intmain(){intList*list=applyList();//随机生成单链表printList(list);//查看链表的值printInt(list);//输出中间值return0;}

编程杂谈

什么是数据结构简单点就是程序设计=数据结构+算法逻辑结构&物理结构传统上把数据结构分为逻辑结构&物理结构逻辑结构:是指数据对象中数据元素之间的相互关系,是需要着重关注和讨论的问题。四大逻辑结构:集合结构:数据元素之间相互没有关系。线性结构:数据元素之间是一对一的关系。树性结构:数据元素之间有一对多的层级关系。图形结构:数据元素是多对多的关系。物理结构:指数据的逻辑结构在计算机中的存储形式。根据物理结构的定义,我们实际上研究的就是如何把数据元素存储到计算器的存储器中。数据元素的存储形式有两种:顺序存储:把数据元素存放在地址连续的存储单元里,其数据之间的逻辑关系和物理关系是一致的。就如:一些编程语言的数组就是这样。链式存储:把数据元素存放在任意的存储单元里,这组储存单元可以是连续的,也可以是不连续。就如单链表,只要知道下一个数据元素指向的地址就行`。什么是算法引入计算1+2+3+4+…+99+100的值常规算法(使用循环一个一个加):inti,sum=0,n=100;for(i=1;i<100;i++){sum=sum+i;}printf("sum=%d",sum);使用高斯算法:inti,sum=0,n=100;sum=(1+n)*n/2;printf("sum=%d",sum);这样是不是效率高很多。算法的特征算法有五大特征解决问题并不只有一种算法输入算法具有零个或者多个输入。尽管大多数时候算法来说,输入参数是必要的,但是就像打印bigdataboy.cn,就不需要参数。voidprint(){printf("bigdataboy.cn");}输出:算法需要至少一个或者多个输出。有穷性是指在执行有限的步骤后,自动结束,并且每一步都是在可接受的时间范围内完成。确定性:算法的每一步都具有确定的含义,不会出现二义性。相同的输入只能有唯一的输出结果。可行性:算法的每一步都必须是可行的,就是说,每一步都能通过执行有限的次数完成。算法设计的要求正确性:是指算法至少应该具有输入、输出和加工处理无歧义,能得到正确的结果。大致分为以下四个层次算法程序没有语法错误算法程序对于合法的输入能得到满足要求的输出算法程序对于非法输入能产生相应的说明算法程序对于故意刁难的测试输入都有满足要求的输出结果可读性算法需要便于阅读、理解和交流,方便日后他人和自己的阅读和修改。健壮性当输入不合法时,算法也能做出相关的处理,而不是产生异常、崩溃或莫名其妙的结果时间效率高和存储量低在生活中大家都想找一个漂亮乖巧懂事,懂分寸的女朋友。好的算法就像好的女朋友,应该同时具备时间效率高和存储量低的特点,设计算法时,因尽量考虑这两方面的问题!!!

编程杂谈

格式化读写‘fscanf()’、’fprintf()’格式化读‘fsanf()’用于从指定文件中读取格式化字符串。#include<stdio.h>...intfscanf(FILE*stream,constchar*format,...);用法:跟scanf()一样,只是多了stream参数fscanf(fp,"%d-%d-%d",&year,&month,&day);返回值调用成功,返回值是成功获取并填充到附加参数中的个数。调用失败,返回值小于附加参数的个数(甚至是0)。如果读取到标准输入流的结尾处,则返回EOF。格式化读‘fprintf()’用于打印格式化字符串到指定的文件。#include<stdio.h>...intfprintf(FILE*stream,constchar*format,...);用法:跟printf()一样,只是多了stream参数fprintf(fp,"IloveYou!\n");fprintf(fp,"Todayis%d-%d-%d\n",2021,1,22);返回值调用成功,返回值是实际打印的字符数(不包含表示字符串结束的‘\0’);调用失败,返回值是一个负数。实例格式化文件读写#include<stdio.h>#include<stdlib.h>#definePATH"./lines.txt"intmain(void){//打开文件FILE*fpw=fopen(PATH,"w");if(fpw==NULL)exit(1);//文件写入打开失败//格式化写入文件fprintf(fpw,"Todayis%d-%d-%d\n",2021,1,22);//关闭文件fclose(fpw);//打开文件FILE*fpr=fopen(PATH,"r");if(fpr==NULL)exit(2);//文件读取打开失败//读取文件intyear,month,day;fscanf(fpr,"Todayis%d-%d-%d",&year,&month,&day);printf("%d-%d-%d\n",year,month,day);//关闭读取文件fclose(fpr);return0;}二进制读写‘fread()’、’fwrite()’格式化读‘fread()’用于从指定的文件中读取指定尺寸的数据。#include<stdio.h>...size_tfread(void*ptr,size_tsize,size_tnmemb,FILE*stream);参数:ptr:指向存放数据空间的指针,该内存块的尺寸最小应该是size*nmemb个字节size:要读取的每个元素的尺寸nmemb:要读取的元素个数stream:是一个FILE对象的指针返回值成功:实际读取到的元素个数(nmemb);失败:返回比nmemb参数的值小,表示可能读取到文件末尾或者有错误发生(可以使用feof函数或ferror函数进一步判断)。格式化读‘fwrite()’将指定尺寸的数据写入到指定的文件中。#include<stdio.h>...size_tfwrite(constvoid*ptr,size_tsize,size_tnmemb,FILE*stream);参数:ptr:指向存放数据空间的指针,该内存块的尺寸最小应该是size*nmemb个字节size:要写入的每个元素的尺寸nmemb:要写入的元素个数stream:是一个FILE对象的指针返回值成功:返回实际写入到文件中的元素个数(nmemb);失败:如果返回值与nmemb参数的值不同,则有错误发生。实例#include<stdio.h>#include<stdlib.h>#definePATH"data.txt"structData{intyear;intmonth;intday;};intmain(void){//打开文件FILE*fpw=fopen(PATH,"w");if(fpw==NULL)exit(1);//打开写入文件失败//以二进制形式写入结构体到文件structData*data_write=(structData*)malloc(sizeof(structData));data_write->year=2021;data_write->month=1;data_write->day=21;fwrite(data_write,sizeof(structData),1,fpw);free(data_write);//关闭文件fclose(fpw);//打开文件FILE*fpr=fopen(PATH,"r");if(fpw==NULL)exit(2);//打开读取文件失败//以二进制形式读取文件structData*data_read=(structData*)malloc(sizeof(structData));fread(data_read,sizeof(structData),1,fpr);printf("%d-%d-%d\n",data_read->year,data_read->month,data_read->day);free(data_read);return0;}

编程杂谈

打开文件&关闭文件打开文件需要文件指针接收;关闭文件需要传入文件指针FILE*fp;//定义文件指针打开文件使用到的函数fopen()#include<stdio.h>FILE*fopen(constchar*path,constchar*mode);参数参数含义*path文件的路径,支持相对路径、绝对路径*mode指定文件打开的模式:r、w、a、r+、w+、a+b:以二进制形式打开文件,可以与上面的6种结合("rb","wb","ab","r+b","w+b","a+b")返回值打开成功,则返回一个指向FILE结构的文件指针;打开失败,则返回NULL并设置errno为指定的错误。打开文件模式文件打开模式说明“r”1.以只读的模式打开一个文本文件,从文件头开始读取2.该文本文件必须存在“w”1.以只写的模式打开一个文本文件,从文件头开始写入2.如果文件不存在则创建一个新的文件3.如果文件已存在则将文件的长度截断为0(重新写入的内容将覆盖原有的所有内容)“a”1.以追加的模式打开一个文本文件,从文件末尾追加内容2.如果文件不存在则创建一个新的文件“r+”1.以读和写的模式打开一个文本文件,从文件头开始读取和写入2.该文件必须存在3.该模式不会将文件的长度截断为0(只覆盖重新写入的内容,原有的内容保留)“w+”1.以读和写的模式打开一个文本文件,从文件头开始读取和写入2.如果文件不存在则创建一个新的文件3.如果文件已存在则将文件的长度截断为0(重新写入的内容将覆盖原有的所有内容)“a+”1.以读和追加的模式打开一个文本文件2.如果文件不存在则创建一个新的文件3.读取是从文件头开始,而写入则是在文件末尾追加“b”1.与上面6中模式均可结合(”rb”,“wb”,“ab”,“r+b”,“w+b”,“a+b”)关闭文件使用到的函数fclose()#include<stdio.h>intfclose(FILE*fp);参数参数含义fp指向一个待关闭的文件指针返回值:关闭成功,返回值是0;关闭失败,返回值是EOF,并设置errno为指定的错误。备注:磁盘已满、设备出错或者I/O错误均可能导致fclose函数调用失败。实例(打开文件&关闭文件)#include<stdio.h>#include<stdlib.h>intmain(void){FILE*fp;//定义文件指针//打开文件fp=fopen("data.txt","r");if(fp==NULL){printf("打开文件失败!!!\n");exit(EXIT_FAILURE);};//关闭文件if(fclose(fp)!=EOF){printf("关闭文件成功~~~");exit(EXIT_SUCCESS);};return0;}文件读写字符读写字符读‘fgetc()’、’getc()’fgetc()说明#include<stdio.h>...intfgetc(FILE*stream);参数说明:stream该参数是一个FILE对象的指针,指定一个待读取的文件流返回值:成功:将读取到的unsignedchar类型转换为int类型并返回;失败:如果文件结束或者遇到错误则返回EOF。getc()说明fgetc()、getc()两个的功能和描述基本上是一模一样的,它们的区别主要在于实现上:fgetc()是一个函数;而getc()则是一个宏的实现实例#include<stdio.h>#include<stdlib.h>intmain(){//定义文件指针FILE*fp;//打开文件if((fp=fopen("./data.txt","r"))==NULL){//文件打开失败exit(EXIT_FAILURE);}//读取文件的内容charch;while((ch=fgetc(fp))!=EOF){putchar(ch);;}//关闭文件流fclose(fp);return0;}字符写‘fputc()’、’putc()’将一个字符写入到指定的文件中并推进文件的位置指示器(用来指示接下来要读写的下一个字符的位置)。fputc()说明#include<stdio.h>...intfputc(intc,FILE*stream);参数说明:c:指定待写入的字符stream:该参数是一个FILE对象的指针,指定一个待写入的文件流返回值:成功:返回写入的字符;失败:如果文件结束或者遇到错误则返回EOF。putc()说明fputc()、putc()两个的功能和描述基本上是一模一样的,它们的区别主要在于实现上:fputc()是一个函数;而putc()则是一个宏的实现实例#include<stdio.h>#include<stdlib.h>intmain(){//定义文件指针FILE*fp;//打开文件if((fp=fopen("./data.txt","w"))==NULL){//文件打开失败exit(EXIT_FAILURE);}//写入一个字符charch='A';if(fputc(ch,fp)==EOF){//写入失败exit(EXIT_FAILURE);};//关闭文件流fclose(fp);return0;}字符串读写字符读‘fgets()’用于从指定文件中读取字符串。最多可以读取size-1个字符,因为结尾处会自动添加一个字符串结束符'\0'。当读取到换行符('\n')或文件结束符(EOF)时,表示结束读取('\n'会被作为一个合法的字符读取)。fgets()说明#include<stdio.h>...char*fgets(char*s,intsize,FILE*stream);参数说明:s:字符型指针,指向用于存放读取字符串的位置size:指定读取的字符数(包括最后自动添加的‘\0’)stream:该参数是一个FILE对象的指针,指定一个待操作的数据流返回值:成功:返回s参数指向的地址失败:如果在读取字符的过程中遇到EOF,则eof指示器被设置;如果还没读入任何字符就遇到这种EOF,则s参数指向的位置保持原来的内容,函数返回NULL。如果在读取的过程中发生错误,则error指示器被设置,函数返回NULL,但s参数指向的内容可能被改变。实例#include<stdio.h>#include<stdlib.h>#defineMAX1024intmain(){//打开文件FILE*fp;if((fp=fopen("./data.txt","r"))==NULL){exit(1);}//读取文件chars[MAX];if(fgets(s,MAX,fp)==NULL){//读取失败exit(2);};printf("%s",s);//输出读取内容//关闭文件fclose(fp);return0;}字符写‘fputs()’fputs函数用于将一个字符串写入到指定的文件中,表示字符串结尾的‘\0’不会被一并写入fputs()说明#include<stdio.h>...intfputs(constchar*s,FILE*stream);参数说明:s:字符型指针,指向用于存放待写入字符串的位置stream:是一个FILE对象的指针,指定一个待操作的数据流返回值:成功:返回一个非0值失败:返回EOF实例#include<stdio.h>#include<stdlib.h>intmain(void){//打开文件FILE*fp;if((fp=fopen("./data.txt","w"))==NULL){exit(1);//打开文件失败};//写入内容chars[]="iloveyou***";if(fputs(s,fp)!=0){exit(2);//写入失败}//关闭失败fclose(fp);return0;}

编程杂谈

位域(是表示二进制的位)使用位域是节省内存的一种操作,它能是int不用占用4字节的空间虽然现在的机器都是8G、16G的,但是在单片机的寸土寸金的内存上,还是需要对内存占用进行自定义的控制位的大小:8位构成1字节。1byte(字节)=8bit(位);字节的大小:1024字节等于1KB。1KB=1024B(字节);//位域的定义是在结构体里structToDay{unsignedintmouth:3;//在成员名后加冒号:位的大小undignedintday:2;};位于的使用#include<stdio.h>structToDay{unsignedintmouth:3;//在成员名后加冒号:位的大小unsignedintday:2;}toDay;intmain(void){toDay.mouth=8;toDay.day=3;printf("sizeoftoDay:%d\n",sizeof(toDay));printf("toDay.mouth=%d\n",toDay.mouth);printf("toDay.day=%d\n",toDay.day);return0;}位操作位操作时对二进制位进行一元和二元操作逻辑操作在许多古老的微处理器上,位运算比加减运算略快,通常位运算比乘除法运算要快很多在现代架构中,情况并非如此:位运算的运算速度通常与加法运算相同(仍然快于乘法运算)。运算符含义优先级举例说明~按位取反高~a如果a为1,则~a为0;如果a为0,则~a为1;&按位取与中a&b只有ab同时为1,结果才为1;只要ab其中一个为0,结果就为0;^按位取异或低a^b如果ab不同,则结果为1;如果ab相同,则结果为0;|按位取或最低a|b如果ab其中一个为1,则结果为1;如果ab同时为0,则结果为0;按位取反(~)~000000=>111111按位取与(&)001010&010110=>000010按位取异或(^)010110^011001=>001111按位取或(|)010011|100110=>110111

编程杂谈

共用体定义共用体与结构体有类似的地方//结构体structBoy{intid;charname[20];doubleage;};//共用体unionboy{intid;charname[20];doubleage;};//共用体可以不需要名称union{intid;charname[20];doubleage;}boy,a;共用体初始化初始化只能给其中一个元素赋值//定义时初始化unionBoy{intid;charname[20];doubleage;}boy={.name="大数据男孩",};//直接初始化第一个成员unionBoyboy={1};//用另一个共用体初始化unionBoyb=boy;//初始化指定成员unionBoyo={.name="大数据男孩"};共用体里元素的地址共用体里面元素共用一个地址#include<stdio.h>#include<string.h>//共用体、结构体在初始化之后赋值,需要用到该库函数//共用体unionBoy{intid;charname[20];doubleage;};intmain(void){unionBoyboy;boy.id=1;strcpy(boy.name,"大数据男孩");//不管是结构体、共用体,只有在初始化时才能直接对字符串赋值。boy.age=18.5;//打印地址printf("boy.id:%p\n",&boy.id);printf("boy.name:%p\n",boy.name);printf("boy.age:%p\n",&boy.age);return0;}共用体里元素的值因为共用体里元素的地址是一样的,所以只能输出最后赋值元素的值#include<stdio.h>#include<string.h>//共用体、结构体在初始化之后赋值,需要用到该库函数//公用体unionBoy{intid;charname[20];doubleage;};intmain(void){unionBoyboy;//赋值boy.id=1;strcpy(boy.name,"大数据男孩");//不管是结构体、共用体,只有在初始化时才能直接对字符串赋值。boy.age=18.55;//打印共用体的值printf("boy.id:%d\n",boy.id);printf("boy.name:%s\n",boy.name);printf("boy.age:%.2f\n",boy.age);return0;}共用体的内存占用这里内存占用,涉及到与结构体一样的内存对齐#include<stdio.h>#include<string.h>//共用体、结构体在初始化之后赋值,需要用到该库函数//公用体unionBoy{intid;charname[20];doubleage;};intmain(void){unionBoyboy;//赋值boy.id=1;strcpy(boy.name,"大数据男孩");//不管是结构体、共用体,只有在初始化时才能直接对字符串赋值。boy.age=18.55;//打印共用体元素的内存占用printf("boy.idsizeof:%llu\n",sizeof(boy.id));printf("boy.namesizeof:%llu\n",sizeof(boy.name));printf("boy.agesizeof:%llu\n",sizeof(boy.age));//打印共用体的内存占用printf("boysizeof:%llu\n",sizeof(boy));return0;}

2021-1-10 177 0
编程杂谈

单链表单链表是一种链式存取的数据结构,链表中的数据是以结点来表示的.每个结点的构成:元素(数据元素的映象)+指针(指示后继元素存储位置)元素就是存储数据的存储单元指针就是连接每个结点的地址数据。以“结点的序列”表示的线性表称作线性链表(单链表),单链表是链式存取的结构。单链表插入数据在链表头部插入以下代码有BUG,不能用于实际场景,只是例子这样写,没有释放空间#include<stdio.h>#include<stdlib.h>//定义一个结构体structInfo{charname[255];structInfo*next;//指向下一个Info结构体};//申请链表节点structInfo*applyNode(){structInfo*node;node=(structInfo*)malloc(sizeof(structInfo));if(node==NULL)exit(0);//空间申请失败returnnode;}//输出单链表的值voidprintInfo(structInfo*head){//传入的链表头部,通过头部链表找后面的链表structInfo*info;info=head->next;while(info!=NULL){printf("%s",info->name);info=info->next;};printf("\n");}intmain(void){//申请一个空间创建链表的头部structInfo*head;head=applyNode();head->next=NULL;//初始化头部链表charname[255];while(1){//申请新的节点structInfo*node=applyNode();//用户输入printf("输入姓名(n退出):");scanf("%s",node->name);if(*(node->name)=='n')exit(0);//n退出//改变指针指向地址node->next=head->next;head->next=node;//输出单链表的值printInfo(head);}return0;}在链表尾部插入以下代码有BUG,不能用于实际场景,只是例子这样写,没有释放空间#include<stdio.h>#include<stdlib.h>//定义一个结构体structInfo{charname[255];structInfo*next;//指向下一个Info结构体};//申请链表节点structInfo*applyNode(){structInfo*node;node=(structInfo*)malloc(sizeof(structInfo));if(node==NULL)exit(0);//空间申请失败returnnode;}//输出单链表的值voidprintInfo(structInfo*head){//传入的链表头部,通过头部链表找后面的链表structInfo*info;info=head->next;while(info!=NULL){printf("%s",info->name);info=info->next;};printf("\n");}intmain(void){//申请一个空间创建链表的头部保存链表头部地址structInfo*head;head=applyNode();head->next=NULL;//初始化头部链表structInfo*tail=head;//一直表示链表尾部,第一次就是链表头部charname[255];while(1){structInfo*node=applyNode();//用户输入printf("输入姓名(n退出):");scanf("%s",node->name);if(*(node->name)=='n')exit(0);//n退出//改变指针指向地址tail->next=node;tail=node;tail->next=NULL;//输出单链表的值printInfo(head);}return0;}综合应用-在单链表中间插入链(完整代码)新输入的值,自动插入到适合大小位置相应函数//数组结构体structIntList{intnum;structIntList*next;};structIntList*applyNode();//新节点申请空间voidaddNum(structIntList*head,structIntList*node);//插入值voidprintIntList(structIntList*head);//输出单链表的内容voidclearNode(structIntList*head);//释放空间完整代码代码的难点:在于需要兼顾第一次、在头部、中间、尾部这些不同位置的插入。#include<stdio.h>#include<stdlib.h>//数组结构体structIntList{intnum;structIntList*next;};structIntList*applyNode();//新节点申请空间voidaddNum(structIntList*head,structIntList*node);//插入值voidprintIntList(structIntList*head);//输出单链表的内容voidclearNode(structIntList*head);//释放空间//申请空间structIntList*applyNode(){structIntList*node;node=(structIntList*)malloc(sizeof(structIntList));node->next=NULL;returnnode;}//插入值voidaddNum(structIntList*head,structIntList*node){structIntList*lastNode;//插入节点的前一个structIntList*now;//当前节点structIntList*nextNode;//插入节点的前一个now=head->next;//第一次插入,直接加在头部后面if(now==NULL){head->next=node;return;}//处理最小值,直接再头部插入if(node->num<=now->num){node->next=now;head->next=node;return;}//插入在中间的链while(now!=NULL){lastNode=now;nextNode=now->next;//遍历到最后,认为是最大值,插入在尾部if(nextNode==NULL){now->next=node;return;}//比前一个大,比后一个小,然后中间插入if(lastNode->num<=node->num&&node->num<=nextNode->num){lastNode->next=node;node->next=nextNode;return;//插入完成退出函数}now=nextNode;}};//输出单链表值voidprintIntList(structIntList*head){structIntList*node;node=head->next;while(node!=NULL){printf("%d",node->num);node=node->next;}printf("\n");};//清理空间voidclearNode(structIntList*head){structIntList*node;//循环清理所有空间while(head!=NULL){node=head->next;//记录下一个node地址free(head);//清理headhead=node;//node变成新的head}printf("空间清理完成!!!");};intmain(){structIntList*head=applyNode();//申请链表头部intnum=0;while(1){printf("输入一个数字(-1退出并清理空间):");scanf("%d",&num);if(num==-1){//清理空间并退出clearNode(head);exit(0);}//申请节点空间structIntList*node=applyNode();node->num=num;//把值插入链表addNum(head,node);//输出链表的内容printIntList(head);}

2021-1-6 171 0
编程杂谈

结构体变量之间的传递直接把结构体赋值给另一个结构体变量#include<stdio.h>structDate{intyear;intmonth;intday;}date={.year=2021,.month=1,.day=5};intmain(void){structDated;d=date;printf("d的值:%d-%d-%d",d.year,d.month,d.day);return0;}结构体作为函数参数传递把结构体变量作为函数的参数传递给函数#include<stdio.h>//定义结构体structDate{intyear;intmonth;intday;};//定义函数structDategetDate(structDatedate){//给结构体赋值date.year=2021;date.month=1;date.day=5;//返回结构体returndate;}intmain(void){structDatedate,d;d=getDate(date);printf("日期为:%d-%d-%d",d.year,d.month,d.day);return0;}结构体指针作为函数参数传递函数直接传入结构体会降低性能,传入结构体指针能提高程序效率#include<stdio.h>structDate{intyear;intmonth;intday;};//传入指针不需要返回值voidgetDate(structDate*date){//给结构体赋值date->year=2021;date->month=1;date->day=5;}intmain(void){structDatedate;getDate(&date);//传入地址printf("日期为:%d-%d-%d",date.year,date.month,date.day);return0;}动态申请结构体空间动态申请,存储在堆空间,用完记得释放#include<stdio.h>#include<stdlib.h>structDate{intyear;intmonth;intday;};//传入指针不需要返回值voidgetDate(structDate*date){//给结构体赋值date->year=2021;date->month=1;date->day=5;}intmain(void){structDate*date;//申请空间date=(structDate*)malloc(sizeof(structDate));getDate(date);//传入地址printf("日期为:%d-%d-%d",date->year,date->month,date->day);//释放空间free(date);return0;}

编程杂谈

结构体定义方式关键字:structstruct结构体名称{基本类型变量名;基本类型变量名;...};//注意这有分号structBoy{charname[20];chargender;floatage;};structBoy{charname[20];chargender;floatage;}boy;//这样定义不用初始化boy为全局变量structBoy{charname[20];chargender;floatage;}boy={"大数据男孩",//可以不指定但顺序要对.gender='A',.age=18.5,};//初始化并设置默认值初始化结构体//基本初始化struct结构体名称变量名;structBoyboy;//初始化全部值值的类型需要对应struct结构体名称变量名={内容,""}structBoyboy={"大数据男孩","A",18.2}//初始化部分值struct结构体名称变量名={.定义结构=值,...}structBoyboy={.name="大数据男孩",.gender="A",}结构体使用结构体赋值结构体变量名.值=变量;boy.name="大数据男孩";获取结构体的值变量=结构体变量名.值floatage=boy.age;结构体的内存占用原因:C语言的内存对齐结构体使用#include<stdio.h>//定义结构体structBoy{charname[20];chargender;floatage;};//注意这里有分号intmain(){structBoyboy;//初始化结构体printf("输入姓名:");scanf("%s",boy.name);//数组不用取址符printf("输入性别:");scanf("%s",&boy.gender);printf("输入年龄:");scanf("%f",&boy.age);printf("--------信息录入完毕---------\n\n");printf("基本信息:\n");printf("姓名:%s\n",boy.name);printf("性别:%s\n",&boy.gender);printf("年龄:%.2f\n",boy.age);return0;}结构体嵌套//日期结构体structDate{intyear;intmonth;intday;};//男孩结构体structBoy{charname[20];chargender;structDatedate;//嵌套的日期结构体}boy={.name="大数据男孩",.gender='A',.date={2020,12,15},};访问嵌套结构体#include<stdio.h>//日期结构体structDate{intyear;intmonth;intday;};//男孩结构体structBoy{charname[20];chargender;structDatedate;//嵌套的日期结构体}boy={.name="大数据男孩",.gender='A',.date={2020,12,15},};intmain(){printf("姓名:%s\n",boy.name);printf("性别:%c\n",boy.gender);//嵌套的结构体一层一层的访问printf("日期:%d-%d-%d",boy.date.year,boy.date.month,boy.date.day);return0;}结构体数组structDate{intyear;intmonth;intday;}date[2]={{2020,12,15},{2020,12,16},};访问结构体数组#include<stdio.h>structDate{intyear;intmonth;intday;}date[2]={{2020,12,15},{2020,12,16},};intmain(){//结构体数组//structDatedate[2]={//{2020,12,15},//{2020,12,16},//};//访问结构体数组的内容printf("date[0]:%d-%d-%d\n",date[0].year,date[0].month,date[0].day);printf("date[1]:%d-%d-%d\n",date[1].year,date[1].month,date[1].day);return0;}结构体指针结构体指针本质是指针,作用是指向一个结构体structDatedate={2020,12,15};//定义一个结构体structDate*pt;//定义结构体指针pt=&date;//指针指向结构体通过结构体指针访问结构体#include<stdio.h>structDate{intyear;intmonth;intday;};intmain(){//先定义该结构体structDatedate={2020,12,15};//定义该结构体指针structDate*pt;//结构体指针指向结构体pt=&date;//获取结构体值printf("year:%d",date.year);//结构体直接访问printf("month:%d",(*pt).month);//通过结构体指针访问,括号必须的(优先级问题)printf("day:%d\n",pt->day);//结构体指针箭头访问return0;}

2020-12-27 252 0