当前位置: 首页 > news >正文

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

导言:

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

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

  • 导言:
  • 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++作为后面的++运算符的操作数,该代码没有意义

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

相关文章:

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

导言&#xff1a; 由于一个程序错误可以从不同层面采用不同方式进行考察&#xff0c;而根据程序错误与考察程序的方式之间的相关性&#xff0c;可以将程序错误进行划分为各种陷阱与缺陷&#xff1a; ①.词法“陷阱” ②.语法“陷阱” ③.语义“陷阱” ④.连接问题 ⑤.库函数问…...

千锋教育+计算机四级网络-计算机网络学习-04

UDP概述 UDP协议 面向无连接的用户数据报协议&#xff0c;在传输数据前不需要先建立连接&#xff1b;目地主机的运输层收到UDP报文后&#xff0c;不需要给出任何确认 UDP特点 相比TCP速度稍快些简单的请求/应答应用程序可以使用UDP对于海量数据传输不应该使用UDP广播和多播应用…...

蓝桥杯算法训练合集十四 1.P08052.P07053.同余方程4.P08015.ascii应用

目录 1.P0805 2.P0705 3.同余方程 4.P0801 5.ascii应用 1.P0805 问题描述 当两个比较大的整数相乘时&#xff0c;可能会出现数据溢出的情形。为避免溢出&#xff0c;可以采用字符串的方法来实现两个大数之间的乘法。具体来说&#xff0c;首先以字符串的形式输入两个整数&…...

判断字符串中的字符的类型isdecimal();isalpha();isdigit();isalnum()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 判断字符串中的字符的类型 isdecimal()&#xff1b;isalpha()&#xff1b;isdigit()&#xff1b;isalnum() [太阳]选择题 对于代码中isdecimal()和isalnum()输出的结果是? s "ABc123&…...

VSCode远程调试Linux代码,python解释器配置

安装插件并配置 安装后找到插件图标&#xff0c;点击 点击SSH上的 号 在弹出框中输入命令&#xff1a;ssh usernameip -p port username: 远程服务器的用户名 ip&#xff1a; 远程ip port&#xff1a;端口号&#xff0c;没有可以不用 输入完毕后点击enter 选择ssh配置文件保存…...

03:入门篇 - CTK Plugin Framework 基本原理

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 CTK Plugin Framework 技术是面向 C++ 的动态模型系统。该系统允许插件之间的松散耦合,并且提供了设计良好的方式来进行功能和数据的交互。此外,它没有预先对插件施加限制,这样就可以很容易地将插件的相关…...

面试攻略,Java 基础面试 100 问(九)

数组有没有 length()方法?String 有没有 length()方法&#xff1f; 数组没有 length()方法&#xff0c;有 length 的属性。String 有 length()方法。JavaScript 中&#xff0c;获得字符串的长度是通过 length 属性得到的&#xff0c;这一点容易和 Java混淆。 在 Java 中&…...

JavaScript 代码不嵌套主义

文章目录前言一、何为嵌套代码二、避免嵌套1.提炼抽取2.反转排列总结前言 看过不少过度嵌套的代码, 我真正意识到问题的严重性是刚入职那会, 我在一个老项目里看到了40个连续的else if, 套了6层的if, for和forEach, 因为我们并没有做什么限制代码嵌套的提前约定. 呃, 那之后认…...

使用默认参数的4大要点

概述 默认参数是C中新增的特性。在C中&#xff0c;可以为函数的参数指定默认值。调用函数时&#xff0c;如果没有指定实参&#xff0c;则自动使用默认参数。默认参数的基本语法这里就不作介绍了&#xff0c;下面重点介绍使用默认参数的一些知识要点。 基本规则 1、当函数中某个…...

Linux文件系统中的硬链接及常见面试题

如果能对inode的概念有所了解&#xff0c;对理解本文会有所帮助。如果对inode的概念不太清楚也没有关系&#xff0c;我们会捎带介绍一下。在文件系统的实现层面&#xff0c;我们可以认为包含两个组件&#xff1a;一个是包含数据块的池子&#xff0c;池子中的数据块是等大小的&a…...

opencv-StereoBM算法

原理解释目前立体匹配算法是计算机视觉中的一个难点和热点&#xff0c;算法很多&#xff0c;但是一般的步骤是&#xff1a;A、匹配代价计算匹配代价计算是整个立体匹配算法的基础&#xff0c;实际是对不同视差下进行灰度相似性测量。常见的方法有灰度差的平方SD&#xff08;squ…...

图像分类竞赛进阶技能:OpenAI-CLIP使用范例

OpenAI-CLIP 官方介绍 尽管深度学习已经彻底改变了计算机视觉&#xff0c;但目前的方法存在几个主要问题:典型的视觉数据集是劳动密集型的&#xff0c;创建成本高&#xff0c;同时只教授一组狭窄的视觉概念;标准视觉模型擅长于一项任务且仅擅长于一项任务&#xff0c;并且需要大…...

Metasploit框架基础(一)

文章目录前言一、基础认知二、批量POC/EXP的构想三、poc检测框架的简单实现四、xray五、Meatsploit框架参考前言 Metasploit 一款渗透测试框架漏洞利用的集合与构建和定制满足你的需求的基础漏洞利用和验证的工具 这几个说法都是百度或者官方文档中出现的手法&#xff0c;说…...

pytorch零基础实现语义分割项目(二)——标签转换与数据加载

数据转换与加载项目列表前言标签转换RGB标签到类别标签映射RGB标签转换成类别标签数据数据加载随机裁剪数据加载项目列表 语义分割项目&#xff08;一&#xff09;——数据概况及预处理 语义分割项目&#xff08;二&#xff09;——标签转换与数据加载 语义分割项目&#x…...

python(8.5)--列表习题

目录 一、求输出结果题 二、计算列表元素个数 三、查找是否存在某元素 四、删除某元素 五、如何在列表中插入元素 六、如何从列表中删除重复的元素 七、 如何将列表中的元素按照从小到大的顺序排序 八、从列表中删除重复的元素 九、大到小的顺序排序 一、求输出结…...

rt-thread pwm 多通道

一通道pwm参考 https://blog.csdn.net/yangshengwei230612/article/details/128738351?spm1001.2014.3001.5501 以下主要是多通道与一通道的区别 芯片 stm32f407rgt6 1、配置PWM设备驱动相关宏定义 添加PWM宏定义 #define BSP_USING_PWM8 #define BSP_USING_PWM8_CH1 #d…...

C语言练习 | 初学者经典练习汇总

目录 1、下面代码输出多少&#xff0c;为什么&#xff1f; 2、你要好好学习么&#xff1f; 3、一直写代码&#xff0c; 4、两个数求最大值 5、输入1-5输出工作日&#xff0c;输入6-7输出休息日&#xff0c;其他输入错误 6、写一个输入密码的代码 7、怎么样当输入数字时候…...

华为OD机试 - 自动曝光(Python) | 机试题算法思路 【2023】

最近更新的博客 华为OD机试 - 卡片组成的最大数字(Python) | 机试题算法思路 华为OD机试 - 网上商城优惠活动(一)(Python) | 机试题算法思路 华为OD机试 - 统计匹配的二元组个数(Python) | 机试题算法思路 华为OD机试 - 找到它(Python) | 机试题算法思路 华为OD机试…...

「6」线性代数(期末复习)

&#x1f680;&#x1f680;&#x1f680;大家觉不错的话&#xff0c;就恳求大家点点关注&#xff0c;点点小爱心&#xff0c;指点指点&#x1f680;&#x1f680;&#x1f680; 目录 第五章 相似矩阵及二次型 &2&#xff09;方阵的特征值与特征向量 &3&#xff…...

1.1 硬件与micropython固件烧录及自编译固件

1.ESP32硬件和固件 淘宝搜ESP32模块,20-50元都有,自带usb口,即插即用. 固件下载地址:MicroPython - Python for microcontrollers 2.烧录方法 为简化入门难度,建议此处先使用带GUI的开发工具THonny,记得不是给你理发的tony老师. 烧录的入口是: 后期通过脚本一次型生成和烧…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...