&运算符的用法

本文介绍了Vigenère密码的加密原理,并展示了如何利用按位与运算符"&"简化解密算法,提供了一个简化的C++代码实现,通过取字母的二进制与31进行位运算来确定其在字母表中的位置。

按位与运算符"&"是双目运算符是参与运算的两数各对应的二进位相与。

按位与"&"功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。

例如:9&5可写算式如下: 00001001 (9的二进制补码)&00000101 (5的二进制补码)

00001001

00000101

对比2个数的补码可以得出结构为 00000001 也就是1的二进制补码

可见9&5=1。 按位与运算通常用来对某些位清0或保留某些位。

当然通过一道题 我发现了 &与字母顺序有关的题 有着十分便利的妙用。

题目描述

16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法 Vigenère 密码。Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为南军所广泛使用。

在密码学中,我们称需要加密的信息为明文,用 MM 表示;称加密后的信息为密文,用 CC 表示;而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,记为 kk。 在 Vigenère 密码中,密钥 kk 是一个字母串,k=k_1,k_2,…,k_nk=k1​,k2​,…,kn​。当明文 M=m_1,m_2,…,m_nM=m1​,m2​,…,mn​ 时,得到的密文 C=c_1,c_2,…,c_nC=c1​,c2​,…,cn​,其中 c_ici​=m_imi​®k_iki​,运算®的规则如下表所示:

Vigenère 加密在操作时需要注意:

  1. ®运算忽略参与运算的字母的大小写,并保持字母在明文 MM 中的大小写形式;

  2. 当明文 MM 的长度大于密钥 kk 的长度时,将密钥 kk 重复使用。

例如,明文 M=Helloworld,密钥k=abc 时,密文 C=Hfnlpyosnd。

输入格式

共 2 行。

第一行为一个字符串,表示密钥 kk,长度不超过 100,其中仅包含大小写字母。

第二行为一个字符串,表示经加密后的密文,长度不超过 1000,其中仅包含大小写字母。

输出格式

一个字符串,表示输入密钥和密文所对应的明文。

输入输出样例

输入 #1复制

CompleteVictory
Yvqgpxaimmklongnzfwpvxmniytm

输出 #1复制

Wherethereisawillthereisaway

按照题目所说也好理解 只需要先弄出秘钥字母的位子 再用密文给的字母减去秘钥的位子就可以得到明文。

那么首先我们可以先需要3个数组存放密文 秘钥 明文;

然后测出密文和秘钥的长度 ,由于秘钥基本都比密文短 还需要拼接,
cin>>k>>s;
len1 = strlen(k);//测出密钥长度
len2 = strlen(s);//密文长度
if (len1 < len2)
    for (int i = len1; i < len2; i++)    k[i] = k[i - len1];

来看核心部分

首先是大小写问题 特判即可,再者明文是密文的字母减去秘钥字母得到的。所以会出现减到a一下的情况需要额外分类。只需要加上26就行了。

for (int i = len1; i < len2; i++)    k[i] = k[i - len1]; for (int i = 0, j; i < len2; i++)
    {
        if (k[i] >= 'A' && k[i] <= 'Z')    j = k[i] - 'A';
        if (k[i] >= 'a' && k[i] <= 'z')    j = k[i] - 'a';
        ans[i] = s[i] - j;
        if (s[i] >= 'A' && s[i] <= 'Z')
            if (ans[i] < 'A')    ans[i] += 26;
        if (s[i] >= 'a' && s[i] <= 'z')
            if (ans[i] < 'a')    ans[i] += 26;
    }

完整的代码是

#include<bits/stdc++.h>
char k[1010], s[1010], ans[1010];
int len1, len2;
int main()
{
    cin >> k >> s;
    len1 = strlen(k);//测出密钥长度
    len2 = strlen(s);//密文长度
    if (len1 < len2)
        for (int i = len1; i < len2; i++)    k[i] = k[i - len1];
    for (int i = 0, j; i < len2; i++)
    {
        if (k[i] >= 'A' && k[i] <= 'Z')    j = k[i] - 'A';
        if (k[i] >= 'a' && k[i] <= 'z')    j = k[i] - 'a';
        ans[i] = s[i] - j;
        if (s[i] >= 'A' && s[i] <= 'Z')
            if (ans[i] < 'A')    ans[i] += 26;
        if (s[i] >= 'a' && s[i] <= 'z')
            if (ans[i] < 'a')    ans[i] += 26;
    }
    for (int i = 0; i < len2; i++)    printf("%c", ans[i]);/
    return 0;
}

是不是很长。我去看了其他大佬的解题方法,发现了一种十分简单的代码 及时使用了&的运算

再发简易之前我们先来看点东西

0100 00016541A
0100 00106642B
0100 00116743C
0100 01006844D
0100 01016945E
0100 01107046F
0100 01117147G
0100 10007248H
0100 10017349I
0100 1010744AJ
0100 1011754BK
0100 1100764CL
0100 1101774DM
0100 1110784EN
0100 1111794FO
0101 00008050P
0101 00018151Q
0101 00108252R
0101 00118353S
0101 01008454T
0101 01018555U
0101 01108656V
0101 01118757W
0101 10008858X
0101 10018959Y
0101 1010905AZ
0110 00019761a
0110 00109862b
0110 00119963c
0110 010010064d
0110 010110165e
0110 011010266f
0110 011110367g
0110 100010468h
0110 100110569i
0110 10101066Aj
0110 10111076Bk
0110 11001086Cl
0110 11011096Dm
0110 11101106En
0110 11111116Fo
0111 000011270p
0111 000111371q
0111 001011472r
0111 001111573s
0111 010011674t
0111 010111775u
0111 011011876v
0111 011111977w
0111 100012078x
0111 100112179y
0111 10101227Az

直接看对应的字母a的二进制代码      A的二进制码

0110 0001                                     0100 0001

x 跟X

0111 1000            0101 1000

可以看到 相同字母的后5位二进制是相同的。

而且用对应字母&31(11111)得到的就是改字母在字母表中的顺序

例如a&31  

0110 0001

0001 1111 

0000 0001

也就是a&31=1(0000 0001)

大写的由于后5位相同也是同理

利用这个性质

我们就只需要考虑边界值问题即可

#include<bits/stdc++.h>
using namespace std;
int main() {
    string k, c;
    cin >> k >> c;
    for (int i = 0; i < c.length(); i++) {
        int t = (k[i % k.length()] & 31) - 1;
        c[i] = (c[i] & 31) - t > 0 ? c[i] - t : c[i] - t + 26;
    }
    cout << c << endl;
    return 0;
}

叶jq

&lt;think&gt;好的,我现在要解决用户关于C++中&amp;运算符重载的问题。首先,我需要确认用户的具体需求是什么。用户问的是&ldquo;&amp;运算符重载的用法或实现方式&rdquo;,所以需要明确在C++中,&amp;运算符有两种含义:按位与运算符和取地址运算符。因此,我需要分别讨论这两种情况下的重载可能性。 根据引用[1],C++中不能重载的运算符包括::、sizeof、typeid、.*和三元运算符?:,而&amp;运算符不在其中,所以可以重载。但需要区分是按位与还是取地址。通常,取地址运算符&amp;)是默认存在的,但根据C++标准,用户也可以重载它,不过这样做可能带来风险,比如影响指针的正常使用,需要特别注意。 接下来,我需要整理&amp;运算符重载的两种主要场景:作为二元运算符(按位与)和作为一元运算符(取地址)。按位与的重载较为常见,而取地址的重载虽然可能,但实际应用较少且需谨慎。 然后,要给出具体的代码示例。对于二元运算符,可以展示如何为自定义类重载&amp;,比如一个BitArray类。对于一元取地址运算符的重载,需要说明其语法和潜在问题,例如返回特定类型的指针或单例模式中的应用,同时提醒用户重载取地址运算符可能破坏语言的基本假设,应尽量避免。 此外,需要提到C++11引入的显式重载说明符,允许对取地址运算符进行重载,但同样要注意其影响。还要结合引用[3]中的内容,说明在重载运算符时,如果涉及自定义分配器或比较器,应确保它们是无状态的,以优化存储,但这对当前问题影响不大,可以简要提及。 最后,生成相关问题时要涵盖运算符重载的限制、其他运算符的重载方法、应用场景以及注意事项,确保覆盖用户可能感兴趣的扩展内容。同时,确保回答结构清晰,代码示例正确,符合用户要求的中文回答和LaTeX格式。&lt;/think&gt;### C++中&amp;运算符重载的用法及实现 在C++中,`&amp;`运算符有两种含义: 1. **二元运算符**:按位与操作符(Bitwise AND) 2. **一元运算符**:取地址操作符(Address-of) 根据C++标准,**运算符重载需遵循以下规则**: - 不能修改运算符的原始优先级或结合性 - 至少一个操作数必须是用户自定义类型[^1] - 无法重载的运算符包括`::`、`sizeof`、`typeid`、`.*`和`?:`[^1] --- #### 一、按位与运算符重载(二元&amp;) ```cpp class BitArray { private: uint64_t data; public: BitArray operator&amp;(const BitArray&amp; rhs) const { BitArray result; result.data = this-&gt;data &amp; rhs.data; return result; } // 友元函数实现 friend BitArray operator&amp;(const BitArray&amp; lhs, const BitArray&amp; rhs); }; // 类外定义 BitArray operator&amp;(const BitArray&amp; lhs, const BitArray&amp; rhs) { return BitArray(lhs.data &amp; rhs.data); } ``` --- #### 二、取地址运算符重载(一元&amp;) ```cpp class Singleton { private: static Singleton* instance; public: static Singleton* getInstance() { /*...*/ } // 重载取地址运算符 Singleton* operator&amp;() { return getInstance(); // 强制返回单例指针 } }; ``` &gt; **注意**:重载取地址运算符会改变对象默认的指针获取行为,可能破坏RAII等机制[^2] --- #### 三、特殊场景:引用语义重载 ```cpp class SmartBuffer { private: char* buffer; public: // 返回内部缓冲区的引用 char&amp; operator&amp;() { return *buffer; } }; ``` --- ### 关键注意事项 1. 取地址运算符重载必须是非静态成员函数 2. C++11起支持显式重载说明符: ```cpp explicit operator&amp;() = delete; // 禁止取地址操作 ``` 3. 当与智能指针配合使用时,需注意`std::addressof`会绕过重载的`&amp;`运算符[^3] ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值