【问题标题】:Is it possible to calculate with ASCII numbers that are temporarily bigger than 127?是否可以使用暂时大于 127 的 ASCII 数字进行计算?
【发布时间】:2021-01-19 05:37:42
【问题描述】:

首先,我是编码新手,我曾想过这个问题,并尝试用谷歌搜索。 我已经有一个解决方法,我只想知道是否可以通过其他方式。 我正在上cs50课程,我应该写一个加密函数。

我的问题是,我的 char 暂时大于 127,然后被截断。 那么在我保存它之前是否可以暂时用某个字符进行计算 到内存地址并截断它?

我认为问题应该出在的部分:

for
(int i = 0; i < strlen(ui); i++)
{
    if
    (isupper(ui[i]))
        {
            ui[i] += key;
            if
            (ui[i] > 90)
            {
                ui[i] -= 26;
            }
        }
    if
    (islower(ui[i]))
        {   
            ui[i] += key;
            if
            (ui[i] > 122)
            {
                ui[i] -= 26;
            }
        }

它会被截断,例如如果输入 z 时 key 变得大于 6。

所以我可以以某种方式编写它,26 在它进入存储之前被减去,或者(我认为 atm)不可能,因为一旦它变得大于 127,即使它在一行中,它也会被截断?

解决方法(我想现在写): 我会在之前减去 96,所以我会用 1 到 27 之间的数字进行计算并在之后添加。

提前感谢您的建议。

【问题讨论】:

  • 首先,“截断”听起来你实际上是指它溢出。对于有符号值,溢出的行为是未定义的(或至少是实现定义的)。通常,如果您希望这样做,应该使用unsigned char 执行此类数学运算。此外,不建议使用硬编码的 ASCII 值常量。考虑像@​​987654323@ 这样的东西。如果性能很重要,您可以考虑为每个值使用查找表,从而无需调用任何 isupper 或任何分支。
  • 离题:多么有趣的风格。谁教给你的?
  • 嗯,在用 C 语言编程大约 40 年的时间里,我从未在自己的行中看到像 iffor 这样的关键字。而且我看到了很多代码......
  • 不喜欢这种风格50。如果您是编码新手,那么您的思维方式是错误的。这是 C 而不是 Lisp。
  • @chqrlie 我再次检查了它,你是对的。也许我误解了“在 if 和条件之间留一个空格”和“在 if 和条件之间留出一个空格”的符号。但如上所述,答案是“看起来不错”。我个人不喜欢上面的风格,所以我不会继续它。感谢您指出。

标签: c ascii cs50 truncate caesar-cipher


【解决方案1】:

我的问题是,我的 char 暂时大于 127,然后被截断。那么,在我将某个字符保存到内存地址并截断它之前,是否可以暂时使用某个字符进行计算?

是的,这是可能的,而且您不需要做任何特别的事情来实现它。在 C 表达式中,所有小于 int 的整数类型的算术操作数都将转换为 int 或更宽,并以更宽的类型执行计算,产生该类型的结果。如果需要分配给更窄类型的对象,它会再次缩小。

但请注意,

  1. 如果初始值不能在目标类型中表示,则向有符号整数类型的缩小转换具有实现定义的行为。这可以包括引发实现定义的信号。假设最重要的字节包含非零值时将被截断是不安全的。

  2. 您所描述的并不是所提供的代码实际执行的操作。特别是,我带你讲这个:

         ui[i] += key;

在这种情况下计算ui[i] + key 没有问题,但是在将结果写入内存之前没有特别的延迟。这就是+= 的赋值部分所做的。

你最好完全避免这种情况。例如,

if (islower((unsigned char) ui[i])) {
    ui[i] = (((ui[i] - 'a') + key) % 26) + 'a';
}

不过,请注意,这(以及您的原件)假设连续块的小写字母的数值。这通常是正确的,但并非普遍如此。

【讨论】:

  • 一句话:必须是 islower((unsigned char)ui[i]) 才能 100% 正确
  • 不是这个答案试图关注的重点,@0__________,但是是的,如果 ui 数组可以包含具有负值的元素,并且 OP 的代码和 cmets 不提供,则需要强制转换以不同的方式思考的基础。已更新。
【解决方案2】:

cmets 中提到了可能的溢出错误,但是代码中可能还有另一个错误,也许我不知道您的算法应该是什么

考虑ui[i] 是'Z'(90 ASCII)和键':'(58 ASCII)。 'Z' 是大写的,所以第一个 if 语句的主体被执行,导致 ui[] 是 90 + 58 - 26 = 122,现在是 'z',N.B.小写。

现在z 是小写的,所以第二个if 的主体也会执行,导致ui[] 现在是122 + 58 - 26 = 154。这超出了ASCII 范围,所以你会在那里溢出。

另一个例子是 ui[] = 'A' 和键 70。第一个 ifui[] 更改为 65 + 70 - 26 = 109,即 'm'。这也将触发第二个if 语句并再次导致溢出。

我怀疑两个 if 主体应该以相同的值执行。如果没有,那么您需要在第二个 if 之前添加一个 else

}
else if (islower(ui[i])) {
    ...

【讨论】:

  • 提示用户输入一个非负整数作为值。如果输入大于 26,我使用 %26。那应该这样做还是我错过了什么?感谢您指出这一点,也许我应该在问题中添加更多代码以进行澄清,但我认为如果代码更少,它会更容易。
  • 你说的关键是 %26?那应该没问题。我仍然会小心省略else,以防您稍后更改这些值,以便将大写字母转换为小写字母。可能还有其他情况您没有显示或稍后会添加。我不认为你会想要在同一个字节上执行多个翻译。
猜你喜欢
  • 2021-06-05
  • 2011-09-15
  • 2014-01-15
  • 1970-01-01
  • 1970-01-01
  • 2014-06-20
  • 2011-09-23
  • 2020-07-13
  • 1970-01-01
相关资源
最近更新 更多