C语言基础学习笔记.pdf

上传人:索**** 文档编号:85744082 上传时间:2023-04-12 格式:PDF 页数:34 大小:132.39KB
返回 下载 相关 举报
C语言基础学习笔记.pdf_第1页
第1页 / 共34页
C语言基础学习笔记.pdf_第2页
第2页 / 共34页
点击查看更多>>
资源描述

《C语言基础学习笔记.pdf》由会员分享,可在线阅读,更多相关《C语言基础学习笔记.pdf(34页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、C语言基础学习笔记(第一版修改)丁炳亮1 数据类型和表达式1.1 计算机数据存储方式理解与测试:什么是补码?我们得先知道模的概念。模“模”是指一个计量系统的计数围。如时钟等。计算机也可以看成一个计量机器,它也有一个计量围,即都存在一个“模”。例如:时钟的计量围是 011,模=12。表示 n 位的计算机计量围是02(n)-1,模=2(n)。“模”实质上是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数。任何有模的计量器,均可化减法为加法运算。例如:假设当前时针指向10 点,而准确时间是6 点,调整时间可有以下两种拨法:一种是倒拨4 小时,即:10-4=6;另一种是顺

2、拨 8 小时:10+8=12+6=6在以 12 模的系统中,加 8 和减 4 效果是一样的,因此凡是减 4 运算,都可以用加8 来代替。对“模”而言,8 和 4 互为补数。实际上以12 模的系统中,11 和 1,10 和 2,9 和 3,7 和 5,6 和 6 都有这个特性。共同的特点是两者相加等于模。二进制中整数的补码求法是:正数的补码为原码,负数的补码是符号位不变其他位全部取反再整个数加 1。我们可以通过下面的代码看下负整数在计算机部的表示。void f(int n)unsigned int i;for(i=1,i=1)if(i&n)printf(1);else printf(0);pri

3、ntf(n);main()int a=-0 xff;f(a);getch();输出的结果是 00001。1.2 变量与常量理解与测试:1)类型声明在计算机部数据是以字节为单位存储的,但是我们需要的数据类型有很多种,每种数据类型所占字节和存储方式都不一样。类型声明的作用就是告诉计算机以哪种“格式”去读写该数据数据。类型说明符变量名 1,变量名 2.,变量名 n;类型说明符有基本类型(字符型、整数型、单/双精度型)、高级类型(结构体型、共用体型、枚举类型)、指针型等,其中指针类型包括指向基本类型的指针类型、指向高级类型的指针型和指向函数的指针类型(指向函数指针声明格式在后面章节)。2)符号常量的定

4、义#define 标识符 常量;使用该种方法定义符号常量一个是可以使代码便于阅读理解,另一个是方便代码部多个相同常量的统一修改。总结与注意在写计算式的时候要考虑变量是否会越界。一般来说计算式子时是先强制转换成式子中最大存储空间的数据类型(不包括被赋值的变量),还要注意不同的类型数据在不同的编译器中所占的存有可能是不一样的,例如有些编译器整型是占2 个字节有些是占4 个字节。同时还要考虑到符号的优先级和结合顺序,如果按符号的优先级和结合顺序运算过程中有越界的那么整个计算结果可能和预想的不一样了,例如int i=100;i=500*i/i;最后 i=-155。1.3 输出输入理解与测试:1)格式化

5、输入输出函数可以按设定的格式和设定的数据类型接收和输出多个变量。控制格式和数据类型的是数据控制符。2)字符和字符串可以用专门的输出输入函数。主要有 getch();putch();getchar();putchar();gets();puts();其中 getch()和 putch()是 conio.h 中声明,getch()不需要等待回车键就返回字符并立即执行下面一语句符,getch()不在屏幕显示输入的字符。getchar();putchar();在 stdio.h 中声明。getchar()读取键盘上的一个字符,立即返回并显示在屏幕上,需要等待回车键才能执行下一条语句。例如下面的代码:i

6、nt main(void)char ch,i;for(i=0;i10;i+)ch=getchar();putchar(ch);getch();输入:I LOVE YOU 输出:I LOVE YOU 总结与注意格式输入函数中的参数是变量存放的地址,所以变量前面要”&”符号。如果是数组则可以直接用数组名,因为数组名就是指向该数组首地址的指针常量。1.4 运算符号理解与测试:1)表达式中符号的运算顺序是有先后的,根据符号的优先级和结合性(左结合/右结合)来判定。如果是几个符号连在一起C 部是怎么去读的呢?有一个很简单的规则:每一个符号应该包含尽可能多的字符。也就是说,编译器读取符号的方法是,从左到右

7、一个字符一个字符地读入,如果该字符可能组成一个符号,那么在读入下一个字符,直到与下个字符组合成的符号没有意义为止。例如:a-b;这个表达式等效于(a-)-b;2)复合赋值符及表达式在赋值符“=”之前加上其他双目运算符号可以构成复合赋值符。如:+=、-=、*=、/=、%=。构成复合赋值表达式的一般格式为变量双目运算符=表达式等价于变量=变量运算符表达式可以这么去理解,等号左边的相当于变量自增、自减、自除、自取余一个数,这个数由右边的表达式计算得到。如:int a=7,b=3,c=3;a+=b+=c+=5;运算后是 a=18,b=11,c=8。3)C 中唯一一个三目运算符是条件运算符,由“?”和“

8、:”构成。两个符号必须按下面的格式一起使用:表达式 1?表达式 2:表达式 3 三个表达式可以是任意的合法表达式,条件运算符的运算规则如下:如果表达式1 的值为真,那么整个表达式的值为表达式2 的值,否则为表达式3 的值。4)sizeof()也是一个运算符号,它可以对一个数据类型或一个变量取类型长度。但是当一个数组名作为一个实参传递给函数时,在函数部是不能用sizeof 来获取该数组的长度的。因为数组名是一个指向数组首地址的指针,使用sizeof 只能取得实参指针类型长度。5)比较少用到的符号是“:”和“,”。冒号运算符在C 中有三种用途,第一种是我们上面讲到的与“?”构成三目运算。第二种是在

9、switch 中放在常量表达式后面。第三种用法是在结构体中定义位域时用到。struct 位域结构名 位域列表 ;其中位域列表的形式为:类型说明符位域名:位域长度例如:struct bs int a:8;int b:2;int c:6;逗号运算符的功能是把两个表达式连在一起组成一个新的表达式,称为逗号表达式。其一般格式为表达式 1,表达式 2,表达式 3,.,表达式 n;其求值过程是自左向右求两个表达式的值,并以最后一个表达式的值作为整个逗号表达式的值。例如 for(a=0,b=0,c=0;b10,a20;b+,a+)+c;运算后 c=20,如果把中间的两个语句前后调换 for(a=0,b=0,

10、c=0;b10,aj?i+:j;printf(%dn,n);getch();输出结果:2 4 3)在写式子时要注意运算符号对变量的副作用,单目运算有“+”和“-”,双目运算有“=”。4)位运算符号与逻辑符号容易混淆的有“&”和“&”、“|”和“|”、“”和“!”。前面两个可以这么记,位运算是单个的所以符号也是单个的。5)在使用位运算符号时要主要如果是有符号数则是对他们的补码执行位运算。对于有符号的整数型使用左移“”左补 1。如下代码:void f(int n)unsigned int i;for(i=1,i=1)if(i&n)printf(1);else printf(0);printf(n)

11、;main()int a=-0 xff;f(a);a=1;f(a);getch();输出的结果是:00001 00000 6)运算符优先级可以简单归纳如下几点:单目运算符比任何一个真正意义上的运算符的优先级高。逻辑运算符比关系运算符优先级高。移位运算符表算术运算符优先级低,但高于关系运算符。2 程序控制结构2.1 选择结构理解与测试:使用 if-else 多层嵌套时 else是与上面同一层的最近if 相结合的,在程序设计时有过多的分支最好要选择使用if-else,当然如果可以使用switch 语句还是尽量选择switch 语句或者使用其他能使代码简洁易懂的方法。如下面的代码:main()int

12、 a=10,b=6,c=7,d=8,e=9,f=10;if(ab)printf(%dn,a);if(bc)printf(%dn,b);if(cd)printf(%dn,c);if(de)printf(%dn,d);if(ef)printf(%dn,e);else printf(%dn,f);getch();这种代码又长又难看懂,更要命的是经常搞不懂下面的大括号对应上面的哪个大括号。改进后的代码如下main()int a=10,b=6,c=7,d=8,e=9,f=10;while(1)if(a=b)break;printf(%dn,a);if(b=c)break;printf(%dn,b);if

13、(c=d)break;printf(%dn,c);if(d=e)break;printf(%dn,d);if(e=f)printf(%dn,e);else printf(%dn,f);break;getch();第二种方法比第一种方法来看上去更干净,理解上差不了多少。2)总结与注意switch 语句中每一个分支结束都要有break;语句,如果没有是继续执行下面分支,可能会得到和预料不同的效果。还要注意,case后面跟的一定是整数型或符号型常量表达式,不能是变量,并且不用有相同值的变量表达式,不然会矛盾的。2.2 循环结构理解与测试:1)主要有 for、while、do-while 这三种结构循

14、环体,其中最后一种是比较少用到的,因为一般情况都可以用前面两种替代。2)循环体结构中括号的表达式要知道时候退出,有时候还要知道循环体运行多少次。在循环体部也可以使用continue 语句跳过本次循环,进入下一次循环,或者用break 语句退出当前层循环。总结与注意循环结构中表达式的设计很重要。在for 循环结构我们经常用到从0 到 x,循环体执行x+1 次,可以写成 for(i=0;i0;i-=3);这个循环语句的运行结果一般不是我们想要的。把“=”不注意写成“=”也是容易造成死循环的结果。3 数组3.1 一维数组理解与测试:1)一维数组的定义如下:类型说明符数组名 常量表达式 如果定义时就进

15、行初始化,常量表达式可以省略。动态存储的数组没有初始化所有元素的值都为随机。静态存储的数据没有初始化所有的元素自动赋0。2)一维数组名是一个指针常量,指向数组的首地址。由于是指针常量所以不能对其赋值,只能当指针引用。同理一个数组不能对另一个数组整体赋值。数组引用时下标是从0 开始计算的。3)字符型数组初始化可以直接赋值字符串。char s=“Happy”;或者 char s=”Happy”;。总结与注意数组引用时下标不要越界,字符串数组初始化时,数组元素个数要比字符串多一个,因为字符串结束有个“n”符,否则越界就会发生预料不到的结果。如下:main()char a8=abcdefgh;prin

16、tf(%s,a);getch();输出结果:main()int a2,i;for(i=0;i8;i+)scanf(%d,&ai);getch();上面这个代码当输入字符超过2 个时可能出现无法运行的结果。总结与注意数组名作为函数参数时传递给形参的是数组的指针,而且在子函数中无法用sizeof 取得数组的大小,所以有需要时可以用另一个参数传递数组的大小。数组作为形参时可以写成int f(int a)或者 int f(int*a)或者 int f(int a10),他们三者都一样的,因为对于指针来说“”等效于“*”,数组做形参不会传递数组大小,int a10 等效于 int a。数组作为实参时可以

17、写成f(a)或者 f(&a0)或者,因为 a0的地址就是数组的首地址。但是要注意f(a10)将是把 a10作为实参传递过去,a10的值赋值给指针使用是危险的。3.2 多维数组理解与测试:多维数组和一维数组相似,只是使用了多个下标。多维数组其实可以理解为数组的元素又是一个数组。例如,二维数组可以保存一个矩阵,三维数组可以保存多个矩阵。4 函数4.1 函数的定义和调用理解与测试:1)函数定义一般格式如下函数类型函数名(形参表)声明部分;语句部分;return 表达式;声明部分必须是放在函数的最前面,如果放在语句中则编译不能通过。2)值参数是指,将实际参数的值传递到函数的形式参数中,这也是参数默认传

18、递方式。函数调用中发生的数据传递是单向的,即只能把实际参数的只传递给形式参数,在函数调用过程中,形式参数发生改变,而实际参数中的值不会发生变化(形式参数可与实际参数同名)。引用参数是将实际参数的地址传递给函数的形式参数。总结与注意1)形参必须是变量,用于接收实参传递过来的值。实参可以常量、变量、表达式、函数调用等,无论实参是何种类型的量,在函数调用时都必须有确定的值。实参与形参,数量和类型要能一一对应。2)函数如果在定义前使用,或者在其他文件中。那么必须先声明,再使用。函数运行的时候是根据形参类型去读写形参变量的,而传递过来的实参会根据函数声明里的形参类型进行类型转换。如果声明的函数没有形参列

19、表则传递的实参无法进行类型转换就直接把代表实参的二进制码直接复制给形参。如果实参和形参的数据类型不对,而函数运行时又是根据自己的形参类型去读取形参变量的,所以就会发生读取出错,严重的会使程序停止。声明返回值类型是把数据自动转换成相应的类型才返回给调用者。声明函数的返回值和定义函数时的返回值不一样编译时会提示类型出错。在使用前没有声明或者声明的函数没有声明返回值则编译时默认的返回值都是int 型,若该函数定义时声明的返回值不是int 型,编译器就也会提示类型错误。3)大多数 C 语言实现都是通过函数main 的返回值来告诉操作系统该函数是否执行成功。一般是返回 0表示成功,返回其他值则表示失败。

20、如果 main 中没有 return 0;返回的是一个 int型数值,但是不能保证值为0。4.2 局部变量和全局变量理解与测试:1)全局变量也叫外部变量,它是定义在函数外部。它不属于那个函数,而属于一个源程序文件。局部变量是定义在函数部,可以在函数的声明中定义,也可以在一个语句块中定义。变量的作用围都是相对于同一层次来讲的。例如函数有声明变量,在函数的语句块又有定义相同名称的变量,则起作用的是语句块的变量,虽然它们名称相同但是互不影响。如下面的代码:int k=10;void f(int i)int k=i;k+;printf(%dn,k);main()int k;printf(%dn,k);

21、f(10);for(k=0;k1)分析:像这种有递推公式的就有很明确的递推关系。我们的目的是要求n!,我们只需要两步,第一步是把n!看成 n*(n-1)!。第二步求(n-1)!。由于 n!和(n-1)!都是求某一个数的阶乘,所以调用函数本身来处理(n-1)!。我们的思路知道此为止,不要在一直想下面怎么处理,程序会按我们这思路自己往下递推的。程序设计:f(int n)一、if(n=1|n=0)n!=1;/设计边界二、n!=n*f(n-1);/利用跟被包含的下一个同概念函数计算/这里千万不要感觉f()没有写完就不能用,其实递归函数方便的/就可以随便大胆的调用“自己”。代码如下:double fac

22、t(int n);double fact1(int n);main()int n;printf(Input n:);a 蓝颜色矩形b 蓝颜色矩形c 蓝颜色矩形d 蓝颜色矩形e scanf(%d,&n);printf(%d!=%.0fn,n,fact(n);printf(%d!=%.0fn,n,fact1(n);getch();double fact(int n)double f;if(n=1|n=0)/递归函数出口f=1;else f=n*fact(n-1);return f;汉诺塔问题:分析:要把 A 上的 n 个盘借助 C 搬到 B 上,我们的只需要两步。第一步是把n-1 个盘搬到 C 上

23、,再把 A 上的最后一个盘搬到B。第二步是把 C 上的 n-1 个盘借助 A 搬到 B 上。由于把 n 个盘和把 n-1 个盘的规律相同,所以可以直接调用函数本身。代码如下:void hanio(int n,char a,char b,char c);main()int n;printf(Input the number of disks:);scanf(%d,&n);printf(The steps for%d disks are:n,n);hanio(n,A,B,C);getch();void hanio(int n,char a,char b,char c)if(n=1)/*递归函数出口

24、*/printf(%c-%cn,a,b);else hanio(n-1,a,c,b);/*利用 C 把 n-1 个片从 A 移到 B*/printf(%c-%cn,a,b);hanio(n-1,c,b,a);/*利用 B 把 n-1 个片从 C 移到 A*/九连环解法:分析:我们这边设计是可以解n 连环的程序。九连环有个规律是要解或上第n 个环必须解去 n-1 个环。我们解 n 个环只需要分成两步来处理,第一步就是把解下1 个环。第二步就是把剩下 n-1 个环用解 n 个环的函数来处理。解一个环的过程是些解下n-2 个环,再把第n个环解下,再安上n-2 个环(剩下部分要都是未解开的环)。安n

25、个环的步骤过程和解n 个环的步骤过程相似。代码如下:#include Stdio.h#include Conio.h static int upstep=0;static int downstep=0;void UpRing(int n);/*加上函数说明,否则编译将会出一点小错误*/void DownRing(int n)/*下环的逻辑就体现在这里*/if(n2)DownRing(n-2);printf(DW:%dt,n);+downstep;if(n2)UpRing(n-2);if(n1)DownRing(n-1);void UpRing(int n)/*上环的逻辑则体现在这里*/if(n

26、1)UpRing(n-1);if(n2)DownRing(n-2);printf(UP:%dt,n);+upstep;if(n2)UpRing(n-2);main()int n;scanf(“%d”,&n);puts(Starting.);DownRing(n);puts(nEnding.);printf(nup=%dtdown=%dn,upstep,downstep);getch();4)迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法,即一次性解决问题。迭代法又分为精确迭代和近似迭代。“二分法”和“牛顿迭代法”属于近似迭代法。迭代法的思路和递推法相反,迭代是

27、从开始往后面推导。例如计算n!用迭代法如下:double fact1(int n)double f=1;int i;if(n=0)return 1;else for(i=1;i=n;i+)f=f*i;return f;总结与注意1)用递归法的步骤是:一、把一个事物截去一部分剩下的的部分还是不是该事物如果是就可用递推函数来求解。二、找到截去一部分(剩下的概念上还是该事物)的方法。三、需要把事物截取成多部分函数实现就可以分成两步,首先是用上面的方法把事物截去一部分,最后就是把剩下的部分用这个截去多段事物的函数本身处理。2)递归函数的运行是一个不断递推的过程,每一次递推都要把数据压入栈,如果递推的步

28、骤过多可能就会使栈溢出。所以能用迭代尽量用迭代,一般来说能写出递推式的都可以用迭代。double fact1(int n)double f=1;int i;用 if 设定递归出口截去事物的一部分递归函数F 剩下部分用F 处理if(n=0)return 1;else for(i=1;i=n;i+)f=f*i;return f;5 指针5.1 指针与简单变量理解与测试:简单的讲指针就是地址。指针变量的定义如下:基本类型*指针变量名;指针定义完最好都进行初始化,初始化值可以为NULL。因为没有初始化的指针指向的地址时随机的,如果程序有引用是很容易出错的。总结与注意指针变量指向变量的首地址,指针引用指

29、向的变量时是根据自己的类型来取变量值的,所以不能将不同类型的变量赋值个同一个指针,例如把一个整形指针赋值个符号指针,引用符号型指针指向的变量时只是整形的低字节。5.2 指针与数组理解与测试:1)数组名就是一个指向数组首地址的指针常量。对于指针数组符号 相当于指针符号*,所以数组元素的地址有下面几种表示:&a0.&ai a.a+i pa.pa+i 从技术上可以说数组就相当于指针,但是在声明一个数组,C 语言编译时会分配一段固定的连续空间,而声明一个指针却不会。2)实际上 C 语言只有一维数组。多维数组其实可以理解为指针数组和普通数组的结合。例如,char a25;可以理解为一个char*a2数组

30、,里面的每个元素分别指向一个char b5数组。在二维数组 x 中,数组名 x 表示数组的首地址,xi 表示一个一维数组的名称,(也就是说 xi 不保存元素值),它只是一个地址。x 和 xi 的值相等,但是*a!=*a0,因为 a 是一个二维数组首地址指针,a0一个一维数组首地址指针,引用它们指向的变量时会根据自己类型性质定义变量的类型性质。如下代码:void main()char a26=Hello,World;char*p;p=a;if(a=a0)printf(a=a0n);if(*a=*a0)printf(*a=*a0n);if(*p=*a0)printf(*p=*a0n);printf

31、(%dn,sizeof(a);printf(%dn,sizeof(a0);getch();运算结果:a=a0*p=*a0 12 6 xi 表示数组的首地址,xij 表示数组 xi 的第 j+1 个元素的值,&xij 返回数组 xi 的第 j+1 个元素的地址。也可以使用*(xi+j)的方式表示第 j+1 个元素的值,而*(xi+j)又可表示为*(*(x+i)+j)。3)指针的运算:赋值、间接运算、求地址、递增、递减、求差、比较。指针加上后减去一个整数偏移的长度等于这个整数乘以指针所指数据类型的长度。如下面的代码:int main()unsigned int i;unsigned int*p=&

32、i;printf(%d%d,p,p+1);getch();运行输出:-58-56 5.3 指针与字符串理解与测试:1)在 C 系统部字符串当作一个一维数组,在存中连续存放。结尾存放字符串结束符,就是 ASCII 码为 0 的空字符 0,所以字符串常量实质上是指向该字符串首字符的指针常量。如 char*p=“point”。数组名就是存放数组的首地址,如char sa=”array”;。2)因为字符串名就是指针常量,使用指针数组来存放字符串指针常量可以方便操作多个字符串。由于数组名也是一个指针常量,所以指针数组名是一个指向指针的指针,可以用“*”来读取他被指向的变量。例如下面的代码:void ma

33、in()char*a2=Hello,World;printf(%sn,a0);printf(%cn,*a);getch();输出的结果是:Hello H 3)字符串出来函数主要有输入输出函数:scanf(),printf(),gets(),puts。专门字符串出来函数:strcpy(目的字符串,原字符串),目的字符串是字符串指针,原字符串可以是字符串指针也可以是一个字符串常量。strcat(目的字符串,原字符串),把原字符串中的字符串连接到目的字符串中字符的后面,并删去原字符串后面的字符串结束符。本函数返回的是目的字符串的首地址。strcmp(字符串 1,字符串 2),按 ASCII 码顺序比

34、较两个字符串,字符串1等于字符串 2返回 0,大于返回 1,小于返回-1。strlen(字符串),计算字符串长度,不包括结束符。4)输入命令时,在可执行文件(命令)名的后面可以跟一些参数,这些参数被称为命令行参数。主函数 mian(int argc,char*argv);有两个参数,第一参数argc接受命令行参数(包括命令名)个数。第二个参数argv是个指针数组,接受以字符串常量形式存放的命令行参数(命令名本身也作为一个参数)。例如下面的代码(文件名:test.exe):int main(int a,char*v)int k,s=0;for(k=1;k”运算符来访问其成员,这边其实是访问结构体

35、指针所指向的结构体的成员,因为结构体指针也和其他变量的指针相似,指向的是结构体存储单元的首地址。结构体指针引用成员的一般格式如下:结构体指针-成员名 或(*结构体指针).成员名总结与注意结构体类型与结构体变量是不同的概念,不要混同。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型时不分配空间的,只对变量分配空间。6.2 结构体数组理解与测试:结构体作为一种数据类型也可定义数组,用结构体定义的数组每个元素都是一个结构体变量。结构体数组的定义、引用和普通结构体变量相同。总结与注意在测试的过程中发现使用结构体数组存在下面问题:int main()int i=0;stru

36、ct student float grade2;st2=1,2,1,2;scanf(%f,&sti.grade0);printf(%f,sti.grade0);getch();运行后窗口只是一闪下。如果在scanf();不要用变量作为数组下标程序可以正常运行。这应该是 scanf();语句的一个 bug。6.3 链表理解与测试:1)动态存分配函数:void*mallo(unsigned size)在存的动态存储区中分配一连续空间,其长度为size。成功,返回指向存空间首地址的指针。失败则返回NULL。返回类型(void*)是通用指针的一个重要用途。void*calloc(unsigned n,

37、unsigned size)在存的动态存储区中分配n 个连续空间,每一存储空间长度为size,分配后把存储块里初始化为 0。成功,返回指向存空间首地址的指针。失败则返回NULL。void free(void*ptr)释放有动态存储分配函数申请到的整块存空间。void*realloc(void*ptr,unsigned size)更改以前的存储分配。失败返回NULL。成功返回指向分配到的存储块首地址指针。更改后如果 size 小于原块大小,则容为原块前size围的数据,如果新块更大,则原有数据存在新块的前一部分。更改成功后不要再用原来的指针去操作存储块。1)链表是一种动态分配存储单元的结构。链表

38、由若干个节点构成,每个节点具有相同的数据类型,并且每个节点都有一个可以指向下一个节点的指针(指针域)。因此线性链表不需要连续存放。2)链表的基本操作有:建立、查找、插入、删除、输出等。下面具体介绍各操作。建立:定义变量 head、tail、pnew。head:定义一个头指针作为头结点;tail:定义一个尾指针作为尾结点;pnew:定义一个指针,代表新插入的结点。链表的建立是一个从无到有的过程。因此head=NULL;tail=NULL;新申请结点pnew=(struct linknode*)malloc(sizeof(struct linknode)/分配存/执行后都要判断 pnew是否为空。

39、pnew-no=1;或者 scanf(“%d”,&pnew-no);/设置数据域pnew-next=NULL;/没有指向下个结点建立链表的示代码如下:struct linkonde*Create()struct linkonde*head=NULL,*tail=NULL,*pnew;int no;float score;while(1)printf(input the new no and score:n);scanf(%d%f,&no,&score);if(no=0)/学号为零时退出 break;pnew=(struct linkonde*)malloc(sizeof(struct link

40、onde);if(pnew=NULL)printf(no enough memory!n);return(NULL);pnew-no=no;pnew-score=score;pnew-next=NULL;if(head=NULL)head=pnew;else tail-next=pnew;tail=pnew;return head;查找:示代码如下:struct linkonde*Search(struct linkonde*head,int n)int i=1;struct linkonde*p=head;for(p=head;p!=NULL;p=p-next,i+)/空指针指用间接运算符号

41、运算得到的是0 if(i=n)break;if(inext=p-next;p-next=r;删除:链表删除的时候遵循先接后删的原则。下面为示代码:void Delete(struct linkonde*p)struct linkonde*q;q=p-next;p-next=q-next;free(q);输出:下面为示代码:void Display(struct linkonde*head)struct linkonde*p;for(p=head;p!=NULL;p=p-next)printf(Num:%d,Score:%.2fn,p-no,p-score);总结与注意动态存分配为了保证是成功的

42、,执行完要判断返回值是否不为NULL。6.4 共用体理解与测试:共用体和结构体的区别就是共用体的成员使用的是同一段存空间。共用体定义用的关键字是 union。共用体的定义、引用都和结构体相似。需要注意的是共用体一次只能对一个成员变量进行赋值,多次赋值只有最后一次赋值的共用体成员的值有效,之前赋值的成员值将被覆盖。需要不同时用多个不用类型变量,使用公共用体可以节省存储空间。6.5 枚举类型理解与测试:定义一个枚举类型相当于定义了一个数组常量,每个元素都可以由我们自定义一个名称。枚举类型的定义和结构体类型定义相似,使用的关键字是enum。同样也可以定义枚举数组、枚举指针等。例如:enum week

43、daysun,mou,tue,wed,thu,fri,sat;enum weekday a,b,c2=sun,mou;enum weekdaysun,mou,tue,wed,thu,fri,sata,b,*c=&a;enumsun,mou,tue,wed,thu,fri,sata,b,c;总结与注意1)枚举值(枚举元素)是常量,在程序中可以作为普通常量使用。枚举元素本身有系统定义了一个表示序号的数值,从 0 开始顺序定义 0,1,2.如果在定义枚举类型时指定元素的值也可以改变枚举元素的值。例如:enum weekdeysun=7,mon=1,tue,wed,thu,fri,sat;其实枚举变量

44、就是整数型变量,可以当成整数型变量使用。逻辑上讲要把一个整数赋值给枚举变量应该使用强制类型转换。如:day=(eunm weekday)2;但实际很多编译器直接就把枚举变量视为整型变量。2)在需要使用多个常量时可以使用宏定义也可以定义一个枚举类型,根据自己的需要修改枚举元素的值(只能是正整数)。6.6 自定义类型理解与测试:1)C 语言允许给已有的数据类型起一个别名。一般格式如下;typedef 已有类型名别名为了区分起见,别名一般采用大写字母。2)使用#define 宏定义给数据类型取别名一般是基本的数据类型,对于像结构体这种高级变量类型就不方便了,所以结构体等高级变量类型一般使用typed

45、ef 定义别名。6.7 预处理命令理解与测试:1)C 语言的预处理命令包括:宏定义、文件包含、条件编译、以及其他预处理命令。2)宏定义是用自定义字符串替代程序中的字符。分为不带参数和带参数两种。不带参数宏定义一般格式如下:#define 标识符字符串标识符也称为宏名,字符串也称为宏体,宏体可以省略,例如,编译头文件省略宏体。在预编译的时候把程序出现宏名的地方都用后面的宏体替代。对于宏体中有参数的我们就可以使用带参数的宏定义,一般格式如下:#define 标识符(参数表)字符串3)宏定义可以放在程序中的任何一行,需要终止宏的作用域可以用#undef。格式为:#undef 字符串4)”#”可以将一

46、个宏参数转换成字符串字面量。”#”运算符可以将两个记号(例如标识符)“粘”在一起成为一个记号。例如下面的代码:#define PRINT(a,b)(printf(%#an,(b)#define GENERIC_MAX(type)type type#_max(type x,type y)return xy?x:y;GENERIC_MAX(int);/*定义一个两数值比较大小函数,返回值为整型*/GENERIC_MAX(float);/*定义一个两数值比较大小函数,返回值为单精度型*/main()int i=5,j=4;float a=5.3,b=6.5;PRINT(d,int_max(i,j);

47、PRINT(f,float_max(a,b);getch();运行输出:5 6.5 5)文件包含有两种格式。使用“”是直接到系统指定的”文件包含目录“查找被包含的文件。使用“”是先到当期目录下查找被包含文件,如果没有再到系统指定的”文件包含目录“查找。一般使用双引号比较保险。双引号之间还可以指定包含文件的路径。例如:#include”c:prgp1.h”。6)条件编译有三种。格式和注意事项如下表:类型#if#endif#ifdef#endif#ifndef#endf 格式#if 条件 1 程序段 1#elif 条件 2 程序段 2.#else 程序段 n#endif#ifdef 宏名程序段 1

48、#else 程序段 2#endif#ifndef 宏名程序段 1#else 程序段 2#endif 注意事项1、#elif 不能写成#else if。2、#if 后面是一个常量表达式可以不加括号。在#ifdef 和#else 之间可以加多个#elif 命令。和#ifdef#endif 用法相似。1、可以没有#else(#elif),但必须有#endif 作为结尾。2、每个命令单独占一行。示代码:int main()#define PRINT(a,b)printf(%#an,(b)#define OUTPUT 2#if OUTPUT=1 PRINT(s,one);#elif OUTPUT=2 P

49、RINT(s,two);#else PRINT(s,three);#endif#define END#ifdef END PRINT(s,END!);#else PRINT(s,Go ahead!);#endif getch();运行输出:two END!总结与注意:1)C 语言中一般用大写字母定义宏名,宏名千万不能出现空格,字符串太长行尾可以用“”续行符,结尾不能用分号“;”。一般把需要用到的宏定义统一放在一个头文件。宏定义可以嵌套但不能递归定义。如下:#define R 2#define K 2*R#define M M*2/递归定义错误2)带参数的宏在使用时,参数大多是表达式,宏容本身也

50、是表达式,为了避错误,因此不但需要将整个宏容括号起来,还要把宏参数也用()括号起来。例如:#define PRINT(a,b)(printf(%#an,(b)PRINT(d,54);要注意,宏体中双引号的字符是不当成参数处理的,空的双引号在预处理中会被删去,如上面的 PRINT(d,54);替换后是 printf(“%”d”n”,(54);空双引号处理中会被删去,则变成printf(“%dn”,(54);2)要注意宏定义中的”号。在 C 语言中”符号可作为行结尾符,在双引号可以作为转义符号使用。大部分编译处理时把”放在行尾则当成行结尾符,在双引号则认为是转义符号。3)宏在预编译时的处理步骤如下

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 高考资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁