(大多记于《linux_c编程一站式学习》宋劲杉)
一、全局变量
1、全局变量(global variable)定义在所有函数之外,它们在程序开始运行时分配存储空间。
2、全局变量初始化必须是常量表达式,但局部变量还可以是表达式,如: double pi=3.14+0.0016;和 int minute=360;是合法的,但double pi=acos(1,0);和 int minute=360;int hour=minute/360;是不合法的 这是因为程序开始运行时要用适合的值来初始化全局变量,所以初始值必须保存在编译生成的可执行文件中。而double pi=acos(1,0);需要调用函数的值只有在程序运行之后才可以得到,int hour=minute/360;不是常量表达式,所以都不合法。
3、全局变量不初始化则是0,局部变量不初始化则是不确定的。
二、{}语句块
1、int i;{int i;i=0;}
{}里面的是一个语句块,语句块里面的变量和局部变量一样,每次进入语句块时,分配存储空间,退出语句块时,释放空间。语句块也构成一个作用域的作用,所以语句块里面i和外面的i是不同的两个变量。int i; for(int i;;){;} 这样就会报重复定义的错误。 int i; for(;;){int i;} 不会报错。因为for后面的{}就是一个语句块。
2、《linux_c编程一站式学习》一书第六章循环语句中有一段话这样说:
“C99规定一种新的for循环语法,变量定义可以放在for的第一个控制表达式里面,如:for(int i;;),这样做法,i就只是for循环中的局部变量而不是整个函数的局部变量,相当于{}语句块里面的局部变量。在GCC中编译,要加上选项std=c99。但这种语法是从C++中借鉴的,考虑到兼容性不建议使用。”
C99的规定我不知道,我没有去查,但是“for(int i;;),这样做法,i就只是for循环中的局部变量而不是整个函数的局部变量,相当于{}语句块里面的局部变量”,这句话有待商榷,我在VC6.0上面写一段这样的语句 for(int i;;) { int i=0; }
这个语句是没有报错的,但是
int i;
for(int i;;)
{}
却会报重复定义。至少在VC6.0上面(当然,这是C++的标准,所以说只是商榷,还不敢说这是作者的错误),这个说法是不对的。显然,VC6.0这里for(int i;;),这里i的定义已经被当做是函数的局部变量,而不是for后面{}语句块的局部变量!!!谨记谨记!
三、if(a) if(b)c; else d; 注意,else d;是和if(b)c;配对的!!!
四、浮点数不能做精确比较的。五、switch
1、switch 的case 后面跟的必须是常量表达式,这个值和全局变量的初始值一样,必须在编译时计算出来;
2、而且由于浮点型不适合做精确比较,所以C语言规定case后面跟的必须是整型常量表达式;
3、case后面如果没有break就是继续执行后面的case。switch并不是必不可缺的,因为if else也可以代替。但是,用switch会使得代码清晰,而且,有时候编译器会对switch进行整体的优化,使得生产的指令效率高。
六、逻辑运算
&& 、||、 !分别是logical and,logical or,logical not .关于逻辑运算的数学体系称为布尔代数(boolean algebra)。在编程中表示真和假的数据类型叫做布尔类型,在C语言中通常用int型来表示,非0表示真,0表示假。
七、++、--
1、++,可以做前缀运算符,也可以做后缀运算符。 如果把++i看做一个函数调用,它表示返回一个值,这个值等于参数值+1,此外,还把变量i的值加一; 如果把i++看做一个函数调用,它表示返回一个值,这个值等于参数值i,此外还把变量i的值加一。
2、a+++++b 这个是看成a++ ++ +b,还是a++ + ++b,还是a+ ++ ++b? 这里应该按第一种方式理解。
编译的过程分为词法解析和语法解析两个阶段,在词法解析阶段,编译器总是从前到后找最长的合法token。把这个表达式从前到后解析,变量a是一个token,a后面有两个以上的+号,在C语言中,一个+是合法的token(可以是加分运算符或正号),两个+号也是合法的token(可以是自增运算符),根据最长匹配原则,编译器绝不会止步于一个+号,而是一定会把++当成一个token。再往后解析也是一个++。再往后只有一个+号了。再往后是一个变量名b。
词法解析之后进入下一个阶段语法解析。a是一个表达式,表达式++还是表达式,表达式再++还是表达式,表达式再+b还是表达式,语法上没问题。
最后编译器会做一些基本的语义分析,这时就有问题了。++运算符要求操作数能做左值。a能做左值,所以a++没问题,但是表达式a++的值只能做右值,不能再++了,所以编译器就是报错,error:'++' needs lvalue。
八、goto语句和标号
如果在一个嵌套循环中遇到某个错误条件需要立即跳出最外层循环做错误处理,可以用goto语句 如:
for(……)
for(……)
{ if(出现错误条件) goto error; }
error:出错处理;
这里的error叫标号(label),任何语句前面都可以加若干个标号,每个标号的命名也要遵循标识符的命名规则。
但是goto只能跳转到同一个函数中的某个标号处,而不能调到别的函数中。
然而,goto太强大了,故而危害也大,goto不是必不可少的。goto一般只用于函数任何地方出错,跳转到函数末尾做出错处理(如释放先前分配的资源、恢复先前改动的全局变量等),处理完之后函数返回。除此之外,还是不要轻易用到goto语句。
|