前言:为了准备就业时的专业笔试,自己打算将笔试常考的知识点重新复习一下,这里面还涉及到一些自己新学习的东西,幸好笔试的考点基本上比较固定。我计划按照这样的序列开始准备:C语言拾遗——数据结构与常见算法(重点)——面试考点(C/C++,数据库,数据结构,网络等)。今天的这是其中的第一部分。

C语言拾遗的主要材料是Alan R.Feuer的《C语言解惑》一书。

                                                            2012.11.5

*******************************************************************************

*******************************************************************************

第一章 操作符

这部分的内容其实比较简单,主要有以下几个方面需要特别注意的:

操作符的优先级与同级关联性

增量运算符++的前后缀区别

二进制位操作符

逻辑操作表达式的求值顺序

下面分别小结。

1. 操作符的优先级与同级关联性

这里只需要掌握优先级表即可,有高到低依次为:

关联操作符:如(), [], 以及由结构取部分的操作符->'.'

一元操作符:逻辑非(!)正负号(+-),++/--(自增/减运算),地址操作(&&),强制类型转换(type)以及字节大小运算(sizeof

四则运算:其中乘除余同级,高于加减运算

移位操作:<<>>

关系操作符:其中小于(等于)和大于(等于)同级,高于“相等”比较(==, !=

位操作符:按位与(&) >  按位异或(^) >  按位或(|

逻辑操作符:逻辑与(&&) >  逻辑或(||

条件操作符:a ? b : c

赋值操作符:+=, =, <

逗号:','

关联性:除了一元操作符、赋值运算符与条件运算符是从右向左,其余全是从左向右关联

Exa-1:int x;  x = - 3 * 4 % - 6 / 5; 则 x = 

PS:x = (- 3) * 4 % (- 6 ) / 5 ,从左至右运算即可得x = 0

2. 增量运算符++/--的前后缀

++x:则x先自增1后作为操作数与操作符结合进行运算;

--xx先作为操作数与操作符结合进行运算后,再自增1

Exa-2int x = 1, y = 1, z = 1;  z += - x ++ + ++ y; x = y = 

PSx1参与运算,y2参与运算,之后x = x + 1;此题目x = 2, y = 2, z = 0;

3. 二进制位操作符

这里关键是根据定义规定将变量(整数)转变为二进制进行运算,注意优先级即可。

对于左移操作,如x <,表示x的各位依次向左移动3位,右边空出的位用0补齐;

而对于右移操作,如x >> 3,左侧空出的部分可能保留符号位(负数时为1),也有可能直接补0,这取决于不同的机器。

另: x ^ x = 0; 

4. 逻辑操作符表达式的求值顺序

对于&&||而言,计算机从左向右判断时,一旦可以判断整个表达式的值,便立刻停止计算,这会导致后续的部分没有机会运行。如:

Exa-3int x= 1, y = 1, z = 1;  ++x || ++y && ++z; x = , y = , z = 

PS:原式等价于 (++x) || (++y && ++z)C语言按照从左向右的顺序对表达式求值,计算++x后发现式子变为TRUE || (++y && ++z),根据逻辑或规则,结果一定为TRUE,故C语言不再向下运行++y++z,即yz的值没有改变。

5. 其他一些补充

补充1C语言的副作用。有时候语法没有错误,但是结果却不确定,如变量的值无法预料的情况—— z = (x / (++x) )

补充2'#'号宏

#define PRINT(int)  printf(#int " = %d\n", int)  这里的'#'使得实际参数替换形式参数'int'后被括在一对""中。

PRINT(x)    printf("x" " = %d\n", x)   printf("x = %d\n", x)这里C语言处理器会自动将相邻的字符串合并

补充3重要的原则——编写程序时涉及到复杂的操作符表达式时尽可能使用()来表示结合顺序!

第二章 基本类型

要点:

字符类型与整数类型的关系在于ASC码值为整数值,如何解释取决于格式控制

浮点数向整数类型转换时会丢失精度,比如失去小数部分;

重要的原则——应当尽量避免不同类型数据进行运算;如不能避免,也应当使用强制类型转换符予以标明强调!

第六章 存储类

C语言中的变量有三个基本的属性:

类型:决定了该变量获得的存储空间大小以及允许的操作

作用域:说明该变量在程序的哪些上下文中可见(可用),常见的作用域边界有块、函数与文件

生存期:说明该变量的值有效的时间区间,只有在这个区间内该变量的值才是有意义(存在)的

这里最需要注意的是同一个程序中的同名变量的替换规则,其实该问题笼统来说就是:不同层次(块/函数/文件)中的同名变量引用会发生内层变量对外曾变量的替换。若变量用extern声明,则在该程序的作用域是该程序所有文件,且生存期同该程序相同;若变量用static声明,则从当前文件中该声明开始以下部分为该变量的作用域,生存期同该程序运行一致(同extern变量);每个函数的调用参数都是优先选用同层的变量,没有时才会使用更外层的可见变量。

Static + 局部变量:改变其生存期至整个程序,作用域限定在本文件;

Static + 全局变量:生存期不变,作用域限定在本文件内部,其他文件不可访问;

如程序:

+

头文件略与函数声明略;

Int i = 1;

Main()

{

  Auto int i, j;

  

  I = reset();

  Printf("i = %d\n", Next());

}

另一个文件:

Static int i = 10;  //Static变量只可在本文件中的Next()函数中可见

Next(void)

{

 Return ( i +=1);

}

再另一个文件中:

Extern int i;

Int reset(void)

{

 Return (i);

}

第七章 指针和数组

指针的要点很多也很繁琐,稍不留意就会弄混。这次看书搞懂了之前模糊的两个知识点:

数组形式Array[n]中,Array[n] = *(Array + n),其中n为数组的元素下标,具体计算地址时是n*sizeof(Array的基类型)

指针的指针。如定义char **p,则可以这样理解:(char *) (*p),其中*p表示p是一个指针变量,而(char *)则表示为这个指针变量的基类型是一个char型的指针

C语言不会自动检查指针所指的边界,即如不加限制条件,*(p ++)会一直偏移下去导致溢出


12-22 21:56