词法陷阱
暑假的时候重新学习了C语言,这里记录一些学习的心得和体会.
1.1 "="不同于"=="
#include <stdio.h>
int main(void)
{
///"=="符号写成"="
//这里出现"="与"=="的错误,由于将符号"=="写成"="号,导致c的值一直为32(' '符号的ASCII值),
//因此这个while循环一直都为1,变成一个死循环.
char c;
while (c=' '||c==' '||c=='
')
c=getc(f);
//可以通过显式地进行比较来避免这种问题
if((x=y)!=0)
//foo是程序示例中经常出现的函数名,经常出现的变量名为bar,两者经常一起搭配使用
foo();
///"="符号写成"=="
//下面的语句功能是filedesc存储函数open的返回值,然后通过比较返回值是否小于0来判定
//open函数是否成功执行,但这里将"="符号写成"==",也就是本来的赋值操作变成了比较操作
//比较的结果为0或者1,不会小于0.导致这个判定语句无法按照实现功能.
if((filedesc==open(argv[i],0))<0)
error();
}
"="是赋值运算符,"=="是比较运算符。两者的性质不同,混用会导致错误。
1.2 &和 |不同于 && 和 ||
1.概念区别
- & 和 | 是按位运算符,对操作数的处理方式是将其视作一个二进制的位序列,分别对其每个位进行操作
- && 和|| 是逻辑运算符,其对操作数的处理是将其视作“真”(一般用非0表示)或者“假”(一般用0表示),当结果为“真”时返回1,结果为“假”时返回0,也就是说其返回的值只能为0或者1,并且在表达式中,如果左操作数能够确定最终结果,右侧操作数就不会进行运算。
相关比较代码如下:
i=0;
while(i<tabsize && tab[i] !=x)
i++;<code>
这是一段查找制定元素的检查代码,当等于tabsize时还没有找到x元素时停止循环。
下面将 “&&” 更改为 “&” 来查看其区别:
i=0;
while(i<tabsize & tab[i] !=x)
i++;
这里代码可能还会可能继续工作,可能的原因如下:
- 在 & 两侧的比较运算的结果在“真”的时候为1,在“假”的时候为0,也就是说x和y的取值范围为0或者1,而按位运算得出的结果也是1或者0,即在这种情况下 x&y 等同于 x&&y。但是,如果在 & 两侧的结果用了除 “1“ 之外的数值来表示”真“的话,代码将无法工作。
- 假设程序计数变量i递增到tabsize时,如果是&&的话会跳过右边比较,因为左操作数的结果为0,已经确定了结果了。而按位运算符&则需要对两边操作数进行求值,它会继续检查”tab[i]!=x“这条语句,但tab[i]这个元素并不存在。这里仅仅是读取其数值,如果是对其进行引用的话就会出现错误。
1.3词法分析中的”贪心法“
#include <stdio.h>
int main(void)
{
///贪心法
//每一个符号都应该包含尽可能多的字符,从左到右一个字符一个字符地读入,如果该
//字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串
//是否可能是一个符号的组成部分,如果可能,继续读入下一个字符,重复以上,直到读入的
//字符组成的字符串已不再可能组成要给有意义的符号
//示例1
y=x/ *p;
//示例2
y=x/(*p);
//示例3
y=x/*p;
//上面两个赋值操作的区别不一样,由于/*在编译器作为一个注释的开始,因此编译器会判定
//示例3中/*是一个注释符号,而不断读入字符,直到*/
//示例 1和示例2是对示例3的改进,同时也要注意对老版本的C语言中与现在C语言符号的差异性
}
1.4 整数常量###
#include <stdio.h>
int main(void)
{
//输出数值操作
struct {
int part_number;
char *description;
}partable[]={
046, "left-handed widget",
047, "right-handed widget",
125, "frammis"
};
//上面的代码会输出两个8进制的值,其中046,047代表的是两个八进制的值
//因为整型常量的第一个字符0是八进制的表示
}
1.5 字符和字符串
#include <stdio.h>
int main(void)
{
///字符串
printf("Hello world
");
char hello1[]={'H','e','l','l','o',' ','w','o','r','l','d','
',' '};
printf(hello1);
//用双引号引起的字符串,代表的是一个指向无名数组起始字符的指针,该数组
//被双引号之间的字符以及一个额外的二进制值为0的字符' '初始化,因此两
//个printf()的输出一致
///字符
//用单引号包括的字符其实是一个整数,对应在编译器采用的字符集中的序列值
//因为' '的对应的整数值为0,因此下面将' '改为0,仍然得到相同的输出
char hello2[]={'H','e','l','l','o',' ','w','o','r','l','d','
',0};
printf(hello2);
///字符和字符串两者混用的错误
//这里'/'是对应的整型常量而不是指针,因此出错
char *slash='/';
//printf输出应该有双引号的字符串,而这里是单引号,因此出错
printf('
');
return 0;
}