第五章 操作符和表达式
1、如果整除运算的任一操作数为负值,运算的结果是由编译器定义的。
2、标准说明无符号值执行的所有移位操作都是逻辑移位,但对于有符号值,到底是采用逻辑移位还是算术移位取决于编译器。
3、像这样的移位:
a<<-5;
这样的行为是未定义的,它是由编译器决定的。
还因为它们的效果是不可预测的,使用这类移位的程序是不可移植的。
4、赋值也是一个表达式,赋值表达式的值就是左操作数的新值。
5、看一条语句:
a=x=y+3;
认为a和x被赋予相同的值的说法是错误的。
如果x是一个字符变量,那么y+3的值就会被截去一段,以便容纳字符类型的变量。那么a所赋的值就是这个被截短后的值。
(我还是没有懂)
6、+操作符产生操作数的值。换句话说,它什么也不干。
7、判断表达式的长度并不需要对表达式进行求值,所以sizeof(a=b+1)并没有向a赋任何值。
8、前缀操作符在进行复制之前增加变量的值,后缀操作符在进行复制之后才增加变量的值。这些操作符的结果不是被他们所所修改的变量,
而是变量值的拷贝。
如 ++a=10; 是错误的,++a的结果是a值的拷贝,并不是变量本身,你无法向一个值进行赋值。
9、 逗号表达式的值就是最后那个表达式的值。
10、这里给一个警告
尽管所有的非零值都被认为是真,但是当你在两个真值之间相互比较时必须小心。因为许多不同的值都可能代表真。
但是flag设置为任意的整型表达式,那么第2对语句就是不等价的。只有当flag确实是TRUE或者FALSE,或者是关系表达式或逻辑表达式的
结果值时,两者才是等价的。
11、左值和右值问题:
左值就是那些能够出现在赋值符号左边的东西。
右值就是那些可以出现在赋值符号右边的东西。
a=b+25;
左值a标识了一个可以存储结果的地点,b+25是个右值,因为它指定了一个值。
再看
b+25=a;
b+25不能作为左值,因为它并未标识一个特定的位置,这个表达式是非法的。
第六章 指针
1、名字与内存位置之间的关联不是由硬件所提供的,它是由编译器为我们实现的。
2、不能简单地通过检查一个值的位来判断它的类型,值的类型并非本身所固有的一种特性,而是取决于它的使用方式。
3、变量的值就是分配给该变量的内存位置所存储的数值,即使是指针变量也不例外。
4、*100=25;
这条语句看上去似乎是把25赋值给位置100的单元,但是实际上这是非法语句。
如果实在是要达到上述目的要用强制转换: *(int *)100 = 25 ;
5、* 操作符具有从右向左的结合性。
** c 就相当于*(*c);
6、指针问题
char ch='a';
char *cp=&ch;
1)*++cp ++操作符优先级高于* 相当于 *(++cp) 也就是ch后面的那个存储单元的值,cp指向ch后面的那个单元
2) *cp++ 第一、++操作符产生cp的一份拷贝
第二、然后++操作符增加cp的值
第三、在cp的拷贝上执行间接访问
也就是这个表达式的值为a,cp指向ch后面的那个单元
3) ++*cp ++和*操作符都是从右到左的结合性,所以先执行间接访问操作,然后cp指向的位置加1.也就是b
4) (*cp)++ 它的值是a,但是之后就是b了
5)++*++cp 操作符都是右往左的结合性
先算++cp 然后再间接访问,也就是访问ch后面的那个单元 最后把该单元的值加1.
6)++*cp++ 先执行cp++,把cp拷贝一份,然后把cp增加1,然后对这个拷贝进行间接访问是a,然后把a+1,就是b了,结果cp
指向ch后面那个单元。
优先级:
后缀++
后缀--
*
前缀++
前缀--
7、标准允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较(再往后也是不合法的),但绝对不允许与指
向数组第一个元素之前 的那个内存位置的指针进行比较。
8、声明一个指针变量并不会自动分配任何内存。在对指针执行间接访问前,指针必须进行初始化。
9、对NULL指针执行间接访问操作的后果因编译器而异,两个常见的后果是返回内存位置为0的值以及终止程序。
10、除了NULL指针,再也没有任何内建的记法来表示指针常量。我们偶尔需要用指针常量,可以通过把一个整型值强制转换成指针类型来创
建它。
11、任何指针之间都可以进行比较,测试它们相等或者不相等。但要执行关系运算必须是指向同一数组的指针。
第七章、函数
1、存根:为未编写好的代码“站好位置”。
2、一个没有参数的函数的原型应该写成下面这样子:
int *func(void);
代替 int *func();
3、当程序调用一个无法见到原型的函数时,编译器便认为该函数返回一个整型值。对于那些并不返回整型值的函数,这种认定可能会引起错误。
4、在声明数组参数时,不指定它的长度是合法的,因为函数并不为数组元素分配内存。
5、当你使用递归方式实现一个函数之前,先问问自己 使用递归方式的好处是否抵得上它的代价,而且你必须小心,这个代价可能比初看上去要大得多。
6、可变参数列表
使用stdarg宏
头文件:stdarg.h
类型 va_list
三个宏:va_start,va_arg,va_end
看一个例子:
参数列表中至少要有一个命名参数。如果你在va_arg中指定了错误的类型,其结果是不可预测的。