《C专家编程》学习笔记2
一个 L的 NUL用于结束一个ASCLL字符串
两个L 的NULL 用于表示什么也不指向的指针
标准的C编译器至少允许一条switch语句中有257个case标签。为了满足一个8bit的字符的所有情况。
switch的另一个问题是它内部的任何语句都可以加上标签,并在执行时跳转到哪里,这就有可能破坏程序流的结构化。(类似于goto)
证明在C语言中const并不表示常量,可以在switch-case语句的case中加一个状态case:const i,编译时会抱错,非常量;
break语句中断了什么?break语句事实上跳出的是最近的那层循环语句或switch语句,由此导致AT&T的第一次网络故障。
ANSI C引入的另一个特性是相邻的字符串常量将被自动合并成一个字符串的约定。留意 字符串末尾的逗号是从最早的C语法中继承下来的,不管存在与否,没有任何意义。
软件对象在大多数情况之下应该缺省地采用有限可见性。当程序员需要将它全局可见时,应该采用显式的手段。
C语言中的符号重载:
static 在函数内部,表示该变量的值在各个调用期间一直保持延续性;
在函数这一级,表示该函数只对本文件可见
extern用于函数定义表示全局可见(属于冗余的)
用于变量,表示它在其他地方定义
sizeof不是一个函数,sizeof是C/C++中的一个操作符(operator),简单的说其作用就是返回一个对象或者类型所占的内存字节数;
易错的C语言运算符优先级问题
.的优先级高于*,而-〉的作用就是消除这个问题,例如 *p.f 的含义就是*(p.f)
[]的优先级高于* 例如 int*ap[]表示ap是一个元素为int指针的数组
==和!=高于位运算符 例如(val & mask!=0)的含义是 val& (mask!=0)
==和!=高于赋值运算符 例如 c=gerchar()!=EOF 的含义是C=(getchar(0!=EOF)
算术运算符高于移位运算符 例如 msb<<4+lsb 的含义是msb<<(4+lsb)
逗号运算符在所有运算符中优先级最低
在表达式中如果有布尔操作,算术运算和位操作等混合运算,你始终应该在适当的地方加上括号
所有的赋值符都具有右结合性,就是说表达式的最右边的操作最先执行,然后从右到左执行,.例如a=b=c 顺序是 b=c,然后a=b;类似的具有左结合的运算符(如&,|)则是从左到右依次执行。
枚举有一个优点:#define定义的名字一般在编译的时候被丢弃,而枚举的名字则通常一直在调试器中可见,可以在调试代码时使用它们。
typedef和#define的区别
……#define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错;
……typedef是在编译时处理的。它在自己的作用域内给一个已经存在的类型一个别名
把typedef看成是一种彻底的“封装”类型,在声明它之后不能在往里面增加别的东西。
1)可以用其他类型说明符对宏类型名进行扩展,但对typedef所定义的类型名却不能这样做;
例如 #define A int
unsigned A i; /*没问题*/
typedef int A;
unsigned A i;/*错误,非法*/
2)在连续的几个变量中,用typedef定义的类型能够保证声明中所有的变量均为同一种类型,而用#define定义的类型则无法保证
例如 #define int_ptr int*
int_ptr A ,B;
宏扩展为 int* A,B; A是指针 B是int型
但是 typedef char* char_ptr;
char_ptr A,B;
此时 AB类型是相同的;
典型应用……………………
typedef int * pint ;
#define PINT int *
那么:
const pint p ;//p不可更改,但p指向的内容可更改
const PINT p ;//p可更改,但是p指向的内容不可更改。
pint是一种指针类型 const pint p 就是把指针给锁住了 p不可更改
而const PINT p 是const int * p 锁的是指针p所指的对象。
…………………………此处可以将typedef理解成完全封装,所以const就和P直接绑定了……………………………………
c语言中的对象必须有且只有一个定义,但它可以有多个extern声明.
指针和数组的区别:
定义指针时,编译器并不为指针所指向的对象分配空间,它只是分配指针本身的空间,除非在定义时同时赋给指针字符常量进行初始化 注意只有对字符串长;量才是如此;
不能指望为浮点数的常量分配空间;
例如 float *pip=3.14;/*错误,编译无法通过*/
在ANSI c中,初始化指针时所创建的字符串常量被定义为只读,与指针相反,由字符串常量初始化的数组是可以修改的。
####################################################################################################################################
(承接P192)
对数组的下标的引用总是可以写成“一个指向数组的起始地址的指针加上偏移量”。
对数组的引用如a[i]在编译时总是按被编译器改写成*(a+i)的形式。
只有字符串常量才可以初始化指针数组。指针数组不能由非字符串的类型直接初始化。
::被称为“全局范围分解符”。跟在它前面的标识符就是进行查找的范围。如果::前面没有标识符。就表示查找范围为全局范围。
每个成员函数都有一个this指针,它是隐式赋给该函数的,它允许对象在成员函数内部引用对象本身。
当一个类的对象被创建时,构造函数会被自动调用,程序员永远不应该显式调用构造函数。至于全局和静态对象,它们的构造函数会在程序开始时被自动调用,而当程序终止时,他们的析构函数会被自动调用。
多态是一种运行时效果,它是指c++对象在运行时决定应该调用哪个函数来实现某个特定操作的过程。
C++的异常(exception)用于在错误处理时改变程序的控制流。异常通过发生错误时把处理自动切换到程序中用于处理错误的那部分代码,从而简化错误处理。
new能真正建立一个对象,而malloc()函数只是分配内存。
在c++中,声明可以出现在语句可以出现的任何地方,在c语言中的代码块中,所有的声明必须出现在所有的语句的前面。
库函数调用和系统调用区别何在?
函数库调用时语言或应用程序的一部份,而系统调用时操作系统的一部分。
语言排斥强语言类型,允许不同数据类型的转换,如单精度,双精度浮点数和
字符
auto关键字是摆设,只对创建符号表入口的编译器设计者有意义。
标准c中float自动转化成double类型,但是在ANSI c中不再如此;
一般性的声明可以被分离到头文件中,并且可以被许多源文件使用,
#define命令需要更仔细的分辨
任何学习或者使用C语言的人都应该使用ANSI C。