暑期讲座遗漏知识点整理一

来源:互联网 发布:象棋ai算法 编辑:程序博客网 时间:2024/05/04 03:31
一、有符号数与无符号数的强制类型转换问题
    上次遇到一个问题,在比较两sizeof返回值的时候出现了意想不到的错误,原因在于sizeof返回的是无符号类型,所以出现错误。
    有符号数和无符号数的区别在于第一位表示正负数,还是数值。换句话说,有符号的二进制数最高位是符号位,剩下的是数值部分的补码(正数的补码是其本身,负数的补码是该数值取反加一)。例如int a = -1;unsign b; b = a;
那么printf(“%u”,b);结果是4294967295。
二、表达式的副作用
C 语言中,术语副作用是指对数据对象或者文件的修改,序列点是指程序运行中的一个特殊的时间点,在该点之前的所有副作用已经结束,并且后续的副作用还没发生。C 语句结束标志——分号(;)是序列点。也就是说,C 语句中由赋值、自增或者自减等引起的副作用在分号之前必须结束。任何完整表达式运算结束的那个时间点也是序列点。所谓完整表达式,就是说这个表达式不是子表达式。而所谓的子表达式,则是指表达式中的表达式。
     经常见到m = 1; n = m+++m++;类似的题目,求最后n的值。这里 n = m++ + m++ 是完整表达式,而 m++ 是它的子表达式。这个完整表达式运算结束的那一点是一个序列点,int m = 1, n; 中的 ; 也是一个序列点。也就是说,m++ + m++ 位于两个序列点之间。标准规定,在两个序列点之间,一个对象所保存的值最多只能被修改一次。但是我们清楚可以看到,上面这个例子中,m 的值在两个序列点之间被修改了两次。这显然是错误的!这段代码在不同的编译器上编译可能会导致 n 的值有所不同。比较常见的结果是 n 的值最后被修改为 2 或者 3。在此,各位只要记住这是错误的,别这么用就可以了。
三、关于求平均值所引起的思考
 求两个数的平均值,我想大多数人一定是用(x+y)/2这种方式来求,但是如果
a > INT_MAX,b > INT_MAX,那么最后平均值我们怎么实现呢?可以考虑通过位运算求得((x^y)>>1)+(x&y),知道了所谓的答案并不是目的,关键在于其中的思考过程,为什么不能直接看出问题的本质,又怎么样在看出问题的陷阱后及时想出完善的解法值得我们深思,学习不允许半点马虎的地方,处处应该细心,关注可能出现的问题,同时还要需要牢固的基础,这样才能在技术的道路上越走越远。
四、扫描集
ANSIC 标准向 scanf() 增加了一种新特性,称为扫描集(scanset)。扫描集定义一个字符集合,可由 scanf() 读入其中允许的字符并赋给对应字符数组。扫描集合由一对方括号中的一串字符定义,左方括号前必须缀以百分号。
具体作用是:如果输入的字符属于方括号内字符串中某个字符,那么就提取该字符;如果一经发现不属于就结束提取。该方法会自动加上一个'\0'到已经提取的字符后面。在“[]”内,还可以加入另外一个字符来修饰它的作用:“^”。这个符号可以理解为“补集”,即,扫描除方括号之内的其它字符:如果输入的字符不属于方括号内字符串中某个字符,那么就提取该字符;如果一经发现输入的字符属于该字符,则结束。为了简便,我们可以这样简写[^A-Z]
五、assert断言
注意:assert是宏,而不是函数。在C的assert.h头文件中。
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
#include <assert.h>void assert( int expression );
assert的作用是先计算表达式expression,如果其值为假(即为0),那么它先向标准错误流stderr打印一条出错信息,然后通过调用abort来终止程序运行;否则,assert()无任何作用。宏assert()一般用于确认程序的正常操作,其中表达式构造无错时才为真值。完成调试后,不必从源代码中删除assert()语句,因为宏NDEBUG有定义时,宏assert()的定义为空。
使用assert的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。
在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用,示例代码如下:
#include <stdio.h>#define NDEBUG#include <assert.h>


                                            ————参照百度词条
原创粉丝点击