C陷阱与缺陷——第3章 语义陷阱

news2024/11/17 21:52:41

1. 指针和数组

C语言中只有一维数组,而且数组的大小必须在编译器就作为一个常数确定下来,然而在C语言中数组的元素可以是任何类型的对象,当然也可以是另外的一个数组,这样,要仿真出一个多维数组就不是难事。

对于一个数组,我们只能够做两件事:确定数组大小;获得指向该数组下标为0的元素的指针。

int calendar[12][31];

以上语句声明了calendar是一个数组,该数组拥有12个数组类型的元素,其中每个元素都是一个拥有31个整型元素的数组。

如果calendar不是用于sizeof的操作数,那么calendar总是被转换成一个指向calnedar数组的起始元素的指针。

任何指针都是指向某种类型的变量。

给一个指针加上一个整数,与给该指针的二进制表示加上同样的整数,两者的含义截然不同。

把两个指针相减也是有意义的,但是这两个指针必须指向同类型的变量,否则结果未定义。

当p是int指针,a是int一维数组名时,以下写法正确

p = a;

以下写法错误:

p = &a;

因为&a是一个指向数组的指针,而p是一个指向整型变量的指针。*a是数组a中下标为0的元素的引用。*(a+i)即数组a中下标为i的元素的引用,简记为a[i]。多数情况下i[a]和a[i]的意义相同,但是不推荐使用前面的写法。

calendar[4]是calendar数组的第5个元素,calendar[4]的行为表现为一个有着31个整型元素的数组的行为。

声明指向数组的指针的方法,举例如下:

int calendar[12][31];
int (*monthp)[31];
monthp = calendar;

2. 非数组的指针

假设我们用两个字符串s和t,我们希望将这两个字符串连接成单个字符串r,借助库函数strcpy和strcat正确写法如下:

char *r, *malloc();//声明malloc原型,这样后面就不用再写转换成char*类型了
r = malloc(strlen(s) + strlen(t) + 1); //字符串结尾为'\0',strlen不用加上这个计数1
if (!r)//当malloc无法完成内存分配时,会返回NULL
{
    complain();//报错
    exit(1);//退出
}
strcpy(r, s);
strcpy(r, t);

//使用一段时间后

free(r); //对动态分配内存程序员负责回收

主要注意到点是:

  • 字符串以空字符'\0'作为结束标志,库函数strlen返回参数中字符串所包含的字符数组,而结尾标志的空字符并未计算在内;
  • malloc函数有可能无法提供请求的内存,这种情况malloc函数通过返回一个空指针来作为“内存分配失败”事件的信号
  • malloc分配的内存使用完后应该及时释放,否则会导致内存泄露

3. 作为参数的数组声明

C语言中会自动地将作为参数的数组声明转换为相应的指针声明,也就是说下面两种写法完全等价

int strlen(char s[])
{}
int strlen(char* s)
{}

但是需要注意的是,在其他情况下这两者并不会等价,如

extern char* hello;
extern char hello[];

4. 注意整体代替部分的错误

指针的赋值并不会复制它们指向的内容,因此如下语句

char *p, *q;
p = "xyz";
q = p;

的结果如下:

5. 空指针并非空字符串

当常数0被转换成指针使用时,这个指针绝对不能不能被解除引用dereference

if (p == (char *) 0)...

以上写法正确,因为没有解除引用

if (strcmp(p, (char *) 0) == 0)...

以上写法错误,因为strcmp会查看指针所指向内存的内容

同样以下写法也是错误的:

int *p = NULL;
printf(p);
printf("%s", p);

6. 边界计算与不对称边界

如果一个数组有10个元素,那么这个数组下标的允许范围是0-9

在多数C语言实现中,--n >= 0至少和n-->0一样快

可以用

if (bufptr == &buffer[N])

代替

if (bufptr > &buffer[N - 1])

数组中实际不存在的溢界元素的地址位于数组所占内存之后,这个地址可以用于进行赋值和比较。但不允许进行解引用。

7. 求值顺序

C语言中只有4个运算符(&&、||、?:和,)存在规定的求值顺序:

  • &&和||首先对左侧操作数求值,只有在需要时才对右侧操作数求值
  • a?b:c有三个操作数,操作数a首先被求值,根据a的值再求b或者c
  • 逗号运算符,首先对左侧操作数求值,然后丢弃该值,再对右侧操作数求值

注意:分隔函数参数的逗号并非逗号运算符,例如f(x,y)中求值顺序顺序是未定义的,而在g((x,y))中先求x的值,然后求y的值。

C语言中其他所有运算符对其操作数求值的顺序是未定义的,特别地,赋值运算符并不保证任何求值顺序。

比如,从数组x中复制前n个元素到数组y中,以下做法是不对的:

i = 0;
while(i < n)
    y[i] = x[i++];

因为这里假设y[i]的地址i在自增操作前执行前被求值

正确的做法是:

i = 0;
while(i < n)
{
    y[i] = x[i];
    i++;
}

 8. 运算符&&、||和!和按位运算符&、|、~

按位运算符&、|、~对操作数的处理方式是将其视作一个二进制位序列,分别对其每个位进行操作。

逻辑运算符&&、||和!对操作数的处理方式是将其视作要么是真,要么是假,通常将0视为假,而非0视作真。

9. 整数溢出

当两个操作数都是有符号整数时,溢出有可能发生,而且溢出的结果是未定义的。

例如a和b是两个非负整型变量,我们需要检查a+b是否会溢出,以下的写法是错误的:

if (a + b < 0)
    complain();

正确的写法是将a和b都强制转换成无符号整数:

if ((unsigned)a + (unsigned)b > INT_MAX)
    complain();

也可以使用以下写法:

if (a > INT_MAX -b)
    complain();

10. 为函数main提供返回值

大多数C语言实现都通过main的返回值来告知操作系统该函数执行是成功还是失败,典型的处理方式是返回值0表示程序执行成功,返回值非0表示程序执行失败。

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

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

相关文章

OpenCvSharp从入门到实践-(06)创建图像

目录 1、创建图像 1.1实例1-创建黑色图像 1.2实例2-创建白色图像 1.3实例3-创建随机像素的雪花点图像 2、图像拼接 2.1水平拼接图像 2.2垂直拼接图像 2.3实例4-垂直和水平两种方式拼接两张图像 在OpenCV中&#xff0c;黑白图像其实就是一个二维数组&#xff0c;彩色图像…

vscode插件问题

1 Vscode code颜色变化 最外层标签颜色变成白色 其他标签有颜色&#xff0c;css代码颜色有些变成白色 是安装的另一个插件vue影响的&#xff0c;卸载就能恢复正常的颜色 2 配置Vue项目的代码片段 css 样式代码片段 配置css.json上后偶尔能用偶尔不能用&#xff0c;Vscode 右下…

Flutter应用程序的加固原理

在移动应用开发中&#xff0c;Flutter已经成为一种非常流行的技术选项&#xff0c;可以同时在Android和iOS平台上构建高性能、高质量的移动应用程序。但是&#xff0c;由于其跨平台特性&#xff0c;Flutter应用程序也面临着一些安全风险&#xff0c;例如反编译、代码泄露、数据…

Egg.js的方法扩展

Extend-application 方法扩展 eggjs的方法的扩展和编写 Egg.js可以对内部的五种对象进行扩展&#xff0c;以下是可扩展的对象、说明、this指向和使用方式。 application对象方法拓展 按照Egg的约定&#xff0c;扩展的文件夹和文件的名字必须是固定的。比如要对application扩…

【ZEDSLAM】Ubuntu18.04系统ZED 2i双目相机SDK安装、联合标定、SLAM测试

0.设备、环境和说明 笔记本电脑i5-8300H、GTX 1060、32GRAM 因为后面要测试Vins-Fusion和ORB-SLAM3&#xff0c;所以推荐安装Ubuntu 18.04&#xff08;或者Ubuntu 20.04&#xff09; ROS 1&#xff08;不建议用比Ubuntu18更低的版本&#xff09; ROS一键安装命令&#xff1a;…

Android textView 显示: STRING_TOO_LARGE

默认情况下&#xff0c;TextView只能显示大约32K的字符。如果你的字符串超过这个限制&#xff0c;你将收到一个错误&#xff1a;“String too large”。 <string content" ...."/>问题点是&#xff1a;getResource().getString(R.string.content) 得到的是&am…

linux下实现Qt程序实现开机自启动

1.原理 要想实现开机自启动&#xff0c;首先&#xff0c;QT是没有这种实现的&#xff0c;最好是靠电脑开机的启动目录启动软件&#xff0c;下面这个目录 /etc/xdg/autostart 这是操作系统中用于配置启动项的目录&#xff0c;该目录下存放着开机自启动的启动器(.desktop)文件…

如何练好太极拳?

太极拳是一种需要细心和耐心的武术&#xff0c;要练好太极拳&#xff0c;需要从以下几个方面入手&#xff1a; 找到好的师傅&#xff1a;找到一位经验丰富、技艺高超的师傅是学习太极拳的关键。师傅应该具备正确的太极拳理论、技术和经验&#xff0c;能够正确地指导学生学习太极…

珍爱生活远离“缓存之战”——大话高并发之缓存应用技巧

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容一、引言二、缓存略谈三、无人能挡的命中率四、衣柜里的宝贝&#xff0c;您选对了吗&#xff1f;五、敢用淘汰法&#xff0c;它有何等勇气&#xff1f;六、哪个 “自作主张” 的哥哥藏起了咱们的宝贝&#xff1f;七、善骑千…

创新与高效共融,跨境电商ERP源码大趋势解析

跨境电商ERP源码是什么&#xff1f;它如何帮助企业实现高效管理和创新发展&#xff1f;我们将详细解释跨境电商ERP源码的概念&#xff0c;并探讨它的优势和价值。 跨境电商ERP源码是一种专门为跨境电商企业设计的软件源代码。它通过集成各种功能模块&#xff0c;包括订单管理、…

Facebook广告投放效果不佳?这些投放技巧我不允许你不知道!

众所周知&#xff0c;Facebook广告对于跨境卖家来说是非常有效的站外引流渠道&#xff0c;通过Facebook广告投放可以提高跨境卖家的产品销量和排名&#xff0c;但是有时明明广告已经投放出去了&#xff0c;却无法被受众看到&#xff0c;完全没有获得成果&#xff0c;或许你会怪…

日用品企业ERP有什么用?日用品企业ERP品牌有哪些

日用品是快消品&#xff0c;存在品牌多、出货量大、销售渠道广泛、经营数据量大、销售折扣变化多、成本容易出错等特点&#xff0c;并且不同的供应商有差异化的报价&#xff0c;另外供应商采购份额分析、库龄分析客户销售排名分析以及区域销售数据分析等各类分析报表的准确性和…

22款奔驰GLS450升级香氛负离子 淡淡的幽香

香氛负离子系统是由香氛系统和负离子发生器组成的一套配置&#xff0c;也可以单独加装香氛系统或者是负离子发生器&#xff0c;香氛的主要作用就是通过香氛外壳吸收原厂的香水再通过空调管输送到内饰中&#xff0c;而负离子的作用就是安装在空气管中通过释放电离子来打击空气中…

1.3 排序算法

1.1 冒泡排序 public class BubbleSort {public static void main(String[] args) {int[] arr {133,322,13,444,54,621,174,18,19,2};System.out.println(Arrays.toString(arr));BubSort(arr);System.out.println(Arrays.toString(arr));}//冒泡排序public static void BubSo…

投资5亿英镑!英国启动五项新量子项目

​&#xff08;图片来源&#xff1a;网络&#xff09; 近日&#xff0c;英国财政大臣Jeremy Hunt宣布&#xff0c;英国政府将投资5亿英镑(即6.26亿美元)为英国研究人员和初创企业提供人工智能项目的算力支持。 Jeremy Hunt还详细介绍了政府计划推出的五项新研究计划&#xff0c…

国内传统企业数字化转型升级,有哪些成功案例?

近年来&#xff0c;涌现出了很多使用零代码平台撬动一线业务管理效率的案例&#xff0c;比如&#xff1a; 山东滨州长山镇政府&#xff1a;仅用3小时搭建出监管平台&#xff0c;成功助力辖区300企业返岗复工&#xff1b;纳曲酒业&#xff1a;搭建市场费用和订单联动管控平台&a…

虚拟机指定开放数据库3306端口

1、查看当前防火墙状态&#xff1a; sudo firewall-cmd --state 2、开放指定端口 sudo firewall-cmd --zonepublic --add-port3306/tcp --permanent 3、重新加载防火墙配置 sudo firewall-cmd --reload 4、检查端口是否开放成功 sudo firewall-cmd --zonepublic --list-por…

如何自定义spring-boot-starter

1. 创建自定义starter 1.1 生成Maven工程 mvn archetype:generate -DarchetypeGroupIdorg.apache.maven.archetypes -DarchetypeArtifactIdmaven-archetype-quickstart -DarchetypeVersion1.4交互式输入groupId、artificatId、version&#xff0c;生成Maven工程后用IDEA打开 …

Python精讲 | 条件赋值和and-or技巧

大家好&#xff0c;欢迎来到 Crossin的编程教室 &#xff01; 在之前的 一段奇葩的1024代码 中&#xff0c;有这么一个写法&#xff1a; 看上去是一个由 and 和 or 组成的逻辑表达式。但实际的效果却相当于一个 if-else 的条件判断&#xff1a; if i % 5 4:D \n else:D 为什…

【python+Excel】读取和存储测试数据完成接口自动化测试

http_request2.py用于发起http请求 #读取多条测试用例 #1、导入requests模块 import requests #从 class_12_19.do_excel1导入read_data函数 from do_excel2 import read_data from do_excel2 import write_data from do_excel2 import count_case #定义http请求函数COOKIENon…