《C语言基础学习笔记》由会员分享,可在线阅读,更多相关《C语言基础学习笔记(34页珍藏版)》请在金锄头文库上搜索。
1、C语言基础学习笔记 (第一版修改) 丁炳亮 1 数据类型和表达式 1.1 计算机数据存储方式 理解与测试: 什么是补码?我们得先知道模的概念。模“模”是指一个计量系统的计数围。如时钟等。 计算机也可以看成一个计量机器,它也有一个计量围,即都存在一个“模”。例如: 时钟的计量围是 011,模=12。表示 n 位的计算机计量围是02(n)-1,模=2(n)。 “模”实质上是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只 能表示出模的余数。任何有模的计量器,均可化减法为加法运算。例如:假设当前时针指向 10 点,而准确时间是6 点,调整时间可有以下两种拨法:一种是倒拨4 小时,即:
2、10-4=6; 另一种是顺拨 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 else pr
3、intf(0); printf(n); main() int a=-0 xff; f(a); getch(); 输出的结果是 00001。 1.2 变量与常量 理解与测试: 1)类型声明 在计算机部数据是以字节为单位存储的,但是我们需要的数据类型有很多种,每种数据 类型所占字节和存储方式都不一样。类型声明的作用就是告诉计算机以哪种“格式”去读写 该数据数据。 类型说明符变量名 1,变量名 2.,变量名 n; 类型说明符有基本类型(字符型、整数型、单/双精度型)、高级类型(结构体型、共用 体型、枚举类型)、指针型等,其中指针类型包括指向基本类型的指针类型、指向高级类型 的指针型和指向函数的指针类
4、型(指向函数指针声明格式在后面章节)。 2)符号常量的定义 #define 标识符 常量; 使用该种方法定义符号常量一个是可以使代码便于阅读理解,另一个是方便代码部多个 相同常量的统一修改。 总结与注意 在写计算式的时候要考虑变量是否会越界。一般来说计算式子时是先强制转换成式子中 最大存储空间的数据类型(不包括被赋值的变量),还要注意不同的类型数据在不同的编译 器中所占的存有可能是不一样的,例如有些编译器整型是占2 个字节有些是占4 个字节。同 时还要考虑到符号的优先级和结合顺序,如果按符号的优先级和结合顺序运算过程中有越界 的那么整个计算结果可能和预想的不一样了,例如int i=100;i
5、= 500*i/i; 最后 i=-155。 1.3 输出输入 理解与测试: 1)格式化输入输出函数可以按设定的格式和设定的数据类型接收和输出多个变量。控制 格式和数据类型的是数据控制符。 2)字符和字符串可以用专门的输出输入函数。主要有 getch(); putch();getchar(); putchar(); gets(); puts();其中 getch()和 putch()是 conio.h 中声明, getch()不需要等待回车键就返回字符并 立即执行下面一语句符, getch()不在屏幕显示输入的字符。 getchar();putchar(); 在 stdio.h 中声 明。get
6、char()读取键盘上的一个字符, 立即返回并显示在屏幕上, 需要等待回车键才能执行下 一条语句。例如下面的代码: int main(void) char ch,i; for(i=0;i10;i+) ch = getchar(); putchar(ch); getch(); 输入: I LOVE YOU 输出: I LOVE YOU 总结与注意 格式输入函数中的参数是变量存放的地址,所以变量前面要” 这个表达式等效于 (a-)-b; 2)复合赋值符及表达式在赋值符“=”之前加上其他双目运算符号可以构成复合赋值符。 如:+=、-=、*=、/=、%=。构成复合赋值表达式的一般格式为 变量双目运算符
7、= 表达式 等价于 变量 = 变量运算符表达式 可以这么去理解,等号左边的相当于变量自增、自减、自除、自取余一个数,这个数由 右边的表达式计算得到。如:int a=7,b=3,c=3;a+=b+=c+=5;运算后是 a=18,b=11,c=8 。 3)C 中唯一一个三目运算符是条件运算符,由“?”和“:”构成。两个符号必须按下 面的格式一起使用: 表达式 1?表达式 2:表达式 3 三个表达式可以是任意的合法表达式,条件运算符的运算规则如下:如果表达式1 的值 为真,那么整个表达式的值为表达式2 的值,否则为表达式3 的值。 4)sizeof()也是一个运算符号, 它可以对一个数据类型或一个变
8、量取类型长度。但是当一 个数组名作为一个实参传递给函数时,在函数部是不能用sizeof 来获取该数组的长度的。因 为数组名是一个指向数组首地址的指针,使用sizeof 只能取得实参指针类型长度。 5)比较少用到的符号是“:”和“,”。冒号运算符在C 中有三种用途,第一种是我 们上面讲到的与“?”构成三目运算。第二种是在switch 中放在常量表达式后面。第三种用 法是在结构体中定义位域时用到。 struct 位域结构名 位域列表 ; 其中位域列表的形式为:类型说明符位域名:位域长度 例如: struct bs int a:8; int b:2; int c:6; ; 逗号运算符的功能是把两个表
9、达式连在一起组成一个新的表达式,称为逗号表达式。其 一般格式为 表达式 1,表达式 2,表达式 3,.,表达式 n; 其求值过程是自左向右求两个表达式的值,并以最后一个表达式的值作为整个逗号表达 式的值。例如 for(a=0,b=0,c=0;b10,a20;b+,a+)+c;运算后 c=20,如果把中间的两个语句前 后调换 for(a=0,b=0,c=0;b10,aj?i+:j; printf(%dn,n); getch(); 输出结果: 2 4 3)在写式子时要注意运算符号对变量的副作用,单目运算有“+”和“-”,双目运算 有“=”。 4)位运算符号与逻辑符号容易混淆的有“ for(i=1,
10、i=1) if(i else printf(0); printf(n); 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
11、语句还是尽量选择switch 语句或者使 用其他能使代码简洁易懂的方法。如下面的代码: main() int 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
12、,f=10; while(1) if(a=b)break; printf(%dn,a); if(b=c)break; printf(%dn,b); if(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后面跟
13、的一定是整数型或符号型常量表达式,不能 是变量,并且不用有相同值的变量表达式,不然会矛盾的。 2.2 循环结构 理解与测试: 1)主要有 for、while、do-while 这三种结构循环体,其中最后一种是比较少用到的,因 为一般情况都可以用前面两种替代。 2)循环体结构中括号的表达式要知道时候退出,有时候还要知道循环体运行多少次。在 循环体部也可以使用continue 语句跳过本次循环,进入下一次循环,或者用break 语句退出 当前层循环。 总结与注意 循环结构中表达式的设计很重要。在for 循环结构我们经常用到从0 到 x,循环体执行 x+1 次,可以写成 for(i=0;i0;i-=
14、3); 这个循环语句的运行结果一般不是我们想要的。把“=”不注意写 成“=”也是容易造成死循环的结果。 3 数组 3.1 一维数组 理解与测试: 1)一维数组的定义如下: 类型说明符数组名 常量表达式 如果定义时就进行初始化,常量表达式可以省略。动态存储的数组没有初始化所有元素 的值都为随机。静态存储的数据没有初始化所有的元素自动赋0。 2) 一维数组名是一个指针常量, 指向数组的首地址。 由于是指针常量所以不能对其赋值, 只能当指针引用。同理一个数组不能对另一个数组整体赋值。数组引用时下标是从0 开始计 算的。 3)字符型数组初始化可以直接赋值字符串。char s= “ Happy” ; 或
15、者 char s=” Happy” ;。 总结与注意 数组引用时下标不要越界,字符串数组初始化时,数组元素个数要比字符串多一个,因 为字符串结束有个“ n”符,否则越界就会发生预料不到的结果。如下: main() char a8=abcdefgh; printf(%s,a); getch(); 输出结果: main() int a2,i; for(i=0;i8;i+) scanf(%d, getch(); 上面这个代码当输入字符超过2 个时可能出现无法运行的结果。 总结与注意 数组名作为函数参数时传递给形参的是数组的指针,而且在子函数中无法用sizeof 取得 数组的大小,所以有需要时可以用另
16、一个参数传递数组的大小。数组作为形参时可以写成int f(int a) 或者 int f(int * a) 或者 int f(int a10) ,他们三者都一样的,因为对于指针来说“ ”等 效于 “ *” ,数组做形参不会传递数组大小,int a10 等效于 int a 。数组作为实参时可以写成 f(a)或者 f(返回的是一个 int 型数值,但是不能保证值为0。 4.2 局部变量和全局变量 理解与测试: 1)全局变量也叫外部变量,它是定义在函数外部。它不属于那个函数,而属于一个源程 序文件。局部变量是定义在函数部,可以在函数的声明中定义,也可以在一个语句块中定义。 变量的作用围都是相对于同一层次来