当前位置:文档之家› C程序设计语言(第二版)

C程序设计语言(第二版)

第一章基本概念第二章类型、运算符与表达式一个对象的类型决定着该对象可取值的集合以及可以对该对象施行的运算。

2.2 数据类型与大小1. 在C语言中只有如下几个基本数据类型:char 单字节,可以存放字符集中一个字符。

int 整数,一般反映了宿主机上整数的自然大小。

Float 单精度浮点数。

Double 双精度浮点数。

此外,还有一些可用于限定这些基本类型的限定符。

2.3 常量1.诸如1234一类的整数常量是int常量。

Long常量要以字母l或L结尾。

无符号常量以字母u或U结尾,后缀ul或UL用于表示unsigned long常量。

(这里的常量其实就是指直接指定的一般数字或是字符字符串什么的)浮点常量必须包含一个小数点或指数(如1e-1)或两者都包含,在没有后缀时类型为double。

后缀f与F用于指定float常量,而后缀l或L则用于指定字符常量是一个整数,写成用单引号括住单个字符的形式,如‘x’。

字符常量的值是该字符在机器字符集中的数值。

常量表达式时其中只涉及到常量的表达式。

这种表达式可以在编译时计算而不必推迟到运算时,因而可以用在常量可以出现的任何位置,例如由define定义的宏。

字符串常量也叫字符串字面值,是用双引号括住的由0个或多个字符组成的字符序列。

从技术绝度看,字符串常量就是字符数组。

在内部表示字符串时要用一个空字符’\0’来结尾,故用于存储字符串的物理存储单元数比括在双引号中的字符数多一个。

这种表示发意味着,C语言对字符串的长度没有限制,但是程序必须扫描完整个字符串才能决定这个字符串的长度。

枚举常量。

枚举是常量整数值的列表。

不同的枚举中的名字必须各不相同,同一枚举中各个名字的值不要求不同。

枚举是使常量值与名字相关联的又一种方便的方法,其相对于#define语句的优势是常量值可以由自己控制。

2.4 说明其实就是声明。

如果所涉及的变量不是自动变量(就是局部变量),那么只初始化一次,而且从概念上讲应该在程序开始执行之前进行,此时要求初始化符必须为常量表达式。

显示初始化的自动变量每当进入其所在的函数或分程序时就进行一次初始化,其初始化符可以是任何表达式。

外部变量与静态变量的缺省值为0。

未经显式初始化的自动变量的值为未定义值(即垃圾)。

2.5 算术运算符2.6 关系运算符与逻辑运算符2.7 类型转换1. 当一个运算符的几个运算分量的类型不同时,要根据一些规则把它们转换成某个共同的类型。

一般而言,只能把“比较窄的”运算分量自动转换成“比较宽的”运算分量,这样才能不丢失信息。

2. char类型就是小整数类型,在算术表达式中可以自由地使用char类型的变量或常量。

这就使得在某些字符转换中有了很大的灵活性。

但是在将字符转换成整数时有一点微妙。

C 语言没有指定char类型变量时无符号还是有符号量。

当把一个char类型的值转换成int类型的值时,其结果是不是负整数?结果视机器的不同而有所变化,反映了不同机器结构之间的区别。

在某些机器上,如果字符的最左一位为1,那么就被转换成负整数。

在另一些机器上,采取的是提升的方法,通过在最左边加上0把字符提升为整数,这样的转换结果总是正的。

C语言的定义保证了机器的标准可打印字符集中的字符不会是负的,故在表达式中这些字符总是正的。

但是,字符变量存储的位模式在某些机器上可能是负的,而在另一些机器上却是正的。

为了保证程序的可移植性,如果要在char变量中存储非字符数据,那么最好指定signed或unsigned限定符。

3. 当表达式中包含unsigned类型的运算分量时,转换规则要复杂一些。

主要问题是,在有符号与无符号值之间的比较运算取决于机器,因为它们取决于各个整数类型的大小。

例如,假定int对象占16位,long对象占32位,那么,-1L<1U,这是因为int类型的-1U被提升为signed long类型;但是-1L>1UL,这是因为-1L被提升为unsinged long类型,因此它是一个比较大的正数。

4. 在进行赋值时要进行类型转换,=右边的值要转换成左边变量的类型,后者即赋值表达式结果的类型。

不管是否要进行符号扩展,字符值都要转换成整数值。

当把较长的整型数转换成较短的整型数或字符时,要把超出的高位部分截掉。

5. 由于函数调用的变元是表达式,当把变元传递给函数时也可能引起类型转换。

在没有函数原型的情况下,char与short类型转换为int类型,float转换为double型,这就是即使在函数使用char与float类型的变元表达式调用时仍把参数说明成int与float的原因。

2.8 加一与减一运算符2.9 按位运算符2.10 赋值运算符与赋值表达式2.11 条件表达式2.12 运算符优先级与表达式求值次序同一行的各个运算符具有相同的优先级,纵向看越往下优先级越低。

第三章控制流第四章函数与程序结构4.1 函数的基本知识1. 程序是变量定义和函数定义的结合。

函数之间的通信可以通过变元、函数返回值以及外部变量进行。

函数可以以任意次序出现在原文件中。

源程序可以分成多个文件,只要不把一个函数分在几个文件中就行。

4.3 外部变量1.C程序由一组外部对象(外部变量或函数)组成。

外部变量在函数外面定义,故可以在很多函数中使用。

由于C语言不允许在一个函数中定义其他函数,因此函数本身是外部的。

在缺省情况下,外部变量与函数具有如下性质:所有通过名字对外部变量与函数的引用都是引用的同一对象。

4.4 作用域规则4.5 头文件4.6 静态变量1. static说明适用于外部变量与函数,用于把这些对象的作用域限定为被编译源文件的剩余部分。

2. 外部static说明最常用于说明变量,当然它也可以用于说明函数。

通常情况下,函数名字是全局的,在整个程序的各个部分都可见。

然而,如果把一个函数说明称静态的,那么该函数名字就不能用在除该函数说明所在的文件之外的其他文件中。

Static说明也可用于说明内部变量。

内部静态变量就像自动变量一样局部于某一特定函数,只能在该函数中使用,但与自动变量不同的是,不管其所在函数是否被调用,它都一直是存在的,而不像自动变量那样,随着所在函数的调用与退出而存在与消失。

4.7 寄存器变量Register说明用于提醒编译程序所说明的变量在程序中使用频率较高。

其思想是,将寄存器变量放在机器的寄存器中,这样可以是程序更小、执行速度更快。

但编译器可以忽略此选项。

寄存器说明只适用于自动变量以及函数的形式参数。

所有寄存器变量的地址都是不能访问的。

4.9 初始化1.在没有显示初始化的情况下,外部变量与静态变量都被初始化为0,而自动变量与寄存器变量的初值则没有定义(即,其初值是“垃圾”)。

4.10 递归4.11 C预处理程序第五章指针与数组5.1 指针与地址1.取地址运算符&只能应用于内存中的对象(即变量与数组元素),它不能对表达式、常量或寄存器变量进行操作。

5.3 指针与数组1.数组下标所能完成的任何运算都可以用指针来实现。

一般而言,指针运算比数组下标运算的速度快。

在对数组进行下标运算,即求a[i]的值时,C语言实际上是先将其转化成*(a+i)的形式然后再进行求值,因而在程序中这两种形式等价。

2.必须注意到,数组名字和指针之间仍然存在着一点区别。

指针是变量,因而在C语言中,语句pa=a和pa++都是合法的。

但是数组名字不是变量,因而诸如a=pa(这个是指对整个数组从一个到另一个的整体赋值)和a++(这是指对数组名执行自加运算,其实可以运用a+i的形式,不知为啥a++不行)这样的语句是非法的。

3.当把一个数组名字传递给一个函数时,实际上传递的是该数组第一个元素的位置。

也可以通过传递指向子数组的指针的方法把数组的一部分作为参数传递给函数。

例如f(&a[2])。

5.4 地址算术运算1.有效的指针运算包括:相同类型指针之间的赋值运算;指针值加或减一个整数值的运算;指向相同数组中的元素的指针之间的减或比较运算;将指针赋0或指针与0之间的比较运算。

所有其他形式的指针运算均非法,诸如下列形式的运算就是非法的指针运算:指针间的加法、乘法、除法或屏蔽运算;指针值加单双精度浮点数的运算;除两者之一是void*类型指针外,不经强制类型转换就将指向一种类型对象的指针赋给指向另一种类型对象的指针的运算。

5.5 字符指针与函数char amessage[] = “now is the time”; /*定义一个数组*/char *pmessage = “now is the time”; /*定义一个指针*/上述说明中,amessage是一个不可改变的常量,它总指向同一片存储区。

另一方面,pmessage是一个指针,其初值指向一个字符串常量,之后它可以被修改指向其他地址,但是如果试图修改字符串的内容,结果将不确定。

5.6 指针数组与指向指针的指针1. 例如定义char *line[20],那么请注意,这时首先根据运算符优先级规则,line是一个数组,又由于有*的修饰,所以他是一个指针数组,即数组里面存储的全部是指针。

5.7 多维数组1.数组在内存中按行存储。

如果要将二维数组作为变元传递给函数,那么函数的参数说明中应该指明相应数组的列数,数组的行数不必指定。

5.9 指针与多维数组注意int a[10][20];int *b[10];这两个的区别,对于b来说,每一维的长度可以不一致。

5.10 命令行变元5.11 指向函数的指针1.在C语言中,函数本身不是变量,但可以定义指向函数的指针,这种指针可以被赋值、存放于数组中、传递给函数及作为函数返回值等等。

2.定义指向函数的指针:return_type (*fun_name) (参数列表);调用则为(*fun_name)(实参);5.12 复杂说明1. 见定义:char **argv; argv:指向字符指针的指针int (*daytab) [13]; daytab:指向由13个整形类型元素组成的一维数组的指针(这就是数组指针,指向数组的指针。

就是一指针)。

(这里这么用,int nArray[3] = {1, 2, 3};int (*pArray)[3] = &nArray;)int *daytab[13]; daytab:由13个指向整数类型对象的指针组成的一维数组(存储的是13个指针)。

void *comp(); comp:返回值为指向通用类型的指针的函数。

void (*comp)(); comp:指向返回值为通用类型的函数的指针。

char (*(*X())[])(); X:返回值为指向一维数组的指针的函数,该一维数组由指向返回字符类型的函数指针组成。

char (*(*X[3])()) [5]; X:由3个指向函数的指针组成的一维数组,该函数返回指向由5个字符组成的一维数组的指针。

相关主题