汇聚点滴启迪思维(三)

news/2024/12/26 4:42:30/

switch存在的问题

缺少default语句

switch语句可以包含一个可选的default语句,用于处理没有与任何case标签匹配的情况。如果没有default语句,并且没有与表达式匹配的case标签,程序将不会执行任何操作。

除了case

switch包含的大括号中间可以变量声明、赋值等操作,但是这些操作无法执行,因为switch只执行case匹配的语句

穿透

当某个case块的末尾没有break语句时,程序会继续执行下一个case块的代码,直到遇到break语句或者switch语句的末尾。这种穿透特性在某些情况下是非常有用的,它允许你共享代码块而不需要重复编写相同的代码。然而,它也容易导致逻辑错误,特别是当你不小心忘记添加break语句时。

下面是一个使用switch穿透特性的例子:

int main() {int num = 2;switch (num) {case 1:printf("Case 1\n");// 没有break,会穿透到case 2case 2:printf("Case 2\n");// 没有break,会穿透到case 3case 3:printf("Case 3\n");break; // 在这里停止穿透default:printf("Default case\n");break;}return 0;
}

在这个例子中,当num为2时,输出将是:

Case 2
Case 3

这是因为case 2的末尾没有break语句,所以程序继续执行case 3的代码。然而,这种穿透特性也可能导致意外的行为,特别是当你不希望它发生时。因此,在使用switch语句时,你应该清楚地知道何时使用穿透特性,何时需要添加break语句来防止穿透。

关于break跳到了那里

大家来看下面的例子

switch(line){case THING1: doit1();break;case THING2:if(x == STUFF){do_first();if(y == OTHER)break;}//程序员想让程序跳到这里default: .......//各种业务
}//实际跳到这里use_modes();

原本想从if语句中跳出,但是break实际跳出了最近的switch语句,程序跳出了switch语句,执行了use_modes(),这样给程序埋下了隐患。

关于书写格式

在C语言中,如果两个字符串常量在代码中相邻出现,并且它们之间仅由空白字符(如空格、制表符或换行符)分隔,或者根本没有分隔符,那么它们会被编译器自动合并成一个字符串。这是C语言的一个特性,允许程序员在编写代码时以更灵活的方式处理字符串。

以下是一个简单的示例,展示了C语言中相邻字符串常量被自动合并的特性:


#include <stdio.h>int main() {printf("这是第一个字符串""这是第二个字符串\n");return 0;
}

然而这种自动合并意味着在字符串初始化时漏掉一个逗号,编译器不会发出任何错误信息,悄悄的把两个字符串合并在一起

int main() {char strArray[][40] = {"Hello""World","C Programming","is fun but hard" };int numRows = sizeof(strArray) / sizeof(strArray[0]);for (int i = 0; i < numRows; i++) {printf("%s\n", strArray[i]);}return 0;
}

这样二维数组从四行变为了三行。字符串的数目比预期少了一个。当程序想修改第二行数组字符串时却修改了别的字符串。

缺省带来的问题

在C语言中,如果你定义了一个函数而没有指定其作用域(即使用static关键字),那么该函数默认具有全局可见性。这意味着该函数可以在整个程序中被访问和调用。虽然这种默认的全局可见性在某些情况下可能很方便,但它也可能带来一些问题:

1‌、命名冲突‌:当多个文件或模块中定义了相同名称的函数时,就会发生命名冲突。这可能导致链接错误或不可预测的行为,因为编译器不知道应该使用哪个函数的定义。

2、代码维护困难‌:全局可见的函数使得代码更难以维护和理解。因为任何文件都可以调用这些函数,所以很难跟踪函数的调用关系和依赖关系。

3‌、潜在的错误‌:全局可见的函数更容易被误用或滥用。其他开发者可能会在不了解函数用途或副作用的情况下调用它们,从而导致程序错误或不稳定。

为了避免这些问题,你可以采取以下措施:

1‌、使用static关键字‌:在函数定义前加上static关键字,可以将函数的可见性限制在定义它的文件内。这有助于避免命名冲突和减少代码之间的依赖关系。

2、模块化设计‌:将程序划分为多个模块,每个模块只暴露必要的接口给其他模块。这可以通过头文件和源文件分离来实现,以及使用static函数来隐藏模块内部的实现细节。

3‌、命名规范‌:采用一致的命名规范来减少命名冲突的可能性。例如,可以使用前缀或后缀来标识函数所属的模块或库。

符号重载

不同的关键字在不同的环境中具有不同的意义,下表描述了部分关键字的重载情况

符号意义
static

在函数内部,表示变量的值在各个调用间一直保持延续性

在函数这一级,表示该函数只对本文件可见

extern

用于函数定义,表示全局可见

用于变量,表示在其他地方定义

void

作为函数的返回类型,表示不返回任何值

在指针声明中,表示通用指针的类型

位于参数列表中,表示没有参数

*

乘法运算符

用于指针,间接引用符

声明中,表示指针

&

AND操作符

取地址操作符

=赋值
==比较运算符

<=

<<=

小于等于运算符

左移复合赋值运算符

<

小于运算符

#include指令的左定界符

( )

在函数定义中,包围形式参数

调用一个函数

改变表达式的运算次序

将值转换为其他类型(强制类型转换)

定义带参数的宏

包围sizeof操作符的操作数

还有些奇怪的例子让大家恼火

if(x>>4)

这是啥意思,是x远远大于4

p = N * sizeof * q;

能不能马上判断出,这个乘号是一个还是两个

apple = sizeof(int) * p;

这代表设么意思,是int的长度乘p,或者把p强制转换为int,然后进行sizeof操作。

运算优先级带来的问题

运算符优先级是指不同运算符在表达式中按照一定的顺序进行运算的规则。这个规则决定了在没有括号明确指定顺序时,运算的执行顺序。具有高优先级的运算符会先于低优先级的运算符执行。然而,运算符优先级在使用中也存在一些问题,容易让程序员产生误解或错误

1、sizeof运算符的特殊性‌:

当sizeof的操作数是一个类型名时,两边必须加上括号。这容易让人误以为sizeof是一个函数。

例如:sizeof(int) 是正确的,而 sizeof int 是错误的。

‌2、点运算符(.)和星号运算符(*)的优先级‌:

点运算符(.)的优先级高于星号运算符(*)。

例如:表达式 *p.f 的实际结果是 *(p.f),而不是 (*p).f

‌3、方括号运算符([])和星号运算符(*)的优先级‌:

方括号运算符([ ])的优先级高于星号运算符(*)。

例如:表达式 int* ap[] 的实际结果是 int*(ap[]),而不是 int(*ap)[]

‌4、函数运算符()和星号运算符(*)的优先级‌:

函数运算符()的优先级高于星号运算符(*)。

例如:表达式 int* fp() 的实际结果是 int*(fp()),而不是 int(*fp)()

‌5、比较运算符和位运算符的优先级‌:

比较运算符(如 == 和 !=)的优先级高于位运算符。

例如:表达式 val & mask != 0 的实际结果是 val & (mask != 0),而不是 (val & mask) != 0

比较运算符和赋值运算符的优先级‌:

6、比较运算符的优先级也高于赋值运算符。

例如:表达式 c = getchar() != EOF 的实际结果是 c = (getchar() != EOF),而不是 (c = getchar()) != EOF

7、算术运算符和移位运算符的优先级‌:

算术运算符的优先级高于移位运算符。

例如:表达式 msb << 4 + lsb 的实际结果是 msb << (4 + lsb),而不是 (msb << 4) + lsb

‌8、逗号运算符的优先级‌:

逗号运算符在所有运算符中优先级最低。

例如:表达式 i = 1, 2; 的实际结果是 (i = 1), 2;,即 i 被赋值为 1,然后整个表达式的结果是 2(但通常不会使用这种写法,因为它可能导致代码难以理解和维护)。

为了避免这些问题,程序员需要熟悉C语言中各种运算符的优先级规则,并在编写代码时谨慎使用括号来明确表达式的运算顺序。同时,保持代码的清晰和可读性也是非常重要的,这有助于减少因运算符优先级问题而导致的错误。


http://www.ppmy.cn/news/1557844.html

相关文章

搭建Elastic search群集

一、实验环境 二、实验步骤 Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎Elasticsearch目录文件&#xff1a; /etc/elasticsearch/elasticsearch.yml#配置文件 /etc/elasticsearch/jvm.options#java虚拟机 /etc/init.d/elasticsearch#服务启动脚本 /e…

【Django开发】前后端分离django美多商城项目第11篇:商品数据库表设计,1. SPU介绍【附代码文档】

本教程的知识点为&#xff1a; 项目准备 项目准备 配置 1. 修改settings/dev.py 文件中的路径信息 2. INSTALLED_APPS 3. 数据库 用户部分 图片 1. 后端接口设计&#xff1a; 视图原型 2. 具体视图实现 用户部分 使用Celery完成发送 判断帐号是否存在 1. 判断用户名是否存在 后…

分布式爬虫scrapy-redis

Scrapy 爬虫,虽然爬虫是异步加多线程的,但是我们只能在一台主机上运行,所以爬取效率还是有限的,分布式爬虫则是将多台主机组合起来,共同完成一个爬取任务,这将大大提高爬取的效率。 分布式爬虫解决的问题1:爬虫任务共享 所谓分布式爬虫,我们需要做的就是在多台主机上…

Day1 苍穹外卖前端 Vue基础、Vue基本使用方式、Vue-router、Vuex、TypeScript

目录 1.VUE 基础回顾 1.1 基于脚手架创建前端工程 1.1.1 环境要求 1.1.2 脚手架创建项目 1.1.3 工程结构 1.1.4 启动前端服务 1.2 vue基本使用方式 1.2.1 vue 组件 1.2.2 文本插值 1.2.3 属性绑定 1.2.4 事件绑定 1.2.5 双向绑定 1.2.6 条件渲染 1.2.7 跨域问题 1.2.8 axios 1.…

Excel中match()函数

函数功能概述 MATCH 函数是 Excel 中用于在指定区域中查找特定值的位置的函数。它返回指定数值在指定数组区域中的位置。这个位置是相对于查找区域的相对位置&#xff0c;而不是绝对的单元格位置。语法结构 MATCH(lookup_value, lookup_array, match_type)lookup_value&#xf…

WebRTC服务质量(08)- 重传机制(05) RTX机制

一、前言&#xff1a; RTX协议&#xff08;Retransmission&#xff0c;即重传协议&#xff09;是 WebRTC 中用于处理丢包恢复的一部分。由于网络通信中的丢包不可避免&#xff0c;WebRTC RTP协议栈支持多种丢包恢复机制&#xff0c;其中之一便是通过RTX协议实现的重传机制。 …

Spring Cloud OpenFeign快速入门demo

一、应用场景 Spring Cloud OpenFeign 是一个声明式的 HTTP 客户端&#xff0c;旨在简化微服务之间的通信。它使得开发者能够通过简单的接口定义和注解来调用 RESTful API&#xff0c;极大地减少了样板代码。以下是一些典型的应用场景&#xff1a; 微服务间调用&#xff1a;在…

小程序 - 模拟时钟

微信小程序常用API练习 - 模拟时钟小程序开发笔记 模拟时钟 “模拟时钟”微信小程序是一个简约风格的动态时钟&#xff0c;该时钟时间与系统时间一致&#xff0c;且时针、分针、秒针会与系统时间同步更新&#xff0c;用户可以很方便地查看时间。下面将对“模拟时钟”微信小程序…