编程杂谈

常规想法遍历一遍单链表,记录长度再一次遍历,输出中间元素这样的效率不是最优另一种方式(来源于网络)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;}

编程杂谈

格式化读写‘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 743 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 650 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 784 0
编程杂谈

更灵活的内存管理方式在C语言中不存在其他高级语言的垃圾回收机制,在平常方式直接的声明变量,C语言不知道什么时候回收它,所以会一直占用内存空间.而更灵活的管理就是我们能在不使用该变量时就主动释放它。申请的空间不在使用,一定要释放(free(),虽然不是一定释放,但这是一个好习惯使用的库需要引入#include<stdlib.h>void*malloc(size_tsize);申请动态内存空间voidfree(void*ptr);释放动态内存空间void*calloc(size_tnmemb,size_tsize);申请并初始化内存空间为0void*realloc(void*ptr,size_tsize);重新分配内存空间申请空间&释放空间void*malloc(size_tsize);申请成功:返回一个指向申请的内存空间的指针,返回值是void所以可以转化成其他类型申请失败:返回NULL如果size参数设置为0,返回值也可能是NULL,但这并不意味着函数调用失败。voidfree(void*ptr);只能释放由malloc、calloc、realloc函数申请的空间,释放后该地址变为非法地址。参数指向将要释放的内存空间的地址没有返回值#include<stdio.h>#include<stdlib.h>//引入intmain(){//申明变量int*ptr,num=520;//申请内存空间ptr=(int*)malloc(sizeof(int));if(ptr==NULL){exit(1);}//内存申请失败//内存空间存入变量ptr=&num;//输出值printf("prt->%d",*ptr);//释放内存空间free(ptr);return0;}内存泄漏内存泄漏是程序一直占用内存,不释放,造成内存达到很高的使用量,严重造成计算机卡死,所以在不使用该空间时尽量释放掉。有两种情况会导致:隐式内存泄漏(即用完内存块没有及时使用free函数释放)丢失内存块地址申请并初始化&重新分配申请并初始化void*calloc(size_tnmemb,size_tsize);nmemb:指定分配的内存块个数size:指定每个内存块的大小,以字节为单位。#include<stdio.h>#include<stdlib.h>intmain(){//初始化变量int*ptr=NULL;//申请并初始化变量ptr=(int*)calloc(10,sizeof(int));if(ptr==NULL){exit(1);}//查看内容for(inti=0;i<10;++i){printf("%d",ptr[i]);};printf("\n");return0;}重新分配内存空间只能重新分配malloc()函数申请的空间void*realloc(void*ptr,size_tsize);重新分配内存空间参数*ptr:指向由先前调用malloc、calloc或realloc函数返回的内存空间如果传入NULL,相当于调用malloc(size)函数参数size:指定新的内存块空间大小,以字节为单位该函数将移动内存空间的数据并返回新的指针如果新分配的内存空间比原来的大,则旧内存块的数据不会发生改变;如果新的内存空间大小小于旧的内存空间,可能会导致数据丢失,慎用!#include<stdio.h>#include<stdlib.h>intmain(){//初始化变量int*ptr=NULL;//申请并初始化变量ptr=(int*)malloc(10*sizeof(int));if(ptr==NULL){exit(1);}//重新分配内存空间ptr=(int*)realloc(ptr,20*sizeof(int));printf("%llu",sizeof(ptr));ptr[12]=66666666;//赋值//查看内容for(inti=0;i<20;++i){printf("%d",ptr[i]);}return0;}