c语言笔记唐发根自学C语言笔记.docx
- 文档编号:11208887
- 上传时间:2023-02-25
- 格式:DOCX
- 页数:34
- 大小:1.28MB
c语言笔记唐发根自学C语言笔记.docx
《c语言笔记唐发根自学C语言笔记.docx》由会员分享,可在线阅读,更多相关《c语言笔记唐发根自学C语言笔记.docx(34页珍藏版)》请在冰豆网上搜索。
c语言笔记唐发根自学C语言笔记
C程序设计
在职研究生复习笔记
本书适合稍微有编码基础的人,主要是一个复习的纲要,可以根据他把握纲要,是北航在职研究生的考试教材---C程序设计(谭浩林)
hell
2011-12-20
一、算法
算法的定义:
广义、为解决一个问题而采取的方法和步骤;怎么做,做什么
1.算法的特性:
又穷性、确定性、有0个或多个输入、有一个或多个输出、有效性
2.算法的步骤通常用S1、S2。
。
。
来表示(step)
3.算法的表示:
Ø传统的流程图
连接点主要是针对多个流程、或流程过长而导致花了二个,其连接作用,如下图
流程表示法连接点用法
传统流程的缺点:
①线没有规范,比较乱、②箭头的指向也容易比较乱
ØN-S流程图表示法,又称“盒图表示法”就像盒子套盒子
即:
采用基本结构的顺序组合来表示,即不显示流程线
N-S流程图表示法
流程图表示法的缺点:
很好理解,但是不易修改。
所以有了伪代码表示法
Ø伪代码表示法(pseudocode)
可以用中文或英文来表示,没有特别的规定
4.算法的实现
以上都是算法的设计,本节介绍算法的实现,即用计算机语言,按照算法编写可执行的程序
①结构化程序设计方法、原则
Ø自顶向下
Ø逐步细化
Ø模块化设计
Ø结构化设计
二、C语言的数据类型、运算符与表达式
1.C语言的数据类型
以下是数据类型的结构列表
2.常量与变量
Ø定义常量
#definePRINCE30
Ø变量
C语言的变量必须是字母、数字、下划线组成,且第一个必须是字母或下划线。
Inta=1;TurboC为a分配2个字节
3.整型数据
Ø十进制123
Ø八进制0123
Ø十六进制0x123
1正数在内存中的存放形式
Ø正数的补码就是原码
Ø负数的补码是正数的原码+1
Ø由上可知,最左边的位是符号位,如果是1表示负数、如果是0表示正数
2整形变量的分类
Intshortlong可以标记为unsigned无符号数、signed有符号数,默认是有符号数(signed)。
符号数和无符号数代表在内存地址中会存符号位,那么,无符号数表示的范围是有符号数的2倍。
范围:
signed(-32768-32767)unsigned(0-65535)
123u是无符号数;
123是有符号数;
如果是-123u,则先将-123转化成补码,然后按无符号数存储。
3以下是turboC++中各个整型详细信息
4整形数据的溢出
32767+1的情况会是什么呢,见下边的例子。
4.浮点型数据(float、double、longdouble)
两种表现形式:
123.0(十进制形式)和1.23e2(指数形式)
以下是指数形式的内存存储形式
一个浮点数变量只能保证有效数字7位,后面的数字无意义,会自动截取的。
具体参照如下
5.字符型数据
注意\r、\b都是移动后输出替换原来的字符
Ø字符型变量:
chara=‘a’,在所有的编译系统中都规定一个字节来存放一个字符,那么是如何来存放的,即把对应的字符转化成ascII的数字后,存到这一个字节中,且默认是有符号的。
8位中有一个是符号位,那么就剩7为了,所以他的表示范围就是-128~127。
Ø字符串常量:
字符串和字符的区别,字符串的存法是和字符型存法一样的,只是用字符型数组来存的,而且最后再加一个‘\0’表示存储结束。
所以这个长度比正常的要多一个。
6.各个类型之间的混合运算
计算前会先换型,3+3.0=6.0,会把3先换成3.0的double型。
混合运算要特别注意各个类型之间转化,隐形的转化。
以下是转化的详情
7.算术运算符和算术表达式
下图是运算符列表
1算术运算符:
5/3=1取整后TurboC中先0靠拢,否则就是2了。
2强制类型转换:
(int)5.0%3=>5.0会被先转成5。
3自增自减运算:
Ø++i和i++的区别,写过代码的人都知道,先计算i=i+1后在使用i的值;注意i++的结核性是又结合型,从右向左结合的,不要晕了哦。
ØInti=3;intsum=(i++)+(i++)+(i++);打印出来之后值为9;对于这种极易导致混乱的方法不要使用,java中也是这样。
ØC语言编译时采用自左向右的顺序编译,即表达式i+++j=》(i++)+j;是等价的。
8.赋值运算符
1=的赋值作用
Ø注意赋值后的类型的隐式转换;
Ø赋值时数值范围不能溢出;
例如:
floatf;
Doubled=123.456789e100;
F=d;
这就溢出了,float只能控制7位。
Ø赋值时的补位低到高
Double付给float时,如下图,符号位保留(主要看原来变量的符号位是记了)。
Ø赋值时的补位高到低,就一个原则:
按存储单元的形式直接传送。
2复合的赋值运算符
A+=y+8=a=a+y+8;
3赋值表达式
Ø赋值看出赋值表达式可以作为左值a=b=5;相当于b=5、a=b;所以a=5;
(a=3*5)=3*4√
A=3*5=3*4×
因为赋值操作是从右向左操作的,3*4无法赋给3*5,这就是错误的,所以必须的加括号。
ØA=12;那么a+=a-=a*a;值是多少呢
A=a-a*a=12-144=-132;
A=a+a=-132+(-132)=-264
注意这个中间赋值的a=-132值后的改变
9.逗号运算符和表达式
逗号表达式主要用在for循环中,应该不陌生吧。
Ø注意区分逗号表达式和函数中的逗号哈;看下边的例子,(a,b,c)中的逗号是运算符,其他的是函数参数的逗号;
1Printf(“%d,%d,%d”,(a,b,c),b,c);
Ø逗号的运算级别中最低的,
1x=(a=3,6*3);x=18;
2x=a=3,6*3;x=3;但是整个表达式是18;
三、顺序程序设计
下图是C语言的程序的组成,这个图还是比较说明一些东西的。
语句的分类在这里就不介绍了,大部分人应该都知道了。
1赋值语句
If((a=b)>0)t=a;在面试中应该经常看到这个题,
先把b赋给a,然后a和0比较看起表达式的真假即可。
2输入输出函数
Putchar(输出字符)、getchar(输入字符)、printf(格式输出)、scanf(格式输入)、puts(输出字符串)、gets(输入字符串)
这些函数都在stdio.h的这个文件中,用时需要引用
#include“stdio.h”在TurboC2.0以后就不在需要引用了,默认有引用。
3格式的输出控制
Ø首先printf(“%3d”,1234),如果长度小于3,前面补一个空格;如果长度大于3,那么是什么输出什么;
Ø注意%o和%x的控制,是不可能输出负数的,如果是负数的话,不输出符号位,直接输出存的补码。
会是一个很大的数,然后把符号加上
Ø%u是输出unsigned无符号数的,对于负数存后的补码,直接输出,包括符号位,认为是无符号的数据
Ø%s是字符串
Ø%e按指数形式输出
以下是对上边总体格式的总结
4格式的输入控制scanf
Scanf(“%4d%4d”,a,b)
四、
选择结构程序设计
1、运算符的优先级
如:
C>A+B;
ØB==C(A>B)==C
Øa==b Øa=b>ca=(b>c) 2、逻辑运算符的优先级 3、条件运算符自右向左 4、Switch必须是ascII中的任意表达式,就不能是字符串了 五、循环 1、goto一般用法是从循环的外层 2、while先判断后循环 3、dowhile先循环后判断 4、for循环: 中的3个表达式都可以隐藏,但是要保留分号“;” #include"stdio.h" voidmain(){ charc='1'; for(;(c=getchar())! ='\n';){ printf("%c",c); } } Input: computer Outpurt: computer 5、Break只能和switch和for相结合 六、数组 1、C语言不允许对数组进行动态定义 2、只能一个个引用元素,不能一次性引用数组 3、A[]={1,2,3,4,5}; 4、A[10]={1,2,3,4,5};后边5个是默认是0. 5、气泡排序的示意图,如下: 6、chara[10]={'a','b','c'};对于没有赋值的默认为'\0';他不是一个可以显示的字符。 7、注意chara[]={'a','b','c'}和chara[]={"abc"}定义的不同之处, 8、Chara[]中a的引用代表数组的其实地址, Ø所以scanf("%c",a)中的a不需要加取地址符号 Ø对于scanf("%c",a)遇到空格和回车就会停止接受,例如howareyou? 那么实际上a[]={"how\0"}; Ø对于上述情况可以用gets函数来进行接受,就会只控制回车了,可以试一下。 9、字符串处理函数 ØPuts(s)输出,用的很少,因为printf("%s",s)就可以输出来 ØGet(s)输入,一般用来接受字符串,注意: puts和gets只能接受和输出只能针对一个 ØStrcat(str1,str2): 连接函数,str1=str1+str2,注意str1的长度一定要足够长,足够容纳str1+str2 ØStrcpy(str1,str2): 复制函数,把str2的内容赋值给str1,注意str1的长度一定要足够长,足够容纳str2,str1被赋值时容纳str2后,后面的字符是str1原来的字符(前提是str1[10],str2[5]指定长度)。 对于如下赋值错误: str1=str2;但是a[0]=a[1]复制时ok的 ØStrncpy(str1,str2,n): 把str2中的前几个字符复制给str1,注意问题同上 ØStrcmp(str1,str2): 字符串函数比较, ØStrlen(str1): 字符串长度函数,不算"\0" ØStrlwr(str1): 小写转换 ØStrupr(str1): 大写转换 C语言函数的总结: 库函数,非C语言的组成部分,而是C语言编译系统为方便用户使用的提供公共函数。 不同的编译系统函数名不同,变量不同,所以要注意。 七、函数 1、函数如果没有指定返回类型(void都没有指定),那么默认为int类型。 2、数组元素作为参数是传值的 3、数组作为参数,在函数中要指定数组的长度无所谓,这个长度是无用的,是以真正的实参为主的。 因为他只代表数组的首地址。 4、变量 Ø数组名作为函数的实参传递的是地址,数组名的首地址。 Ø从变量的作用域角度变量分为全局变量和局部变量 5、register变量 Ø区别: register变量是CPU的变量,运行速度更快;其他的变量都是从内存中取得的。 ØRegister只能用来修饰局部变量和形参 ØRegister的变量不能太多,是有个数限制的 ØRegister\static不能同时来用,不能又放到CPU中,有放到内存中,ok? Ø目前一些编译器就自动register的变量给判断了,不需要设计者自己判断,了解即可 6、extern变量 7、static内部变量和extern外部变量,内部引用和外部引用,默认为extern。 引用外部函数时,要在main函数或其他函数引用,要先声明 八、预处理命令 1、#definePI3.14159注意后边没有“;”如果有的话替换时会把分号也一起换了,宏的定义只是用来置换,不会有正确性检查的,所以是不会报错的,执行就不行了; 2、#undefPI可以终止PI对文件中下边的作用域;这样可以灵活定义宏的作用范围; 3、宏定义的层层置换 #definePI3.14 #defineR3.0 #defineSPI*R*R 以上就定义了一个圆的面积;利用宏层层置换的方法 4、宏的定义只是预处理命令的一个专有名词,他与变量名不同,只作字符替换,不分配内存空间 5、宏参数 #defineS(a,b)a*b 6、宏展开没有返回值,没有值传递,只是替换,可以设法得到多个结果;和函数时不一样的,可能使程序变长,这就是所谓的替换嘛;带参数宏是在编译前就已经处理的,不是在运行时;没有类型检查;宏只占用编译时间; 7、利用宏的常用方法是: 控制输入输出格式,在整个程序中,可以整体的控制。 如下图示例: 8、文件包含处理,把包含进来的文件代码复制到当前文件中,进行编译,生成新的编译文件,而不是利用已有的编译后的文件。 。 注: 由于这个原因,如果修改了被包含文件,那么这些文件都要重新编译。 Ok! ! 9、#include"stdio.h"或者#include 但是<>代表系统存放到C库函数的头文件中,这称为标准方式;而""系统先按当前用户来查找,如果没有找到在去C库函数的头文件中,所有标准方式会省一些时间! 10、下边两个图是等价的包含是等价的 11、有一种情况要考虑文件包含的顺序: 如file1包含file2,file2包含file3,而file2中没有include语句,这时。 。 在file1中要先引用file3,在引用file2。 12、Include文件之后,全局变量是有效的 9.3条件编译 1、在编译不希望都编译,满足一定条件才编译,语句格式如下: 语句可以语句组也可以是命令行,已经被定义过或声明过,即#define标识符 没有定义过的 语句表达式 2、实例如下: 实际用处,提高代码的通用性,更具系统和硬件的环境不同来定义int型的字节数 3、条件编译一般用的都是#define定义的变量,因为只有用他才算是编译前处理的工作,而且,他是控制环境的,所以用#define的宏才更合适。 10章指针 10.1地址和指针 1、指针的理解就是地址哦 2、区分指针和指针变量: 指针就是地址,指针变量就是存放地址的变量 10.2变量的指针和指向变量的指针变量 1、int*p,i。 。 。 。 p是指针变量,p=&i;定义指针时必须指定指针的基本类型;不同类型的地址不能放到int中 2、&去变量的地址*指针运算符,取其指向的内容;*和&优先级是相同的从右到左运算,如&*p=&i是一样的; 3、*p++;是先计算p++后在取值,但是由于p++是后加,所以,*p++取得是原来的值,但是p之后就++了,地址就不一样了; 10.2指针变量作为函数参数*******非常重要 1、指针变量作为函数参数时是把变量的地址传递过去,因为指针对应的就是地址,实际也是值传递,因为值就是地址,所以传的是地址,而且这个地址是指向变量的地址; 2、以下是值传递的示例,输入: 5,9,输出9,5;a和b的值互换了; *p实际就是间接引用a,因为他存的就是a的地址 注意在函数中用变量作为中间变量,不要重新定义指针 //-------------begin #definePRprintf voidmain(){ inta=5,b=9; voidswap(int*p1,int*p2); int*p1,*p2; p1=&a;p2=&b; if(a PR("%d,%d\n",a,b); } //p1穿过来的也是复制一份,只是对应的a不是,因为对应的是地址 voidswap(int*p1,int*p2){ //---tmp不要用指针哦 inttmp; tmp=*p1; *p1=*p2; *p2=tmp; } //-------------end 3、*p1=*p2和p1=p2的区别 *p1=*p2是把p1指向的变量的值改变,但p1所指向的变量不变,p1=p2,则是p1指向改变了,即p1不再指向原变量的地址,改为指向p2所指向的地址。 有人说*p1无论是在函数中还是在那,可以当做全局变量来用,指的是他指向的a,而且没有作用域的范围限制,牛人。 注意上面这段话,结合【2】中的程序来理解,很重要哦 10.3数组与指针 1、 Int*p; Inta[10] P=&a[0]<=>p=a<=>int*p=&a[0]两者等价,因为a代表数组的起始地址 2、p+1 *p(P+i)=a[i]=*(a+i)指向数组的第i个元素 P+i*d实际是这样计算地址的,你应该明白的 以下是指针方法打印数组 如果上边这个例子接受数组元素的时候,注意要重置p的位置,因为接受完p已经=a+10了,所以要设置p=a之后才能输出 10.3.3 数组元素前后位置互换 Inta[10]={0,1,2,3,4,5,6,7,8,9}; Intinv(a,10); 1、注意这里是怎么互换的,对于下面直接串的是数组,注意c的策略,数组就是数组的起始地址,可以理解为时传址的了 2、注意这里是如何互换的,用指针接受后,里面定义了3个指针,i代表从头的指针,j代表从后面的指针,p代表中间位置的指针,可以仔细阅读程序。 注意p定义之后一定要赋值,如p=arr;arr代表数组的其实位置,也可p=arr+2;总之是必须赋值的 3、指向多维数组的指针变量 Inta[][]是个二维数组。 可以把表格和图对照着来看。 注意*(a+0)=a[0]是第一行的起始地址,不是a[0][0],*(*(a+0)+0),*(a+0)+0,**a都是值0行0列的值 对于数组每次编译之后这个数组存的地址是不同的,因为会释放内存,下次就不一定分配什么了 对于下边这个例子不要大惊小怪哦,看到*p直接就输出值得,一定要注意现在p指的是谁,指的是a[0],这就相当于一维数组来使用了嘛,对于是**p的时候,p=a才是你想的那样哦。 Int(*p)[4]和int*p[4]的区别,前者是指向4个整形元素的一维数组(指向一位数组的指针变量),后者是指针数组,下面介绍前者p+1只是表示一维数组 Inta[3][4] Average(*a,12); 由于穿参数的时候传的就是*a,*a代表的是一维数组,就相当去传的就是a[0]了,所以在函数average中*p+3就相当与是a[0][2]了。 10.4数组与字符串 数组与字符串的关系可以从下边这个例子体现出来,chara[]=”Iamaboy.”;,printf(“%s”,a);注意打印的时候后面跟上指针的地址就行,printf(“%s”,p);。 就ok了。 注意复制数组的时候最后一定要加‘\0‘哦,注意’\0‘这是一个字符 10.7指针数组和指向指针的指针 1、指针数组 Int*p[]={“book1”,”book2”,”book3”}; []比*的优先级高,实际相当于二维数组了,但是二维的长度可变。 2、指向指针的指针 注意下面打印语句printf(“%s”,*p);这里的*p是地址,但是用%s,就把字符串打出来了 指针变量小结: 1)p++《==》p+c*I指的是加一个内存单元的字节 2)指针变量的赋值 注意p=1000是错的,分配地址也是不对的,只能将变量给p 3)指针变量的空值: p=NULL,p指向0单元,注意p=NULL和p未赋值的区别,一个是有值,一个是未赋值,直接使用是一个随机的内存地址的值 4)2个指针变量相减p2-p1是查看他们之间有多少个元素个数,注意这也是属于内存单元字节数的问题,例如1)中的阐述 5)2个指针变量的比较,p1 6)Void类型,可以定义一个指针类型,但不指定他是哪一种数据类型,使用的时候可以进行强制转换。 第十一章结构体 10.2结构体的定义 1、结构体定义: 一定要注意后边的分号;注意结构体中的成员和变量中定义的是不会冲突的 2、定义结构体变量 Structstudentstudent1,student2; 3、结构体的引用 1)结构体的输出 只能按照成员一个一个输出,不能将结构体变量直接输出 10.2结构体变量的初始化 10.2结构体数组和正常的数组使用是一样的 1)例如: stu[0].age 下面是自己写的一个简单例子,包括指针的使用 structstu { charname[20]; intage; }stu2={"yang",27}; voidmain(){ structstustu1[2]={{"liul",29},{"yang",27}}; structstu*p; //如果是变量的话应该是p=&stu2; p=stu1; for(inti=0;i<2;i++,p++) { printf("%s,%d\n",stu1[i].name,stu1[i].age); printf("\n"); printf("%s,%d\n",(*p).name,(*p).age); } } 2)(*p).age等价于p->agep->age代表p指向结构体变量中的age的值 3)结构体的成员中也是可以使用指针的,要不然如何利用结构体来实现链表这种结构体呢 10.7动态链表 动态链表虽然不考,但是个人认为还是挺不错的,可以学习一下 Malloc(intsize)分配一个size的字节长度,连续的 Calloc(intn,intsize)分配n个size的字节长度,连续的 Free(void*p)释放掉p指向的内存单元! ! 注: LEN=sizeof(structstudent);这就是字节数 常用p=malloc(4);这就指向了一个分配的空间,注意哦,链表的最后一个节点的指向地址是NULL 第十三章文件 13.2文件指针类型 下面图为文件结构体的定义,在stdio.h文件中,在其中你可以学到一个函数哦,typedef,自己看看是怎么回事吧 13.2文件的打开和关闭 1、打开 File*p=Fopen(“filename”,”r”);返回值NULL是异常 2、关闭 Fclose(p);返回值是EOF是-1异样 13.3文件的读写 1、fputc(ch,fp) 把一个字符写到磁盘中取。 2、fgetc(fp) 从文件里得到一个字符 注意: 这里有一个函数feof(fp)看看当前指针的位置。 是不是到文件尾部了。 不能直接用EOF来判断,因为是-1,文件可能就存了。 所以这样判断是有弊端的所以有了feof这个函数的价值 //复制in文件到out文件中 While(! feof(in)){ Fputc(fgetc(in),out); } 3、fread(buffer,size,n,fp) 从文件fp中读n个size字节到地址buffer中 阅读下面例子,你应该会明白的 for(inti=0;i<40;i++)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 笔记 发根 自学