更灵活的内存管理方式在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=#//输出值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;}
递归递归是一种编程思想,但是在实际的开发中除特定场景外,尽量不要使用递归使用递归求解阶乘#include<stdio.h>intfact(int);intfact(inti){longres=1L;//计算结果if(i>0){res=i*fact(i-1);}returnres;}intmain(void){longres=fact(30);printf("res=%ld",res);//输出long类型return0;}汉罗塔汉罗塔的C语言实现#include<stdio.h>voidhanoi(intn,charx,chary,charz);voidhanoi(intn,charx,chary,charz){if(n==1){printf("%c-->%c\n",x,z);}else{hanoi(n-1,x,z,y);printf("%c-->%c\n",x,z);hanoi(n-1,y,x,z);}}intmain(){intn;printf("请输入层数:");scanf("%d",&n);hanoi(n,'X','Y','Z');return0;快速排序#include<stdio.h>voidquick_sort(intarray[],intleft,intright);voidquick_sort(intarray[],intleft,intright){inti=left,j=right;//左右索引intpivot;//中间基准变量inttemp;//替换元素的临时变量pivot=array[(right+left)/2];while(i<=j){//遍历右边的小while(array[i]<pivot){i++;};//遍历左边的大while(array[j]>pivot){j--;};//左右大小交换if(i<=j){temp=array[i];array[i]=array[j];array[j]=temp;i++;j--;};}if(left<j){quick_sort(array,left,j);}if(i<right){quick_sort(array,i,right);}}intmain(void){intarray[]={33,12,4,8,45,56,78,9,56};//待排序数组intlength;length=sizeof(array)/sizeof(array[0]);//数组长度数组占用长度/其中一个元素长度quick_sort(array,0,length-1);for(intk=0;k<length;++k){printf("%d",array[k]);}putchar("\n");return0;}快速排序原理
局部变量局部变量只在那一个代码块能访问。#include<stdio.h>intmain(){inti=520;for(inti=0;i<3;i++){printf("for内部i:%d\n",i);};printf("外部的i%d",i);return0;}全局变量全局变量在程序启动就会创建,直到程序结束才会被销毁,所以会一直占用内存。在实际使用中,尽量避免使用全局变量,在维护时,会改一点而牵全身#include<stdio.h>intcount=0;//这就是全局变量inta(){returncount++;}intb(){returncount++;}intc(){returncount++;}intmain(){a();b();c();printf("count=%d",count);return0;}extern关键字当全局变量没有在开头定义,但在前面又需要使用,这时就需要使用extern了。#include<stdio.h>inta(){externcount;returncount++;}intcount=0;//这就是全局变量intb(){returncount++;}intc(){returncount++;}intmain(){a();b();c();printf("count=%d",count);return0;}
指针函数格式:返回类型*函数名(参数列表);不要返回局部变量的指针举个例子#include<stdio.h>char*get_Word(chars);char*get_Word(chars){charstr[]="Apple";//函数内的局部变量switch(s){case'A':returnstr;//无法返回这个strcase'B':return"Bad";case'C':return"Cat";default:return"None";}}intmain(){chari;printf("请输入一个字母:");scanf("%s",&i);printf("%s\n",get_Word(i));return0;}函数指针定义格式:返回值(*名称)(参数类型);#include<stdio.h>intsquare(intnum);intsquare(intnum){returnnum*num;}intmain(){intnum;int(*fp)(int);//定义函数指针printf("输入一个数字:");scanf("%d",&num);fp=square;printf("%d*%d=%d\n",num,num,(*fp)(num));printf("%d*%d=%d\n",num,num,*fp(num));return0;}头脑风暴涉及知识&实现功能涉及知识把函数指针作为函数的返回值。实现功能用户输入一个式子(1+5),自动判断符号,进行相应的运算。代码说明声明函数intadd(int,int);//加法函数intsub(int,int);//减法函数int(*select(char))(int,int);//符号选择,返回相应的计算函数intcalc(int(*)(int,int),int,int);//计算函数,传入一个函数指针,以及两个数字函数方法//加法函数intadd(intnum1,intnum2){returnnum1+num2;}//减法函数intsub(intnum1,intnum2){returnnum1-num2;}//符号选择int(*select(charop))(int,int){switch(op){case'+':returnadd;case'-':returnsub;}}//计算函数intcalc(int(*fp)(int,int),intnum1,intnum2){return(*fp)(num1,num2);}使用#include<stdio.h>intmain(){intnum1=0,num2=0;charop;int(*fp)(int,int);//接收函数指针printf("输入一个式子(1+1):");scanf("%d%c%d",&num1,&op,&num2);fp=select(op);//符号选择,返回函数指针printf("%d%c%d=%d",num1,op,num2,calc(fp,num1,num2));return0;}
爬虫目标爬虫字段:职位名称、职位URL、职位要求(逗号分隔csv文件)完整代码:https://github.com/bigdataboy2020/job51_spider爬虫结构分层结构模块化结构,减少耦合使用模块:gevent、lxml、typing、requests项目说明操作类(job51.py)主要包含发送请求的方法defget_data():请求获取一页所有的职位名称和职位的URLdefget_job_explain():获取一个职业的要求classJob51(object):#总页数。第一次获取会设置真实页数all_page=9999#正在获取的页数page_num=1#Job_name和url列表job_url_data:List[Tuple[str,str]]=list()#职位详情页列表[name,url,说明]job_explain:Tuple[str,str,List[str]]=Nonesession=requests.session()defget_data(self,page_num:str,city:List[str],search:str)->bool:"""#获取该关键词所有的职位名称与链接:parampage_num:当前页数:paramcity:城市列表:paramsearch:搜索词:return:"""returnTruedefget_job_explain(self,job_name:str,url:str)->bool:"""#获取一个职业的要求:paramjob_name:职位名称:paramurl:职位的详情页:return:"""returnTrue中间处理函数(handle.py)主要包含对请求的数据进行处理的函数及相应错误提示defget_data():获取所有页数的职位名称及职位URLdefget_job_explain():获取单个职位的详细信息msg={1:"获取成功",-1:"获取职位链接获取失败",-2:"获取职位详情失败"}classHandle(object):job=Job51()job_num=0#job总个数job_explain:Tuple[str,str,List[str]]=None#Job_name和url列表job_url_data:List[Tuple[str,str]]=list()def__init__(self,city:List[str],search:str):self.get_data(city,search)defget_data(self,city:List[str],search:str):"""#获取所有页数的职位名称及URL:paramcity:城市列表:paramsearch:搜索词:return:"""#获取职位详情链接whileself.job.page_num<=self.job.all_page:ifnotself.job.get_data(str(self.job.page_num),city,search):return-1self.job.page_num+=1#总Job个数self.job_num=self.job.job_url_data.__len__()self.job_url_data=self.job.job_url_datadefget_job_explain(self,job_name:str,job_url:str):"""#获取单个职位的详细信息:paramjob_name:城市名称:paramjob_url:城市url:return:"""job_url_data=self.job.job_url_dataself.job_len=job_url_data.__len__()ifnotself.job.get_job_explain(job_name,job_url):return-2self.job_explain=self.job.job_explainreturn1工具类模块(utils.py)只有一个写入结果的函数#文件写入deflog(msg:Tuple[str,str,List[str]]):withopen("msg.csv","a",encoding="utf-8")asf:f.write(f"{msg[0]},{msg[1]},{msg[2]}\n")主文件(main.py)主要启动文件,协程在这支持
函数传值如果函数只是传入变量值(不是数组),那么传入变量值的作用域只有该函数内部。#include<stdio.h>voidswap(intx,inty);voidswap(intx,inty){inttmp;//存储临时变量printf("swap传入值交换前x=%d,y=%d\n",x,y);tmp=x;x=y;y=tmp;printf("swap传入值交换后x=%d,y=%d\n",x,y);}intmain(){intx=111,y=222;printf("main传入指针互换前x=%d,y=%d\n",x,y);swap(x,y);printf("main传入指针互换后x=%d,y=%d\n",x,y);return0;}函数传址(指针)函数如果传入指针(地址),在函数内部改变指针,外部会跟着改变。#include<stdio.h>voidswapzz(int*x,int*y);/**交换数字*/voidswapzz(int*x,int*y){printf("swap传入指针交换前x=%d,y=%d\n",*x,*y);inttmp;tmp=*x;*x=*y;*y=tmp;printf("swap传入指针交换后x=%d,y=%d\n",*x,*y);}intmain(){intx=111,y=222;printf("main传入指针互换前x=%d,y=%d\n",x,y);swapzz(&x,&y);printf("main传入指针互换后x=%d,y=%d\n",x,y);return0;}函数传入数组函数传入数组,本质是传入一个指针。#include<stdio.h>voidget_arr(intarr[3]);voidget_arr(intarr[3]){inti;arr[1]=520;printf("get_arr方法内");for(i=0;i<3;i++){printf("%d",arr[i]);};}intmain(){intarr[3]={1,2,3};get_arr(arr);inti;printf("\nmain方法内");for(i=0;i<3;i++){printf("%d",arr[i]);}return0;}
函数定义格式返回类型函数名(参数类型参数变量){函数方法体}//定义函数intsum_num(intnum){intres=1;returnres;}函数使用#include<stdio.h>//首先声明函数(有些版本C语言,可以不用)intsum_num(intnum);//定义函数intsum_num(intnum){intres=1;//循环阶乘for(num;num>1;num--)res=num*res;returnres;}intmain(){intnum=10;//使用函数intres=sum_num(num);printf("%d的阶乘结果:%d\n",num,res);return0;}函数的可变参数使用可变参数需要引入:#include<stdarg.h>#需要#include<stdarg.h>头文件里面的这几个东西-va_list-va_start-va_arg-va_end定义可变参数之前的intnum,是可变参数的总长度一般这是实现原理#include<stdio.h>#include<stdarg.h>//声明函数intsum_num(intnum,...);//定义可变参数的函数intsum_num(intnum,...){/*该函数实现可变函数的值相加。*/inti,sum=0;va_listvap;//定义接收可变参数的列表va_start(vap,num);//开辟接收可变参数的空间num是可变参数的个数//利用循环取出可变参数for(i=0;i<num;i++){sum+=va_arg(vap,int);//判断参数逻辑}//关闭空间va_end(vap);returnsum;}intmain(){intres=sum_num(5,1,2,3,4,5);printf("相加结果:%d\n",res);}
常量常量一般这样定义://不加分号#defineLOVE520#defineA'a'#definePI3.14const修饰的指针变量const靠近谁就锁定谁,靠近*p,就锁定*p。intnum=520;intconst*p=##//锁定*p为只读,p能变int*constp=##//锁定p为只读,*p能变const修饰的指针变量有三种常见情况地址值能变,值不能变#include<stdio.h>intmain(){intnum=520;intconst*p=##//锁定*p为只读,p可变printf("p=%d\n",*p);//解引用指针变量,获取值p=(constint*)1314;//等价于p=1314;重新赋值printf("p=%d\n",p);return0;}地址值不能变,值能变#include<stdio.h>intmain(){intnum=520;int*constp=##//锁定p为只读,*p可变printf("p=%d%p\n",*p,p);//解引用指针变量,获取值*p=1314;//重新赋值printf("p=%d%p\n",*p,p);return0;}地址值&值都不能变实际中很少用到intmain(){intnum=520;constint*constp=##//锁定p、*p为只读return0;}
void指针viod指针称为通用指针,就是可以指向任意类型的数据,就是任意类型的指针都可以赋值给void指针。#include<stdio.h>intmain(){//声明不同类型的变量inti=123;char*c="ABC";//声明void指针void*v;v=i;//把int类型数据赋值给void类型数据printf("%d\n",(int*)v);v=c;//把char类型数据赋值给void类型数据printf("%s\n",(char*)v);return0;}NULL指针NULL用于给指针和对象,指向一个不被使用的地址,避免出现野指针(没有初始化的指针,而出现的随机值);而\0表示字符串的结尾。#include<stdio.h>intmain(){int*a;//野指针int*b=NULL;//作为指针变量初始化printf("%d\n",a);printf("%d\n",b);return0;}
问题在使用CLion编写C项目时,一个项目下如果包含多个C文件里有main函数,就会出现以下报错出现问题的原因在CMakeLists.txt文件里,所有包含main函数C文件,都共用了这个a,所有就会起冲突。解决使‘CMakeLists.txt’文件能自动给main函数文件起不同的名字,就完美解决CMakeLists.txt文件内容#遍历项目根目录下所有的.cpp文件file(GLOBfiles*.c*/*.c)foreach(file${files})string(REGEXREPLACE".+/(.+)\\..*""\\0"exe${file})add_executable(${exe}${file})message(\\\\--\src/${exe}.cpp\will\be\compiled\to\bin/${exe})endforeach()技巧#如果你只需要根目录下的test文件夹的所有.c文件file(GLOBfilestest/*.c)#如果你只有两层目录的话file(GLOBfiles*.c*/*.c)#同理,三层的话file(GLOBfiles*.c*/*.c*/*/*.c)#官方提供了一种递归的方法#这样在运行框会多一个CMakeCXXCompilerId,不过无伤大雅file(GLOB_RECURSEfiles*.c)
说明安装Win环境下运行C程序官网安装包地址:https://www.jetbrains.com/clion/download/other.htmlCLion2020.1地址:https://pan.bigdataboy.cn/#/s/vZsD破解包:https://pan.bigdataboy.cn/#/s/mYSB最好配合2020.1使用MinGW下载地址:https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/安装&配置正常下载安装CLion(最好是2020.1版本)配置MinGW下载MinGW网址:https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/进入后,不要直接点下载,往下拉,下载压缩包下载完成解压到某个目录配置CLion第一次安装CLion,会弹出如下窗口配置MinGW在CLion内配置MinGW安装完成破解使用时间拖入插件再次打开查看过期时间