《C陷阱与缺陷》----词法“陷阱”

news2024/9/22 15:49:10

导言:

由于一个程序错误可以从不同层面采用不同方式进行考察,而根据程序错误与考察程序的方式之间的相关性,可以将程序错误进行划分为各种陷阱与缺陷:
①.词法“陷阱
②.语法“陷阱”
③.语义“陷阱”
④.连接问题
⑤.库函数问题
⑥.预处理器问题
⑦.可移植性缺陷

我们知道程序是由符号序列所组成的。本篇主要考察在程序被词法分析器分解成各个符号的过程中可能出现的问题,也就是词法“陷阱”。

  • 导言:
  • 1.=不同于==
    • 1.1 案例1
    • 1.2 案例2
    • 1.3 启示
    • 1.4 案例3
  • 2.&和 |不同于&&和 ||
  • 3.词法分析中的“贪心法”
    • 3.1 读取规则---“贪心法”:
    • 3.2 注意:
    • 3.3 “贪心法”读取案例1
  • 4.整形常量
  • 5.字符和字符串
    • 5.1 字符
    • 5.2 字符串
  • 6.练习题
    • 6.1 练习题①
    • 6.2 练习题②

1.=不同于==

符号 =作为赋值运算符
符号==作为比较运算符
由于在C语言中赋值操作相对于比较出现更加频繁,所以将字符较少的符号=赋予更常用的含义—赋值操作。
不过这种便利的使用可能导致一个潜在的问题:当程序员本想使用比较运算符却使用了赋值运算符。

1.1 案例1


if(x=y)
break;

该句的本意是想检查x是否等于y;但实际上却是将y的值赋给了x,然后检查表达式结果是否为0。

1.2 案例2

再比如下面这个例子:
例子中循环语句本想跳过空格符,制表符,和换行号;

   while(i=' '||i=='\t'||i=='\n')
   i=getchar();

但是却把比较运算符误写成赋值运算符,因为赋值运算符=的优先级是低于逻辑运算符||,所以语句先将’ ‘赋给了i,然后发先i结果不为0(’ 'ASCII码值是32)根据短路求值原则,左边为真,则右边不再进行,此语句也就是真,因此循环将一值进行下去直到整个文件结束。或者变成一个死循环。

1.3 启示

某些C编译器在发现形如a=b的表达式出现在循环语句的条件判断部分时,会给出警告以提醒程序员。当确实需要对变量进行赋值并检查该变量的新值是否为0时,为了避免该类编译器的警告,我们应该进行显式地比较,比如

if(x=y)
{
  Function();
}

应该写成

if((x=y)!=0)
{
  Function();
}

这样的写法就使得代码的意图一目了然。

1.4 案例3

前面一直谈的是将比较运算符误写成赋值运算符,另一方面,如果把赋值运算符误写成比较运算符,也会造成混淆。

if ((i == fun(a, b)) < 0)
		error();

本语句的原本意思是如果fun函数执行成功则返回0,执行失败则返回-1或者正数,然后再将返回值赋给i,通过比较i的大小来确定是否fun函数执行成功。但实际上是fun函数的返回值与i进行比较,结果只有真与假也就是0或1,永远不可能小于0,所以函数error没有机会调用。也就不知道fun函数调用是否失败。

2.&和 |不同于&&和 ||

3.词法分析中的“贪心法”

C语言有许多符号,比如只有一个字符长的单字符符号,和多个字符长的多字字符。比如== 和 /*。
当C编译器读取符号时,是如何读取的呢?

比如读入一个字符’/‘后又跟了一个字符’ *',那编译器是将其作为两个分别的符号对待,还是合起来作为一个符号对待?

3.1 读取规则—“贪心法”:

每个符号应该包含尽可能多的字符。
也就是说,编译器将程序分解成符号的方法是:
从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成字符串不再可能组成一个有有意义的符号。
这个处理策略就被称为“贪心法”。

3.2 注意:

需要注意的是,除了字符串与字符常量,符号的中间不能嵌有空白(空格符,制表符和换行符)。
比如:

a---b 与表达式
a-- -b的含义相同,但与
a- --b的含义完全不同。

3.3 “贪心法”读取案例1

本代码想表达的意思是,x先除以指针p指向的数,然后再将所得的商,赋给y.

y=x / *p;// *p指向的是被除数

而实际上,/*被编译器理解为一段注释的开始,编译器将不断的读入字符,直到另一个 * /出现为止。
也就是说该代码,直接将x的值赋给了y,根本不会顾及后面出现的p。

而正确的表达意思应该是这样:

y=x/(*p);//*p指的是被除数

4.整形常量

我们知道一个整形常量第一个字符是数字0,则这个常量代表的是八进制位数。
因此10与010的意思不一样

而有的C编译器会把8,9也作为八进制数字来处理,感觉很奇怪,所以ANSI C标准禁止了这种用法,以免混乱。
不过有时候,在上下文中为了格式对齐,可能会将十进制数写成八进制数。比如:

035
044
123//只是单词的使格式对齐没有多的意思,

5.字符和字符串

C语言中字符与字符串的区别在于单引号与双引号的使用,在某些情况下如果把两者弄混,编译器并不会监测报错,从而运行时产生难以预料的结果。我们先来看看字符与字符串的区别

5.1 字符

用单引号引起的一个字符实际上代表一个整数,整数对应着ASCII码值的字符序列值,比如’a‘的含义与0141(八进制)或者97(十进制)严格一致。

整数(一般为16位或32位)的存储空间可以容纳多个字符(一般位8位)因此有的C编译器允许在一个字符常量(以及字符串常量)中包含多个字符。也就是用‘yes’代替“yes”不会被该编译器监测到。“yes”代表的意思是依次包含‘y’,‘e’,‘s’以及空字符‘\0’的4个练习内存单元的首地址。而‘yes’的含义并没有准确的进行定义,但大多数编译器理解为“一个整数值”
在这里插入图片描述

5.2 字符串

用双引号引起的字符串,代表的是一个指向无名数组起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制为0的字符’0\‘初始化。

#include <stdio.h>
int main()
{
	printf("xiao tao lai lo\n");
	char ch[100] = "xiao tao lai lo";
	//ch是数组名,数组名是首元素的地址,也就是首字符的地址。
	printf(ch);//ch里存放着首元素的地址
	

}

在这里插入图片描述

这说明这两个打印效果是一样的,所以一个字符串代表着一个指向无名数组起始字符的指针。可以用一个指针来存放字符串

#include <stdio.h>
int main()
{
char* p = "xiao tao lai lo";
	//指针p里面存放的就是字符串的首字符地址。
	printf(p);
}

在这里插入图片描述

6.练习题

6.1 练习题①

在这里插入图片描述
答案:
根据“贪心法”规则,在编译器读入>之前,就已经将- -作为一个符号,而后面的>不能和前面的组成一个符号。

6.2 练习题②

在这里插入图片描述

答案:
这个代码唯一有意义的解析是这样:

a++ + ++b

但是根据“贪心法”规则,上面代码应该被分解为

a++ ++ +b

这个式子从语法上来说是不对的,它应该写成

((a++)++)+b

但是,a++的结果不能作为左值,因此编译器不会接收a++作为后面的++运算符的操作数,该代码没有意义

…………………………………………………………请添加图片描述…………………………………………………………
………………………………………………………………………加油…………………………………………………………

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/351667.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Microsoft Office 2021 / 2019 Direct Download Links

前言 微软Office在很长一段时间内都是最常用和最受欢迎的软件。从小型创业公司到大公司,它的使用比例相当。它可以很容易地从微软的官方网站下载。但是,微软只提供安装程序,而不提供完整的软件供下载。这些安装文件通常比较小。下载并运行后,安装的文件将从后端服务器安装M…

2023美赛B题思路数据代码分享

文章目录赛题思路2023年美国大学生数学建模竞赛选题&论文一、关于选题二、关于论文格式三、关于论文提交四、论文提交流程注意不要手滑美赛B题思路数据代码【最新】赛题思路 (赛题出来以后第一时间在CSDN分享) 最新进度在文章最下方卡片&#xff0c;加入获取一手资源 202…

【软件架构设计】SOA/软件架构设计---面向服务的架构(SOA详细解释)

文章目录面向服务的架构SOA 概述1. 服务的基本结构2.SOA 设计原则3. 服务构件与传统构件SOA 的关键技术1. UDDI2.WSDL3.SOAP4.RESTSOA 的实现方法1.Web Service2. 服务注册表3. 企业服务总线微服务1.微服务的优势2. 微服务面临的挑战3.微服务与 SOA面向服务的架构 迄今为止&am…

使用html-to-image代替html2canvas,结合jspdf实现下载pdf(下载截图下载前端dom元素)

一、问题 一开始的时候&#xff0c;准备使用html2canvasjspdf来实现的&#xff0c;但是遇到了一个麻烦的问题&#xff0c;在其他项目中使用html2canvas没有任何问题&#xff0c;但是在要开发的项目中使用&#xff0c;就给我报错&#xff0c;是真滴烦。 html2canvas报错 Uncau…

map和set介绍及其底层模拟实现

致努力前行的人&#xff1a; 要努力&#xff0c;但不要着急&#xff0c;繁花锦簇&#xff0c;硕果累累都需要过程&#xff01; 目录 1.关联式容器 2.键值对 3.树形结构的关联式容器 3.1set的介绍 3.2set的使用 3.3multiset的使用 3.4map的使用 3.5multimap的使用 4.常见的面试题…

【Ctfshow_Web】信息收集和爆破

0x00 信息收集 web1 直接查看源码 web2 查看不了源码&#xff0c;抓包即可看到&#xff08;JS拦截了F12&#xff09; web3 抓包&#xff0c;发送repeater&#xff0c;在响应包中有Flag字段 web4 题目提示后台地址在robots&#xff0c;访问/robots.txt看到Disallow: /fl…

vite结合ts使用mock模拟数据,实现前后端异步开发

vite结合ts&#xff0c;vue3 使用mock模拟数据&#xff0c;实现前后端异步开发 第一步&#xff1a;安装依赖 安装mock&#xff1a;npm install mockjs --save-dev安装vite-mock插件&#xff1a;npm install vite-plugin-mock --save 注解1&#xff1a; npm 安装依赖包的时候…

消息中间件----内存数据库 Redis7(第3章 Redis 命令)

Redis 根据命令所操作对象的不同&#xff0c;可以分为三大类&#xff1a;对 Redis 进行基础性操作的命令&#xff0c;对 Key 的操作命令&#xff0c;对 Value 的操作命令。3.1 Redis 基本命令首先通过 redis-cli 命令进入到 Redis 命令行客户端&#xff0c;然后再运行下面的命令…

2023年浙江建筑八大员(市政质量员)考试试题题库及答案

百分百题库提供建筑八大员&#xff08;质量员&#xff09;考试试题、建筑八大员&#xff08;质量员&#xff09;考试预测题、建筑八大员&#xff08;质量员&#xff09;考试真题、建筑八大员&#xff08;质量员&#xff09;证考试题库等,提供在线做题刷题&#xff0c;在线模拟考…

如何在 Debian 11 上设置一个静态 IP 地址

当你在电脑上安装一个新的操作系统时&#xff0c;DHCP服务器会给你分配一个动态IP地址。然而&#xff0c;在各种情况下&#xff0c;你可能需要在你的机器上设置一个静态IP地址&#xff0c;例如&#xff0c;当你正在托管一个网络服务器&#xff0c;或者任何服务需要一个IP地址而…

K_A12_007 基于STM32等单片机驱动AS608光学指纹识别模块 OLED0.96显示

K_A12_007 基于STM32等单片机驱动AS608光学指纹识别模块 OLED0.96显示一、资源说明二、基本参数参数引脚说明三、驱动说明对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RCAS608光学指纹模块1.2、STM32F103C8T6AS608光学指纹模块五、基础知识学习与相关资料下载六、视…

【自学Linux】Linux一切皆文件

Linux一切皆文件 Linux一切皆文件教程 Linux 中所有内容都是以文件的形式保存和管理的&#xff0c;即一切皆文件&#xff0c;普通文件是文件&#xff0c;目录是文件&#xff0c;硬件设备&#xff08;键盘、监视器、硬盘、打印机&#xff09;是文件&#xff0c;就连套接字&…

小红书数据平台:笔记爆文率提升的三大秘诀公式!

导语 对于小红书商家 / 博主来说&#xff0c;写出爆文就像买彩票&#xff0c;根本不能预知哪一篇会爆。2023年&#xff0c;小红书哪些内容会脱颖而出呢&#xff1f;我们又该如何把握热点趋势&#xff0c;实现优质内容转化出爆文~ 美妆作为小红书的长红赛道&#xff0c;本文我…

如何停止/重启/启动Redis服务

一、命令行直接启动/停止/重启redis 可以直接通过下面的命令启动/停止/重启redis /etc/init.d/redis-server start 启动redis服务 /etc/init.d/redis-server stop 停止redis服务 /etc/init.d/redis-server restart 重启redis服务1、启动redis服务…

BUUCTF-firmware1

题目下载&#xff1a;下载 新题型&#xff0c;记录一下 题目给出了flag形式&#xff0c;md5{网址&#xff1a;端口}&#xff0c;下载发现是一个.bin文件 二进制文件&#xff0c;其用途依系统或应用而定。一种文件格式binary的缩写。一个后缀名为".bin"的文件&#x…

40/365 javascript 数据类型

1.数据类型 number类型&#xff1a;整数&#xff0c;小数都属于这一类&#xff0c;不具体区分 字符串&#xff1a;hello, "hello" 布尔类型&#xff1a;true,false 逻辑运算符&#xff1a; && || ! 比较运算符&#xff1a; : 类型不一致&#x…

openGauss数据库共享存储特性简介

openGauss 3.1.1是openGauss 5.0.0 release版本的Preview版本&#xff0c;希望广大社区伙伴和开发者基于此版本进行场景化验证&#xff0c;提前发现问题并反馈社区&#xff0c;社区将在LTS版本发布前进行问题修复。当前文档说明范围仅限企业版。 文章目录版本介绍继承功能&…

轻松在 MAUI 应用中播放音视频,MediaElement 现已发布!

最受期待的 .NET MAUI 控件之一&#xff1a;MediaElement 现已发布。有了 MediaElement&#xff0c;您可以轻松地在 .NET MAUI 应用程序中播放音频和视频&#xff0c;在这篇文章中&#xff0c;您将了解到有关 MediaElement 第一个版本的所有信息以及我们对未来的计划&#xff0…

8086汇编-35更灵活定位内存地址04

#pragma once/*35-更灵活定位内存地址04不同的寻址方式的灵活应用如果我们比较一下前面用到的几种定位内存地址的方法&#xff08;可称为寻址方式&#xff09;&#xff0c;就可以发现有以下几种方式&#xff1a;&#xff08;1&#xff09;[idata] 用一个常量来表示地址&#xf…

新房装修流程详细步骤有哪些? 新房装修流程注意事项有哪些?

新房装修时&#xff0c;对于装修流程的详细步骤和装修过程中的一些注意事项&#xff0c;有必要了解一下&#xff0c;以免上当受骗&#xff0c;也免得考虑不周&#xff0c;后续造成一些隐患。新房装修流程详细步骤有哪些呢&#xff1f;1.新装装修流程第一步&#xff0c;首先&…