C语言 | C语言深度解剖 ——章节2 符号

C语言基本符号表

在这里插入图片描述

注释符号 // /*

几个似非而是的注释问题

下面例子那个编译器会报错呢?

A) int//i;
B)char* s=“abcdefgh //hijklmn”;
C) //Is it a
valid comment?
D) in//t i;

答案是只有最后一条不正确,原因如下
A)如果编译器是剔除注释部分,那 inti 会报错,但是编译器不是简单地剔除而是替换为空格,所以是 int i;即正确 如下面也是正确的
在这里插入图片描述
B)双引号是字符串常量,双斜杠也不例外,/*也一样,只要在双引号内都算字符串
C)\是一个连续符,所以正确这段注释 包含下面这一行
D)由于是替换成空格,当前就为in t i;自然不对了

注:/**/不能嵌套/ * 总是与离它最近的 * /匹配

y=x/*p

这段主要想表示 x除以p指向的内存的值,把结果赋给y?但编译出错,因为编译器会直接把/*当做注释的开始,那么修改如下
y = x/ p 或者 y = x/( p)
所以只要斜杠要斜杠和星号之间没有空格,都会被当作注释的开始。

出色注释的基本要求

  1. 注释应当准确、易懂、防止有二义性。避免错误的注释
  2. 边写代码边注释,修改代码同事修改相应的注释,不再有用的注释及时移除
  3. 注释要简单明了、不是文档
  4. 一目了然的语句不加注释
    例如:i++; /* i 加 1 */
    多余的注释
  5. 对于全局数据(全局变量、常量定义等)必须要加注释
  6. 注释采用英文,避免注释写缩写,特别是不常用的
  7. 注释的位置与被描述的代码相邻,可以是同一行,也可以是上一行
  8. 当代码比较长、特别是多重嵌套时,应在一些段落的结束处加注释,方便阅读
  9. 注释的缩进要与代码的缩进一致,长度对齐
  10. 注释代码应注意写的是“为何做(why)”而不是“怎么做(how)”
  11. 数值的单位一定要注释,比如说是毫米、米、千米,时间的单位必须是、分、秒、毫秒等
  12. 对变量的范围给出注释
  13. 对一系列的数字编号给出主食,尤其是底层驱动时(比如管脚编号)
  14. 对于函数的入口出口数据给出注释

连接符和转义符 \

C语言中以反斜杠(\)表示断行。编译器会剔除反斜杠
注:反斜杠之后不能有空格,下一行之前也不能有空格
如下例子均是合法的
在这里插入图片描述
反斜杠除了用作连接符、转义字符
常用的转义字符和含义如下

转义字符意义
\n回车换行
\t横向跳到下一制表位置
\v竖向跳格
\b退格
\r回车
\f走纸换页
\反斜杠符“\”
单引号符
\a响铃
\ddd1~3位八进制数所代表的字符
\xhh1~2位十六进制所代表的字符
C语言字符集中的任何一个字符均可用转义字符来表示,表中的\ddd和\xhh正是为此提出的。ddd和hh分别为八进制和十六进制的ASCII代码,如\102表示字母“B”,\134表示斜线,\X0A表示换行等

单引号、双引号

双引号""常用来引起来字符串常量,且占用2byte
单引号’‘用来引起来的是字符常量,占用1byte
如下举例
1,‘1’,“1”
第一个为整形常数,32位系统下占4 byte
第二个为字符常量,占1个byte
第三个是字符串常量,占2个byte
而字符在内存里是以ASCAII码存储的,所以字符串常量可以与整形常量活变量进行运算,如’A’+1

花括号

花括号即用来打包,如if、while、for、switch等语句都在用它,将一段语句活代码打包起来,形成一个整体,那么如下例子有什么区别呢?是否可行呢?

char a[10] = {“abcde”};
char a[10] { = “”};
在这里插入图片描述

可以看到第二个是不行的,因为大括号包含的表达式不正确,而如果是以下则是正确的

char b[10]; if(0){“abcde”;}

由于第一个{“abcde”}表述的是char 数组中一个成员内容,而第二个则是一个正确的表达式
注:如上char a[10] = {“abcd”};是一个字符长度为10字符串表达式,不能单独修改数组内容
即a[i]是无法取到的,而只能直接打印a变量,如下使用
在这里插入图片描述
而只有char a[10] = {‘a’,‘b’} 才可以取数组内容 如a[0] = a
而当char a[10] = {“abc”,“cde”};则会抛出初始值定项太多,即此时字符串的话只能有一个
在这里插入图片描述
而char a[] 和 char *b使用情况类似,但大小不同,具体如下图,而char *b的大小是指针大小,所以永远为4,不随字符串长度决定,具体待第四章数组与指针再继续学习

char a[10] = {“abc”};
char *b = “efg”;
在这里插入图片描述

运算符 10种

1.算数运算符 7个

用于各类数值运算。包括加(+)、减(-)、乘(*)、除(/)、求余(或称模运算,%)、自增(++)、自减(–)共七种。

++、–操作符

++、–作为前缀时,是先做自加、自减,然后再做别的运算,但作为后缀时,什么时候自加自减呢?例子如下:

i=3
A) j= (i++,i++,i++); //i=6,j=5
B) k = (i++) + (i++) + (i++); .//i=6,k=9
C) for (i=0;i<10;i++){…} //i = 10 与++i结果同样

计算结果已如上,而原因是
A)逗号表达式,i在遇到每一个逗号后,认为本次运算已经结束,i这时候自加。
比如

int x;
int i = 3;
x = (++i,i++,i+10);

此时i = 5;x=15 ,即i在遇到每一个逗号后,都认为本次计算结束这是后i才会自加

B)i遇到分号才认为本计算单位结束,此时i再自加,且加入括号,则会先计算括号内,在计算等号
C)例子i与10进行比较后,在自加,此时i=10
而书中的例子 打印如下,但此时循环会持续,不会停在10
在这里插入图片描述

再来看两个个例子

(++i)+(++i)+(++i)

int i = 3;
(++i)+(++i)+(++i)

如上表达式最后内容结果i为多少呢,4+5+6 = 15?
在这里插入图片描述
可以看到结果是18,因为i经过3次自加后已经变为6 而三次 则是 6+6+6=18
那当我们去除括号后呢?

++i+++i+++i

在这里插入图片描述
可以看到此时编译器是报错的,其实是因为不知道i++还是++i

而只有加入空格,才能正常计算,且结果如上

p = ++i+ ++i+ ++i;

而a++b则是 a++ b ,结果如下
在这里插入图片描述
即a+b后赋值给p,再对a++

贪心法

编译器从左到右一个一个字符的读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号。这种处理的策略被称为“贪心法”。

而需要注意的是:除了字符串与字符常量,符号中间不能嵌有空白(空格、制表符、换行符等)。
比如 ==是单个符号,而= =是两个等号 ,那么根据这个就能判断出a++b表达式与a++ +b一致, 而a+++++b的表达式呢?
仍然是错误表达式
在这里插入图片描述

2/(-2)的值是多少?

2/(-2)的值为多少?2%(-2)的值呢? ,答案为-1 和0
先看下规则,假如a除以b,商为q,余数为r
那么
q = a/b
r = a%b
这里不妨假设b大于0,那么a、b、q、r之间是为什么关系呢?

  1. q*b+r== a ;即定义余数的关系
  2. 如果改变a的正负号,希望q的符号也随之改变,但q的绝对值不会变
  3. 当b>0时,我们希望保证r>=0且r<b

这三条性质,是我们认为整数除法和余数应该具备的,但是,很不幸它们很可能不同时成立
先考虑一个简单的例子:3/2 商为1 余数唯一,那么第一条性质满足,在改一下(-3)/2值呢?答案如果是-1,那么余数必定是-1,这样第三条兴致无法满足,如果首先满足第三条性质,即余数为1,这样根据第一条性质商应该为-2,那么第二条又无法满足
因此上述矛盾无法解决,所以此时必须放弃上述中的一跳,所以大多数编译器会放弃第三条,而改为要求余数与被除数的正负号相同
但是,C语言的定义只保证了性质1,以及当a>=0且b>0时,保证|r|<|b|以及r>=0,后面部分的保证与性质2或性质3 比起来,限制性要弱很多

所以如上解释2/(-2)的值-1,2%(-2)的值为0就能解释的通了,即商保证符号相同,余数必须大于等于0

2.关系运算符 6个

用于比较运算。包括大于(>)、小于(<)、等于(==)、 大于等于(>=)、小于等于(<=)和不等于(!=)六种。
在这里插入图片描述

3.逻辑运算符 3个

用于逻辑运算。包括与(&&)、或(||)、非(!)三种。
先看如下例子

int i = 0;
int j = 0;
if ((++i > 0) || (++j >0))
  printf("i=%d j=%d \n",i,j);

结果为 i=1 j=0
我们都知道 || 或是只有一个为真,结果为真,而两个都为假,结果才为假,所以在如上结果中,后面++j>0不会被计算,所以j仍然为0,如果第一个为假,才会去判断第二个
而&& 则是两个均要判断,且只有两个均为真才能进入,一个为假则不能进入

4.位操作运算符 6个

参与运算的量,按二进制位进行运算。包括位与(&)、位或(|)、位非(~)、位异或(^)、左移(<<)、右移(>>)六种。
其中按位异或操作可以实现不用第三个临时变量交换两个变量的值:
在这里插入图片描述

左移和右移

左移运算符"<<“是双目运算符,其功能是把”<<"左边的运算数各二进位全部左移若干位,相当于乘法,即<< 1相当于*2 ,<<2则乘4, <<3则乘8 以此类推
右移运算符“>>”,则是吧左边的运算数个二进制全部右移若干位,相当于除法
需要注意的是:对于有符号数,在右移时,符号位将随同移动

单目就是一个操作数,比如++,a++,操作数只有一个a
双目就是两个操作数,最熟悉的就是+,a+b,计算a、b的和
三目就是三个操作数,?:运算符,比如a?b:c,当a的值为真时,结果是b,否则结果是c。

0x01<<2+3 的值为多少?

你以为的是什么?是不是 1* 4 +3 =7 ?但实际结果却是32,因为"+"号运算符优先级是比移位运算符的优先级高,所以其实是 1 * 2^5 =32
那么0x01<<2+32 或0x01 <<2-3呢?

显然都不行,第一个报错warning: left shift count >= width of type [-Wshift-count-overflow],即已经超出范围
而第二个报错是warning: left shift count is negative [-Wshift-count-negative],即是消极数,所以左移右移的位数不能大于数据长度,不能小于0

5.赋值运算符 11个

用于赋值运算,分为简单赋值(=)、复合算术赋值(+=,-=,*=,/=,%=)和复合位运算赋值(&=,|=,^=,>>=,<<=)三类共十一种。

6.条件运算符 ?:

这是一个三目运算符,用于条件求值(? : )。简化了if-else的操作
表达式1 ? 表达式2 : 表达式3 ,即如果表达式1为帧则选择表达式2为真个条件的值,否则则选择表达式3

7.逗号运算符 ,

用于把若干表达式组合成一个表达式(,)。
常用于for结构的括号内的第一个表达式

for(n = 1, sum = 0; n <= 100; n++) {

8.指针运算符 2个

用于取内容(*)和取地址(&)二种运算。
&var 读作"var 的地址"
取内容、间接寻址运算符,返回操作数指定地址的变量值

int main ()
{
   int  var;
   int  *ptr;
   int  val;

   var = 3000;

   // 获取 var 的地址
   ptr = &var;

   // 获取 ptr 的值
   val = *ptr;
   printf("val=%d\n",var);
   printf("ptr=%d\n",ptr);
   printf("val=%d\n",val);
   return 0;
}

结果如下

val=3000
ptr=296011440
val=3000

9.求字节数运算符 sizeof

用于计算数据类型所占的字节数(sizeof)。,再说第一章已经说了具体sizeof相关用法

10.特殊运算符 3个

有括号(),下标[],成员(→,.)
->成员选择(指针) . 成员选择(对象c)

运算符的优先级

同一优先级的运算符,运算次序由结合方向所决定。
简单记就是:初级运算符( )、[ ]、->、.
高于 单目运算符
高于 算数运算符(先乘除后加减)
高于 关系运算符
高于 逻辑运算符(不包括!)
高于 条件运算符
高于 赋值运算符
高于 逗号运算符。

运算符的优先级表

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一些容易出错的优先级问题

优先级问题表达式经常误认为的结果实际结果
.的优先级高于* ->操作符用于消除这个问题*p.fp所指对象的字段f (*p).f先对p取f对象,作为指针,然后进行解除引用操作。*(p.f)
[]高于*int *ap[]ap是个指向int 数组的指针,int (*ap)[]ap是个元素为int 指针的数组 int * (ap[])
函数()高于*int *fp()fp是个函数指针,所指函数返回int。int (*fp)()fp是个函数,返回int指针 int * int * (fp())
== 和 !=高于位操作(val & mask !=0)(val & mask) != 0val & (mask!=0)
== 和 !=高于赋值符c = getchar() != EOF(c = getchar() )!=EFO)c =( getchar() != EOF)
算术运算符高于位移运算符msb << 3+1(msb << 3)+1msb <<(3+1)
逗号运算符在所有运算符中优先级最低i=1,2i = (1,2)(i =1),2
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值