C语言KR圣经笔记 2.8自增和自减 2.9位运算 2.10赋值

news2025/1/15 6:26:57

2.8 自增和自减操作符

C提供了两个不同寻常的操作符,用于对变量进行自增和自减。自增操作符++对操作数加上1,而自减操作符 -- 对操作数减去1。我们已经频繁使用++ 对变量进行自增,如:

if (c == '\n')
    ++nl;

不寻常之处在于 ++ 和 -- 既能用作前缀操作符(在变量之前,如++n),又能用作后缀(在变量之后,如n++)。两种情况下,效果都是n递增。不过表达式 ++n 是在它的值被使用之前对n进行递增,而 n++是在它的值被使用之后对n进行递增。这意味着如果不仅要用到递增的效果,还要用到表达式的值时,++n 和 n++ 是不一样的。如果 n 为 5,则

x = n++;

将x设为5,而

x = ++n;

将x设为6。两种情况下,n都会变成6。自增和自减操作符只能用于变量;像 (i+j)++ 这样的表达式是非法的。

当只需要用到递增效果,而不需要值的时候,如

if (c == '\n')
    nl++;

前缀和后缀是一样的。不过有些情况下会专门要求使用前缀,而有些则专门使用后缀。举个例子,看看下面这个函数 squeeze(s, c) ,将字符串s中出现的所有字符c都删除:

/* squeeze: 从s中删除所有的c */
void squeeze(char s[], int c)
{
    int i, j;

    for (i = j = 0; s[i] != '\0'; i++)
        if (s[i] != c)
            s[j++] = s[i];
    s[j] = '\0'; 
}

每当非c字符出现时,它就被拷贝到当前的 j 位置,而只有这时 j 才会自增,为接收下一个字符做准备。与下面的写法是完全相同的:

if (s[i] != c) {
    s[j] = c;
    j++;
}

类似结构的另一个例子来自于我们在第一章写的 getline 函数,其中的

if (c == '\n') {
    s[i] = c;
    i++;
}

可以替换成更紧凑的形式:

if (c == '\n')
    s[i++] = c;

第三个例子可以看看标准库函数 strcat(s, t),它将字符串 t 连接到字符串 s 的末尾。strcat 假定 s 有足够的空间来存放合并的结果。按我们下面的写法, strcat 不返回值,标准库的strcat版本返回指向结果字符串的指针。

/* strcat: 把t拼接到s的末尾;s必须足够大 */
void strcat(char s[], char t[])
{
    int i, j;

    i = j = 0;
    while (s[i] != '\0')    /* 找到s的结尾 */
        ++s;
    while ((s[i++] = t[j++]) != '\0')    /* 拷贝t */
        ;
}

由于每个字符都要从 t 拷贝到 s,++后缀同时用于 i 和 j,以保证它们在循环的下一轮时处于正确的位置。

练习2-4,写另一个版本的 squeeze(s1, s2),把字符串s1中出现的所有字符串 s2 都删除

练习2-5,写一个函数 any(s1, s2),返回字符串s2中任意字符在字符串s1中首次出现的位置,如果s1不包含s2的任何字符,则返回-1。(标准库函数 strpbrk 做同样的事,但返回的是位置的指针)

2.9 位运算操作符

C提供了六个位操作符;它们只能用于整型,即 char, short, int 和 long,不管有无符号均可。

&        按位与

|        按位或

^        按位异或

<<        左移

>>        右移

~        取反(一元)

按位与操作符 & 经常用于屏蔽位中的某些部分;例如

 n = n & 0177

只保留 n 的低7位,其他位都设为0。

按位或操作符 |  用于将一些位打开(设为1)

x = x | SET_ON

会将 SET_ON 中为1的位设置到 x 上对应的位。

按位异或操作符 ^ 的规则是:若两个操作数对应的位不同时,则运算结果中该位设为1,若相同则设为0。

必须把位操作符 &  |  和逻辑运算符 && || 区分开,后者隐含的是从左到右的真值计算。

例如,如果 x是1,y 是2,则 x & y 结果为0 ,而 x && y 结果是1。

移位操作符 << 和 >> 分别对它们左边的操作数进行左移或者右移,移动的位数由右边的操作数(必须为正数)指定。这样  x << 2 会将 x 的值左移两位,空出的位补0;这就等于乘以 4。对 unsigned 值进行右移,空位总是补0。对有符号的值进行右移,在有些机器上会填充符号位(算术移位),而有些机器上填充0(逻辑移位)。

一元操作符 ~ 得出整数的反码,也就是说,把每个1都转成0,每个0都转成1。例如

x = x & ~077

把 x 的低6位设为0。注意 x & ~077 不依赖于字长,这种写法比假定字长的写法好,比如 x & 0177700 假定 x 是 16位的值。可移植的写法不涉及额外的开销,因为 ~077 是常量,可以在编译期间求值。

函数 getbits(x, p, n) 可用来演示一些位操作符的用法,该函数返回 x 从位置 p 算起的 n 个位(右对齐)。我们假定第0位是最右边一位,并且 n 和 p 都是合适的正数。例如, getbits(x, 4, 3) 返回第 4,第3 和 第2 位的三个比特,右对齐。

/* getbits:返回从位置 p 开始的 n 个比特 */
unsigned getbits(int x, int p, int n)
{
    return x >> (p+1-n) & ~(~0 << n);
}

表达式 x >> (p+1-n) 把所需的比特位段移到字的最右边。~0 是所有位均为1;用 ~0 << n 把它左移 n 位,会把最右边的 n 个位变为 0;再对它取反,就得到一个最右边 n 位 都是 1 的掩码。

练习2-6、写个函数 setbits(x,p,n,y),返回值是 x 从位置 p 开始 的 n 个位 被 y 的最右边 n 个位替换后得到的值,x 其他位都不变。

练习2-7、写个函数 invert(x,p,n) ,返回值是 x 从位置 p 开始的 n 个位被翻转(即0变1,1变0)后的结果,其他位都不变。

练习2-8、 写个函数 rightrot(x,n),返回值是整数 x 向右旋转了 n 个位。

2.10 赋值操作符和表达式

 i = i + 2

像这种左侧的变量在右边马上重复出现的表达式,可以写成紧凑的形式:

i += 2

其中操作符 += 被称为 赋值操作符

大部分的二元操作符(像 + 这样左右两边各有一个操作数的操作符)都有一个对应的赋值操作符 op=, 其中 op 是下列操作符之一

 + - * / % << >> & ^ |

设有表达式 expr1 和 expr2,则

expr1 op= expr2

等价于

expr1 = (expr1) op (expr2)

唯一区别是在前面一种形式中, expr1 只会被计算一次。注意 expr2 两边的括号:

x *= y + 1

意思是

x = x * (y+1)

而不是

x = x * y + 1

看看下面这个例子,函数 bitcounts 统计其整数参数中为1的比特位数量。

/* bitcounts: 计算x中为1的比特位数量 */
int bitcounts(unsigned x)
{
    int b;

    for (b = 0; x != 0; x >> 1)
        if (x & 01)
            b++;
    return b;
}

将参数 x 声明为 unsigned 可以保证,对 x 做右移时,左边填充的总是0而不是符号位,不管这个程序在什么样的机器上运行。

除了简洁之外,赋值操作符的优势在于它们与人们思考的方式更为一致。我们会说“把 i 加上 2 ”或者“ i 自增 2 ”,而不是“拿到 i 的值,加上 2, 再把结果放回 i ”。因此 表达式  i += 2 比 i = i + 2 更好。另外,对于复杂的表达式如

yyval[yypv[p3+p4] + yypv[p1]] += 2

赋值操作符使代码容易理解,因为读者不必费力地检查两个长表达式是否相等,或者疑惑它们为什么不相等。而且赋值操作符甚至能帮助编译器生成高效的代码。

我们已经知道赋值语句是有值的,可以出现在表达式中;最常见的例子是

while ((c = getchar()) != EOF)
    ...

其他赋值操作符( +=   -= 等)也能出现在表达式中,不过出现频率会低些。

在所有这样的表达式中,赋值表达式的类型就是它左边操作数的类型,而赋值表达式的值就是赋值之后的值。

练习2-9、在2的补码系统中,x &= (x-1) 删除x最右边的一个比特位。解释为什么。并使用这个发现来写一个更快的 bitcount 版本。

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

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

相关文章

接触式静电压测量仪的用途和操作方法

接触式静电压测量仪是一种用于测量静电电荷的仪器&#xff0c;主要用于工业生产和科学研究领域。它可以测量静电电压、静电场强、静电电荷等参数&#xff0c;对于静电控制和环境监测等方面具有重要的作用。 接触式静电压测量仪的操作方法如下&#xff1a; 接通电源&#xff1a;…

【Java系列】HashSet

HashSet 介绍添加元素判断元素是否存在删除元素删除集合中所有元素可以使用 clear 方法&#xff1a;计算大小迭代 HashSet 系列文章版本记录 介绍 HashSet 基于 HashMap 来实现的&#xff0c;是一个不允许有重复元素的集合。 HashSet 允许有 null 值。 HashSet 是无序的&#x…

PHP | php入门知识(if、switch、数组、数组排序、超级全局变量)

文章目录 一、php条件语句&#xff08;if、switch&#xff09;1. if语句2. if...else语句3. if...elseif...else语句4. switch语句 二、数组1&#xff09;数值数组1. 创建数值数组的两种方法&#xff1a;2. 获取数组的长度&#xff08;count()函数&#xff09;3. 遍历数值数组&…

港大联合百度开源通用图大模型GraphGPT:让大语言模型读懂图数据

导读 图神经网络&#xff08;GNN&#xff09;已成为处理和学习图数据的强大工具&#xff0c;在社交网络分析、推荐系统、智慧城市和生物信息等多个领域带来了革命性的进展。图神经网络的核心优势在于其揭示图数据中复杂关联性的能力。通过消息传递和信息聚合&#xff0c;图神经…

Leo赠书活动-04期 【国家数据局正式揭牌,数据专业融合型人才迎来发展良机 】文末送书5本

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 赠书活动专栏 ✨特色专栏&#xff1a;…

数据防泄密软件排行榜(10大数据防泄密软件推荐)

众所周知&#xff0c;公司中往往由于员工离职而出现泄密的情况&#xff0c;比如公司的财务资料、客户资料以及数据资料等&#xff0c;员工在跳槽的时候将这些带走&#xff0c;管理者无从考证导致部门甚至企业出现亏损的情况。 数据泄密一旦发生&#xff0c;企业在查证追责时就有…

有了这本书学习递归算法不再那么难

递归是一种编程技术&#xff0c;能够产生相当优雅的代码&#xff0c;但它也经常会把写代码和看代码的程序员给弄糊涂。这并不是说程序员可以或者应该忽略递归。尽管大家都知道递归比较难&#xff0c;但是这是计算机科学领域的一个重要话题&#xff0c;它能让你敏锐地观察到编程…

【linux进程(七)】程序地址空间深度剖析

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; 程序地址空间 1. 前言2. 什么…

中国卖家的出路:TikTok电商重塑东南亚市场

2023年10月4日&#xff0c;印尼政府发布了一则重要公告&#xff0c;宣布不再允许社交媒体作为商品销售平台。这一决策直接影响了TikTok在印尼的电商业务&#xff0c;迫使该平台关闭了其印尼市场的电商运营。 对于TikTok电商而言&#xff0c;印尼市场一直占据着重要地位&#x…

机器视觉工程师们,人的命运大多数连在一起

看着鱼池里的小鱼&#xff0c;很是治愈。自己的往后的生活还要继续。 有次出差&#xff0c;和工作经验13年机器视觉工程师&#xff0c;他用手指着流水线上的操作工说&#xff0c;他们失业&#xff0c;去干什么&#xff0c;回家种田吗&#xff1f;都机械化种田&#xff0c;回家…

程序员为啥要做副业(02)-中指备用金

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

table 部分列宽度固定,剩余列宽度等分

table 固定列固定宽度&#xff0c;剩余列给最小宽度 <thead><tr><th rowspan"2" style"width:100px">序号</th><th rowspan"2" style"width:120px">姓名</th><th v-for"date in dates&q…

如何实现可靠的数据调度同步,数据同步方案看一下!

随着企业规模不断扩大&#xff0c;分支机构越来越多&#xff0c;跨区域跨国的集团越来越多&#xff0c;越来越多的企业要求内部各种业务数据在服务器、数据中心甚至云上&#xff0c;能够进行实时的调度和同步&#xff0c;从而需要部署一套数据同步方案&#xff0c;实现服务器与…

DC电源模块如何承受超负荷电流的能力

BOSHIDA DC电源模块如何承受超负荷电流的能力 DC电源模块是现代电子设备中必不可少的部件&#xff0c;它们通常被用来将交流电转换为稳定的直流电&#xff0c;为电子设备提供所需的电力。在某些情况下&#xff0c;DC电源模块可能会遇到超负荷电流的情况&#xff0c;如启动过程…

CleanMyMacXMac4.14.4版本系统优化工具

CleanMyMac是macOS上不可或缺的清理工具&#xff0c;它的作用非常强大&#xff0c;可以帮助用户清理系统、照片、邮件、iTunes垃圾&#xff0c;甚至是隐私数据。以下是CleanMyMac的主要功能和特点&#xff1a; 首先&#xff0c;CleanMyMac可以帮助清理系统垃圾&#xff0c;包括…

Pyqt5 List Widget 用户自定义添加/删除字段

添加和删除字段的逻辑 在窗口上显示一个list widget的窗口&#xff0c;还有一个添加字段的按钮 点击添加字段会弹出一个输入框&#xff0c;将内容作为一个item添加到list widget中 点击对应的已添加的字段&#xff0c;即会显示删除按钮&#xff0c;点击即可删除该字段 效果…

登录Edge发生了错误请稍后再试。Oxcfff82e发送反馈ccf05c90-0acc-0005-3100-f2cccc0ada01

登录Edge 发生了错误请稍后再试。Oxcfff82e发送反馈ccf05c90-0acc-0005-3100-f2cccc0ada01 1、如果连接了 VPN &#xff0c;建议断开 VPN。 2、按 “Windows 徽标键X”&#xff0c;启动 “Windows Power Shell&#xff08;管理员&#xff09;”&#xff08;也可以自行以管理员…

【java学习—十】List集合(6)

文章目录 1. List 与 ArryList2. 应用2. ArrayList 与 Vector 1. List 与 ArryList List 代表一个元素有序、且可重复的集合&#xff0c;集合中的每个元素都有其对应的顺序索引     List 允许使用重复元素&#xff0c;可以通过索引来访问指定位置的集合元素。     List…

开源库存管理系统InvenTree的安装

本文是应网友 shijie880500 要求折腾的&#xff1b; 什么是 InvenTree &#xff1f; InvenTree 是一个开源的库存管理系统&#xff0c;提供强大的低级别库存控制和零件跟踪。InvenTree 系统的核心是 Python/Django 数据库后端&#xff0c;它提供了一个管理界面&#xff08;基于…

Mac 上免费的网络Folx Mac 下载器

Mac最好的下载工具Folx Pro 5 for Mac 是由兔八哥爱分享整理发布 。 Folx Pro 5 for Mac是目前Mac平台上数一数二的下载工具&#xff0c;功能强大&#xff0c;几乎可以满足您的所有下载需求。folx pro for mac完整版不但可以下载网上任何文件&#xff0c;而且支持断点续传&…