




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C语言知识点复习C语言——只看这一篇就够了!数据类型用不同数据类型所定义的变量所占空间大小不一样,定义的变量不是保存于数据类型中,而是因为只有定义了该数据类型的变量才能保存数据。一、整型1、整型(int)四字节,默认有符号(-231-231-1),无符号加unsigned(0-232-1)(十位数);2、短整型(shortint),两字节(-215-215-1)(五位数);3、长整型(longint),四字节(同int,在目前的操作系统中几乎没有区别);4、长长整型(longlongint),八字节(-263-263-1),无符号(0-264-1);二、浮点型1、单精度浮点数(float),四字节,保留小数点后6位2、双精度浮点数(double),八字节,保留小数点后15位int为一个32为的存储单元,longlong为64为的存储单元1B/byte(字节)=8bit(比特)(位)1KB(千字节)=1024B/byte(字节)1MB=1024KB1GB=1024MB1TB=1024GB1PB=1024TB1EB=1024PB三、字符型char,用于储存字符,和int很像,可用ASCII码来储存字符,eg:chargrade=’A’;chargrade=65;''单引号为字符,eg:chara='a';""双引号为字符串,eg:char*a=“asd”;编译器会自动给字符串结尾添加’\0‘来作为字符结束标识,strlen函数中不统计\0,但是\0在内存中占据空间。除此之外,还有转义字符,通过反斜杠来完成相关操作,如果要特殊字符转字面字符需要另外添加反斜杠,转义字符在字符串中占空间,但是只计算一个长度,\0不计长度。四、变量和常量作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。生命周期:变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段#include<stdio.h>intglobal=2019;//全局变量intmain({intlocal=2018;//局部变量return0;}。分支及循环语句一、分支语句1、if语句语法结构:if(表达式)语句;if(表达式){语句列表1}else{语句列表2;}//多分支if(表达式1){语句列表1;}elseif(表达式2){语句列表2;}else{语句列表3;}。表达式部分为真则执行语句(0为假,非0为真),尽量在每个分支语句后都加{},否则只会执行分支后第一条语句。else在没有括号的情况下遵循就近原则所以在多重if语句嵌套使用情况下一定要加括号!2、switch语句switch作为分支结构常用于多分支的情况,可以简化多重if语句嵌套的情况。语法结构switch(表达式A){case常量表达式1:语句1;break;case常量表达式2:语句2;break;……case常量表达式n:语句n;break;default:语句n+1;break;}。其中1、case后第一句不可定义变量,必须跟常量或者常量表达式,并且不可相同;2、break在语句中可以起到划分作用,不可省略,否则无法实现分支功能;3、default语句不应该省略,一般推荐位语句列表末尾;4、switch语句结束条件:①遇到break;②执行到语句列表末尾。二、循环语句1、while语句语法结构while(表达式){循环语句;}注:在循环语句中break的作用是停止后期所有循环,continue的作用是终止本次循环,开始下一次循环的判断。2、for语句for(表达式1;表达式2;表达式3){循环语句;}表达式1为初始化部分,用于初始化循环变量,当表达式1为空时直接进入循环;表达式2为条件判断部分,用于判断循环是否终止,当表达式2为空时为死循环;表达式3为调整部分,用于循环条件的调整。注:建议使用“前闭后开”来限定区间范围。for(i=0;i<10;i++){a[i]=i;}3、dowhile语句do{循环语句;}while(表达式);循环体至少执行一次,while之后记得加分号。二分查找函数循环实现范例:intbin_search(intarr[],intleft,intright,intkey){intmid=0;while(left<=right){mid=(left+right)>>1;if(arr[mid]>key){right=mid-1;}elseif(arr[mid]<key){left=mid+1;}else{returnmid;//找到了,返回下标}}return-1;//找不到}。函数一、库函数C语言基础库中的函数,在添加头文件后可直接调用。二、自定义函数1、函数组成由函数名、返回值类型、函数参数以及函数体组成。实参:真实的传入函数的变量,**在被调用时会发生临时拷贝,并非把原来的变量直接放入函数中,**只是把实参的数据拷贝给形参。形参:函数名括号后的变量,因为形参只有在被调用的时候才被实例化并分配空间(形参实例化),**在被调用过后即被销毁,只在该函数中有效(局部变量),**所以叫形参。函数声明,要满足先声明后使用的原则,由返回值类型、函数名与函数参数组成(需要加分号),当我们用到很多函数声明的时候,为了方便我们的调用,我们可以创建一个头文件.h(比如test.h),将函数声明放在头文件当中,在写头文件时,要注意加上#pragmaonce。//函数定义doubleAdd(doublex,doubley){returnx+y;}//函数声明doubleAdd(doublex,doubley);2、函数调用函数也可以进行嵌套调用以及链式访问。嵌套调用样例:#include<stdio.h>voidnew_line({printf("hehe\n");}voidthree_line({inti=0;for(i=0;i<3;i++){new_line(;}}intmain({three_line(;return0;}。链式访问样例:#include<stdio.h>#include<string.h>intmain({chararr[20]="hello";intret=strlen(strcat(arr,"bit"));printf("%d\n",ret);return0;}。3、函数递归程序自身调用被称为递归,把复杂问题层层转化为与原问题类似的小问题,函数在调用自身的情况下存在不合法递归(即无限次的递归导致栈溢出)。所以在使用递归的时候一定要有递归出口,否则会陷入死循环导致栈溢出!**注:**栈结构为电脑存储的一部分,从高地址处向下开辟存储空间,与用于开辟动态存储空间的堆相向开辟(堆为从低地址出向上开辟存储空间),而函数调用将会形成栈帧,函数返回后自动释放栈帧结构,在此过程中,该函数定义的所有局部变量都在该函数的栈帧内进行空间开辟。样例:求n的阶乘intfactorial(intn){if(n<=1)return1;elsereturnn*factorial(n-1);}递归与迭代递归在使用过程中由于频繁进行函数调用,且每次调用都需要时间成本以及空间成本,所以递归程序简单,但是可能导致递归效率变低的问题,而迭代方案通过对变量值进行替换所以不会造成栈溢出,解决了效率低下的问题。样例(求斐波那契数列第n个的值)://递归实现intfibrec(intn){if(n<=2)retuen1;elsereturnfibrec(n-1)+fibrec(n-2);}//迭代实现intfibite(intn){intfir=1,sec=1,thd=2;if(n<=2)return1;else{while(n>2){fir=sec;sec=thd;thd=fir+sec;n--;}returnthd;}}。数组一、一维数组的创建与初始化创建数组时数组空间为整体开辟整体释放,在内存中是连续存放,在定义时就已经确定数组大小(下标不可为0),且不可被整体赋值。在数组的创建过程中,如果进行了初始化则可不指定数组的大小,多维数组按照一维数组进行理解。数组传参发生降维,降维成指向其(数组)内部元素类型的指针。数组名一般情况下都指的是首元素的地址,但如果sizeof(单独出现以及&后跟数组名时表示的是整个数组ints[5];//表示数组首元素地址printf("%d\n",sizeof(s+1));//结果为4/8,指针的具体大小根据编译器的不同大小不同//表示整个数组printf("%d\n",sizeof(s));//结果为20。二、数组传参(函数)由于在传参过程中如果拷贝整个指针会导致效率大大降低甚至导致栈溢出,所以数组传参要发降维问题,函数内数组作为参数时,实参为首元素地址,形参为指针。在访问结构体成员时也同样要发生类似的操作,用指向结构体的指针来指代结构体。typedefstructnode{inta;intb;}point;voidpop(int*p){}intmain({pointa;int*p=a;pop(p);return0;}。传参样例://用数组的形式传递参数,不需要指定参数的大小,传的只是数组首元素的地址。voidtest(intarr[]){}//也可以传入数组大小voidtest(intarr[10]){}//数组降维,用指针进行接收,传的是数组首元素的地址voidtest(int*arr){}//二维数组传参,第一个方括号可以空,但是第二个不可以空voidtest(intarr[][5]){}voidtest(intarr[4][5]){}//传过去的是二维数组的数组名,即数组首元素的地址,也就是第一行的地址,第一行也是个数组,用一个数组指针接收(比较少用)voidtest(int(*arr)[5]){}。三、字符数组chara[]={'a','x','d'};//此处由于结尾没有'\0',strlen的机制是遇到'\0'即停止,所以在结尾没有'\0'时为随机数//strlen(a)为随机数//sizeof(a)为3chara[]={'a','x','d','\0'};//strlen(a)为3//sizeof(a)为4char*a="axd";//或chara[]="axd"//直接通过""定义字符串时,会自动在结尾补'\0',不需要自行补充,但'\0'依旧会占据一个字节//strlen(a)为3//sizeof(a)为4charc[5]={'a','b','\0','c','\0'};printf("%s",c);//结果为ab,因为字符串结束标志位'\0'。操作符一、运算优先级注:①++/–高于解引用;②解引用高于±*/③±*/高于位运算;④位运算高于+=、-=、/=、*=;%操作两边必须是整数。二、二进制中的操作符1、位运算基本介绍与运算:&同1则1,否则为0;或运算:|同0为0,否则为1非运算:~1取00取1异或运算:^两者相等为0,不等为1移位运算操作符:<<左移;>>右移①**<<左移:**左边抛弃末尾补0;负数对反码的补码进行移位操作;相当于乘2;②**>>右移:有符号的补符号位**,无符号的补0;相当于除以2。2、反码与补码**反码:**正数的反码为原码本身,负数反码符号位不变,剩余的数字位取反;**补码:**正数的补码为原码本身,负数的补码为反码+1。三、隐式类型转换隐式类型转换的原因:参与计算的数据如果类型不同无法直接进行计算。整型提升:有符号的补符号位,无符号的补0(符号位为最外面的那位)样例:例题,求循环次数解答:unsignedchar8位数据位,范围在0-255,所以-2(11111110)时,变成254;同理-1(11111111)时,变成255;最后减到0时,不满足循环条件,for停止。刚好173次。(741==>共(7-1)/3+1=3次,1-3=-2,即254,继续循环)254251…52==>共(254-2)/3+1=85次(2-3=-1,即255,继续循环)255252…63==>共(255-5)/3+1=85次(3-3=0,退出循环)所以总共173次。指针指针变量是个变量,指针本身是个地址,用于存放内存单元的地址。指针时用来存放地址的,指针类型的变量无论指向目标是什么类型,指针本身在32位平台所占大小都为4个字节,在64位平台是8个字节。#include<stdio.h>intmain({inta=10;//在内存中开辟一块空间,左值为空间,右值为内容int*p=&a;//type*p//这里我们对变量a,取出它的地址,可以使用&操作符。//将a的地址存放在p变量中,p就是一个之指针变量。return0;}。一、指针的解引用1、对指针的解引用只能看到sizeof(type)个字节的数据;2、按字节为单位,数据有高权值和低权值之分,地址有低地址和高地址之分;3、数据低权值位在低地址处即为小端存储,反之则为大端存储。(“小小小”)二、野指针概念指向的位置是不可知的指针。规避1、指针在定义时就进行初始化;2、避免指针越界(eg:注意循环时循环次数的限制);3、指针使用完即进行指针指向空间释放;4、避免返回局部变量的地址;5、指针使用前检查其有效性。三、指针运算1、指针±整数,等价于±sizeof(type);2、指针-指针,两指针必须同一类型,一般用于数组与字符串求其两地址间相隔的单元格数,否则无效(指针+指针为非法操作);3、指针的关系运算。4、指针和数组都可以用中括号或者解引用(二者互通)。四、字符指针1、字符指针在指针的类型中我们知道有一种指针类型为字符指针char*;一般使用方法intmain({charch='w';char*pc=&ch;*pc='w';return0;}用char*指针指向字符串intmain({constchar*pstr="hellobit.";printf("%s\n",pstr);return0;}//上述代码中把字符串hellobit.的首地址放入了指针中。需注意字符串可以以字符数组的形式给出,但是此时的字符数组附有存储功能,而字符指针具有常量属性,指向的是常量区的内容,因此不可被修改,可以写作:constchar*str="helloworld";//从上图表示不可被修改也正因为这个原因C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。#include<stdio.h>intmain({charstr1[]="helloworld.";charstr2[]="helloworld.";constchar*str3="helloworld.";constchar*str4="helloworld.";if(str1==str2)printf("str1andstr2aresame\n");elseprintf("str1andstr2arenotsame\n");if(str3==str4)printf("str3andstr4aresame\n");elseprintf("str3andstr4arenotsame\n");return0;}。2、const知识点在此说一下const的一些知识点:①const修饰的变量不能被直接修改,但是可以通过指针在进行类型强转来修改(只是可以但是完全没必要);②const修饰指针,表示不可以通过指针来修改所指目标;③const能用则用,会很好的保护数据。const的作用:①写给编译器看,提前发现可能错误的修改;②写给程序员看,提示该变量不建议修改。constint*p=&a;*p=20;//错误,*p所指的值不可以修改p=&n;//正确,*p的指向可以修改int*constq=&m;*q=20;//正确,此时const修饰的是q,此时q所指向的值可以进行修改q=&t;//错误,由于const修饰的是q,此时的q的指向不可以进行修改constinta=10;//若consta=10,编译器也会默认为a是int类型的int*P=(int*)&a;//注意需要强制&a前需要加int*类型强制类型转换(&a的原本类型为constint*)*P=12;。五、指针数组指针数组本质上是数组,该类数组内存放的的元素是指针。int*arr1[10];//整形指针的数组char*arr2[4];//一级字符指针的数组char**arr3[5];//二级字符指针的数组六、数组指针1、数组指针定义指针数组本质上是指针,该类指针指向的是一个数组。example:int(*p)[10];//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针2、数组指针&数组首先需要看的是数组名与&数组名(可以等价于数组指针)之间的关系#include<stdio.h>intmain({intarr[10]={0};printf("arr=%p\n",arr);printf("&arr=%p\n",&arr);printf("arr+1=%p\n",arr+1);printf("&arr+1=%p\n",&arr+1);return0;}。根据上面的代码我们发现,其实&arr和arr,虽然值是一样的,但是意义应该不一样的。实际上:&arr表示的是数组的地址,而不是数组首元素的地址。(细细体会一下)本例中&arr的类型是:int(*)[10],是一种数组指针类型数组的地址+1,跳过整个数组的大小,所以&arr+1相对于&arr的差值是40。七、数组传参,指针传参1、一维数组传参数组传参会发生降维,最终传入的是首元素的地址(指针),并利用此来访问数组内其他元素。#include<stdio.h>voidtest(intarr[])//ok{}voidtest(intarr[10])//ok{}voidtest(int*arr)//ok{}voidtest2(int*arr[20])//不ok{}voidtest2(int**arr)//不ok{}intmain({intarr[10]={0};int*arr2[20]={0};test(arr);test2(arr2);}。2、二维数组传参二维数组传参,函数形参的设计只能省略第一个[]的数字。因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。voidtest(intarr[3][5])//ok{}voidtest(intarr[][])//不ok{}voidtest(intarr[][5])//ok{}voidtest(int*arr)//不ok{}voidtest(int(*arr)[5])//ok{}voidtest(int*arr[5])//不ok{}voidtest(int**arr)//ok{}intmain({intarr[3][5]={0};test(arr);}。3、一级指针传参需要传入一个地址#include<stdio.h>voidprint(int*p,intsize){inti=0;for(i=0;i<size;i++){printf("%d\n",*(p+i));}}intmain({intarr[10]={1,2,3,4,5,6,7,8,9};int*p=arr;intsize=sizeof(arr)/sizeof(arr[0]);//一级指针p,传给函数print(p,size);return0;}。4、二级指针传参#include<stdio.h>voidtest(int**ptr){printf("num=%d\n",**ptr);}intmain({intn=10;int*p=&n;int**pp=&p;test(pp);test(&p);return0;}。八、函数指针1、函数指针定义函数指针是指指向函数而非指向对象的指针。像其他指针一样,函数指针也指向某个特定的类型(特定的函数类型)。函数类型由其返回类型以及形参表确定,而与函数名无关。代码在电脑中同样占据内存空间,所以具有存储地址,而代码部分在电脑中也是不可被修改的类似字符串常量。在函数中,函数名单独时即为函数的地址(eg:main=&main),所以在用指针调用函数时,可以直接用指针调用不需要加*Type(*pFunc)(datatypeargs);//pFunc为函数指针,Type为数据类型,参数(datatypeargs)可以有多个,也可以没有。使用示例boolmax(inta,intb){if(a>b){returna;}else{returnb;}}voidTest({bool(*pFunc)(int,double);pFunc=max;cout<<max(5,10)<<endl;}。九、函数指针数组指针指向一个数组,数组的元素都是函数指针使用方法:把几个相同类型的函数地址放到一个数组中,这个数组就是函数指针的数组。十、回调函数解释:调用库中函数,但是库中函数需要编写程序时编写一个调用函数,该库中的函数为回调函数。也就是说一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数必须在中间函数以及回调函数同时具备时才可以实现。回调函数就是回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。结构体1、基本定义**注:**①结构体不可以自引用!但可以在结构体内定义该结构体类型的指针!②定义结构体本质是新增一种类型;③结构体传参要传结构体地址(指针),以此提高效率。structnode1{inta;intb;};typedefstructnode2{intc;intd;}node2;//通过typedef为结构体变量定义一个别名node2,在以后使用中可以使用别名以此提高编写效率intmain({structnode1s;//用结构体定义变量node2q;//用别名定义变量}。**注:**结构体不可以自引用!但可以在结构体内定义该结构体类型的指针!structNode{intdata;structNodenext;};//错误structNode{intdata;structNode*next;};//正确typedefstructNode{intdata;structNode*next;}Node;//正确。2、结构体变量的定义和初始化structPoint1{intx;inty;}p1;//声明类型的同时定义变量p1structPointp2;//定义结构体变量p2typedefstructPoint2{intx;inty;}p;pp1;pp2;。在定义结构体变量时,可以在初始化的部分定义其内容,也可以在之后定义。typedefstructPoint2{intx;inty;}p;pp1;p1.x=1;p1.y=2;//可以直接用结构体类型的变量进行定义typedefstructPoint2{intx;inty;}p;p*p2=(p*)malloc(sizeof(p));p2->x=1;p2->y=2;//定义一个指向结构体的指针并为其分配空间即可进行定义。3、结构体的内存对齐(结构体的占用大小的计算)结构体内存空间占用的大小并不是单纯的元素相加,而是通过浪费一定量的空间来换取目标数据读取速度的加快计算方式:①第一个成员在与结构体变量偏移量为0的地址处。②其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。(起始偏移量要能整除该成员的对齐数)对齐数=编译器默认的一个对齐数与该成员大小的较小值。VS中默认的值为8③结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。④如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处(即结构体大小),结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。样例:structS1{chara;intb;charC;};printf("%d\n",sizeof(structS1));char为1个字节,int为4个字节;chara从0偏移开始,占用一个字节;偏移量为1,接下来存放intb,偏移量1不是对齐数4的整数倍,所以向后继续偏移一直到4,4是对齐数4的整数倍,所以将intb存放在偏移地址为4处,占用4个字节;偏移量变为8,存放charc,占一个字节,偏移量9不是最大对齐数4的整数倍,所以向后继续偏移直到偏移处为12的地方。图示如下:自主设置默认对齐数#pragmapack(a)//通过该指令可设置默认对齐数为a位断位段的声明和结构是类似的,有两个不同:1.位段的成员必须是int、unsignedint、signedint或者char(同属于整型家族);2.位段的成员名后边有一个冒号和一个数字。structA{int_a:2;int_b:5;int_c:10;int_d:30;};注:①位段的成员可以是intunsignedintsignedint或者是char(属于整形家族)类型;②位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的;③位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段;④位断不需要考虑内存对齐问题所以较为节省空间。总而言之,跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。枚举即一一列举enumDay//星期{Mon,Tues,Wed,Thur,Fri,Sat,Sun//最后一个不加逗号};en
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 体位管理技术操作规程
- 大数据隐私保护合规合同与协议
- 仪器标签采购合同标准文本
- 秋季课外活动计划
- 房地产交易合同范文参考
- 中药采销合同标准文本
- 产品试用合同标准文本
- 代销垫资合同标准文本
- 中介佣金合同标准文本英文
- 员工注册管理制度
- 2025年模具师傅考试题及答案
- 计算机科学与技术毕业论文-基于Internet的网络教学系统
- 2025届福建省厦门市高三第二次质量检测地理试题(原卷版+解析版)
- 【课件】时间管理逆袭90分!课件-2025届高考倒计时90天主题班会
- 2025年安庆医药高等专科学校单招职业适应性考试题库新版
- 2025年学校师德师风培训课件:培育新时代好老师
- JJF1033-2023计量标准考核规范
- 《会计职业规划》课件
- 2025年春新人教版语文一年级下册教学课件 语文园地三
- 六年级数学下册-4.1.3 解比例
- 设计单位施工期间配合及技术服务措施
评论
0/150
提交评论