我的程序在调试时运行正常,但在调试时运行不正确

时间:2021-01-22 21:14:13

标签: c debugging cs50 caesar-cipher

我目前正在用 C 编写一个简单的程序,该程序从用户那里获取一个命令行参数,该参数是一个替换密码密钥。目前,我的程序正在检查用户可能输入的所有可能不正确的参数。

通过调试器运行它会导致我的程序每次都完美运行,无论输入是什么。但是,在没有调试器的情况下运行我的程序,同时使参数至少有一个小写字母(例如 ./substitution VCHPRZGJNTLSKFBDQWAXEuymoi),会导致“sum”变量在大约 50% 的情况下具有不正确的值。< /p>

我将快速解释“sum”变量的用途,以便更容易理解。 'sum' 从 2015 年开始,因为这是根据 ASCII 表将所有 26 个大写字母相加的值。我的函数中的 for 循环然后从 2015 中减去密码密钥中的每个字符。最后,最后一个 if 语句检查 sum 是否为 0,这意味着只输入了唯一字符。

在没有调试器的情况下运行时,'sum' 有时是 0,有时是 -32 * 小写字母的数量。例如,VCHPRZGJNTLSKFBDQWAXEuymoi 有 4 个小写字母,'sum' 有时为 0,有时为 -128。

我不知道这个问题是从哪里来的,如果能得到任何帮助,我将不胜感激。

这是我的代码:

for (final Map.Entry<String, Command> entry : commands.entrySet()){  
                 if (content.startsWith(";" + entry.getKey())){  
                     entry.getValue().execute(messageCreateEvent);  
                     break;  
                 }  
             }  

2 个答案:

答案 0 :(得分:5)

您的操作系统可能正在使用 ASLR 来防止利用内存损坏漏洞。这可能是 sum 变量的值在大约 50% 的时间内具有错误值的原因。正如在 this 注释中发现的那样,将指针与 if ((int) cipher[i] > 96 && (int) cipher < 123) 中的整数进行比较,这可能是问题所在。 但是,您的调试器似乎禁用了 ASLR,并且地址未随机化。因此,变量 cipher 指向的地址不是随机的,你总是得到相同的结果。

如果您使用的是 gdb,则可以使用命令 set disable-randomization off 启用 ASLR。

编辑 正如 Eric Postpischil 在他的评论 [1, 2] 中所建议的,您应该使用 'a' 而不是像 97 这样的常量,并且 (int) 类型转换应该完全删除。 (int) 强制转换是不必要的,因为数组的 char 元素将被提升为 int

您还应该看到编译器警告。

为了

if ((int) cipher[i] > 96 && (int) cipher < 123)

我收到以下警告:

warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
if ((int) cipher[i] > 96 && (int) cipher < 123) {

gcc -Wpointer-to-int-cast 上应该默认启用。否则,您也可以尝试使用 -Wall 选项。

答案 1 :(得分:2)

不相关,但对于这种比较,有 ctype.h

这将循环更改为

for (int i = 0; i < strlen(cipher); i++)
{
    if (islower(cipher[i]))
    {
        cipher[i] = toupper(cipher[i]);
    }

    if (!isalpha(cipher[i]))
    {
        printf("Key must only contain alphabetical characters.\n");
        return 1;
        /* break; */
    }

    sum -= (int) cipher[i];
}

这将减少代码长度,使代码更具可读性,避免常量,并避免一些陷阱。 还有一点,这里不需要 break,因为您已经从函数中 return。所以永远不会到达休息时间。