我的程序在调试时运行正常,但在调试结束时运行不正确 我现在正在编写C中的一个简单程序,它从用户那里获取一个命令行参数,它是一个替换密码密钥。目前,我的程序正在检查用户可能输入的所有可能不正确的参数

我的程序在调试时运行正常,但在调试结束时运行不正确 我现在正在编写C中的一个简单程序,它从用户那里获取一个命令行参数,它是一个替换密码密钥。目前,我的程序正在检查用户可能输入的所有可能不正确的参数,c,debugging,cs50,caesar-cipher,C,Debugging,Cs50,Caesar Cipher,通过调试器运行此命令,无论输入是什么,我的程序每次都能完美运行。但是,在不使用调试器的情况下运行我的程序,同时使参数至少有一个小写字母(例如../substitution VCHPRZGJNTLSKFBDQWAXEuymoi),会导致“sum”变量在大约50%的时间内具有不正确的值 我将快速解释“sum”变量的用途,以便更容易理解sum'从2015年开始,因为这是根据ASCII表将所有26个大写字母相加的值。然后,函数中的for循环从2015中减去加密密钥中的每个字符。最后,最后一个if语句检查

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

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

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

我不知道这个问题是从哪里来的,我非常感谢任何帮助

这是我的密码:

#include <cs50.h>
#include <stdio.h>
#include <string.h>

string sub(string plaintext,string cipher);

int main(int argc, string argv[])
{
    string cipher = argv[1];
    // checks for whether an argument was provided
    if (argc != 2)
    {
        printf("Usage: ./substitution KEY\n");
        return 1;
    }
    // checks for whether the cipher is 26 characters long
    else if (strlen(cipher) != 26)
    {
        printf("Key must contain 26 characters\n");
        return 1;
    }
    
    // makes sure the cipher contains only non-alphabetical characters
    // also subtracts from 2015 (sum of all unique, upper-case letters) with each iteration to test for whether every character in the argument is unique
    int sum = 2015;
    for (int i = 0; i < strlen(cipher); i++)
    {
        if ((int) cipher[i] > 96 && (int) cipher < 123)
        {
            cipher[i] = (char) ((int) cipher[i] - 32);
        }
        
        if ((int) cipher[i] < 65 || ((int) cipher[i] > 90 && (int) cipher[i] < 97) || (int) cipher[i] > 122)
        {
            printf("Key must only contain alphabetical characters.\n");
            return 1;
            break;
        }
        sum -= ((int) cipher[i]);
    }
    
    // DEBUG: prints 'sum'
    printf("%i\n", sum);
    
    // THIS IS THE PROBLEM STATEMENT
    // determines whether every character in the argument is unique
    if (sum != 0)
    {   
        printf("Key must contain all unique characters.\n");
        return 1;
    }
    
    // gets the plaintext from the user and prints out the cipher text using the 'sub' function
    string plaintext = get_string("plaintext: ");
    printf("ciphertext: %s\n",sub(plaintext,cipher));
}
#包括
#包括
#包括
字符串子(字符串明文、字符串密码);
int main(int argc,字符串argv[])
{
字符串密码=argv[1];
//检查是否提供了参数
如果(argc!=2)
{
printf(“用法:./substitution KEY\n”);
返回1;
}
//检查密码是否为26个字符长
else if(strlen(密码)!=26)
{
printf(“密钥必须包含26个字符\n”);
返回1;
}
//确保密码仅包含非字母字符
//还可以在每次迭代中从2015中减去(所有唯一大写字母的总和),以测试参数中的每个字符是否唯一
整数和=2015;
for(int i=0;i96&(int)密码<123)
{
密码[i]=(字符)((int)密码[i]-32);
}
如果((int)密码[i]<65 | |((int)密码[i]>90&(int)密码[i]<97)| |(int)密码[i]>122)
{

printf(“密钥必须只包含字母字符。\n”); 返回1; 打破 } 和-=((int)密码[i]); } //调试:打印“总和” printf(“%i\n”,总和); //这就是问题陈述 //确定参数中的每个字符是否唯一 如果(总和=0) { printf(“密钥必须包含所有唯一字符。\n”); 返回1; } //从用户处获取明文,并使用“sub”函数打印出密文 字符串明文=获取字符串(“明文:”); printf(“密文:%s\n”,sub(明文,密码)); }
您的操作系统可能正用于防止利用内存损坏漏洞进行攻击。这可能是
sum
变量的值在大约50%的时间内具有不正确值的原因。如注释中所示,指针与
if((int)cipher[i]>96&&(int)cipher<123)
中的整数进行比较,这可能是问题所在。 但是,ASLR似乎被调试器禁用,并且地址不会随机化。因此,变量
cipher
指向的地址不是随机化的,并且总是得到相同的结果

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

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

您还应该看到编译器警告

为了

if((int)密码[i]>96&(int)密码<123)
我得到以下警告:

warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
if ((int) cipher[i] > 96 && (int) cipher < 123) {
警告:从指针转换为不同大小的整数[-Wpointer到int cast]
if((int)密码[i]>96&(int)密码<123){

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

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

这会将循环更改为

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];
}
for(int i=0;iprintf(“密钥必须只包含字母字符。\n”);
返回1;
/*中断*/
}
和-=(int)密码[i];
}
这将减少代码长度,使代码更具可读性,避免常量,并避免一些陷阱。
还有一点,这里不需要
中断
,因为您已经从函数中返回了
。因此,中断永远不会到达。

“键必须只包含字母字符。”?使用
isalpha()
,使您的代码更简单。Re最后,最后一个if语句检查sum是否为0,这意味着只输入了唯一的字符:该推断不正确。
aaaaaaaaaaaaaaaaaazzzzzzzzzzzzz
ABCDEFGHIJKLMNOPQRSTUVWXYZ具有相同的总和,因此比较它们的总和并不能区分它们。经验法则:具有一个自由度的统计数据(如总和)无法区分具有26个自由度的集合,如26个字母的字符串。请勿使用co在源代码中使用
96
123
65
90
、或
32
。使用
'a'
'z'
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];
}