0

我是一名新程序员,试图通过为 CS50 编写 pset 来自学。我编写了以下代码,它可以正常工作。

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


string vencipher(string text, string key)
{
    for (int i=0, j=0, n =strlen(text); i < n; i++,j++)
    {   
        int m = strlen(key);
        if (text[i] >= 65 && text[i] <= 90 && key[j % m] >= 65 && key[j % m] <= 90)
        {
            text[i] = 65 + ((text[i] - 65) + (key[j % m] - 65)) % 26;
        }
        else if (text[i] >= 65 && text[i] <= 90 && key[j % m] >= 97 && key[j % m] <= 123)
        {   
            text[i] = 65 + ((text[i] - 65) + (key[j % m] - 97)) % 26;
        }
        else if (text[i] >= 97 && text[i] <= 123 && key[j % m] >= 65 && key[j % m] <= 90)
        {
            text[i] = 97 + ((text[i] - 97) + (key[j % m] - 65)) % 26;
        }
        else if (text[i] >= 97 && text[i] <= 123 && key[j % m] >= 97 && key[j % m] <= 123)    
        {
            text[i] = 97 + ((text[i] - 97) + (key[j % m] - 97)) % 26;
        }
        else 
        {
            text[i] = text[i];
            j = j - 1;
        }    
    }       
    return text;
 } 

int keyvalidator(string text)
{
    int alphalen = 0;
    for (int i=0, n=strlen(text); i < n; i++)
    {
        if ((text[i] >= 97 && text[i] <= 123) || (text[i] >= 65 && text[i] <= 90))
        {
            alphalen = alphalen + 1;
        }
    }
    if (alphalen == strlen(text))
    {
        return 1;
    }
    else
    {
        return 0;
    }
}  

int main(int argc, string argv[])
{
    if (argc != 2 || keyvalidator(argv[1]) != 1)
    {
        printf("That is not a valid secret key!\n");
        return 1;
    }

    if (argc == 2)
    {
        string secretKey = argv[1];
        string plainText = GetString();
        printf("%s\n", vencipher(plainText, secretKey));       
    }
    return 0;
}

我想尝试将 vencipher 拆分为一些不同的方法,以尝试提高代码的可读性。这就是我所做的

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

string keycaseID(string key)
{
    for (int i=0, n=strlen(key); i < n; i++)
    {
        if (key[i] >= 65 && key[i] <= 90)
        {
            key[i] = 1;
        }

        else
        {
            key[i] = 0;
        }
    }
    return key;
}

string setkeycase(string key)
{
    for (int i=0, n=strlen(key); i < n; i++)
    {
        if (keycaseID(key)[i] == 1)
        {
            key[i] = key [i] - 65;
        }
        else if (keycaseID(key)[i] == 0)
        {
            key[i] = key [i] - 97;
        }
    }
    return key;
}

string vencipher(string text, string key)
{
    for (int i=0, j=0, n =strlen(text); i < n; i++,j++)
    {   
        int m = strlen(key);
        if (text[i] >= 65 && text[i] <= 90 && keycaseID(key)[j % m] == 1)
        {
            text[i] = 65 + ((text[i] - 65) + setkeycase(key)[j % m]) % 26;
        }
        else if (text[i] >= 65 && text[i] <= 90 && keycaseID(key)[j % m] == 0)
        {   
            text[i] = 65 + ((text[i] - 65) + setkeycase(key)[j % m]) % 26;
        }
        else if (text[i] >= 97 && text[i] <= 123 && keycaseID(key)[j % m] == 1)
        {
            text[i] = 97 + ((text[i] - 97) + setkeycase(key)[j % m]) % 26;
        }
        else if (text[i] >= 97 && text[i] <= 123 && keycaseID(key)[j % m] == 0)    
        {
            text[i] = 97 + ((text[i] - 97) + setkeycase(key)[j % m]) % 26;
        }
        else 
        {
            text[i] = text[i];
            j = j - 1;
        }    
    }       
    return text;
 } 

int keyvalidator(string text)
{
    int alphalen = 0;
    for (int i=0, n=strlen(text); i < n; i++)
    {
        if ((text[i] >= 97 && text[i] <= 123) || (text[i] >= 65 && text[i] <= 90))
        {
            alphalen = alphalen + 1;
        }
    }
    if (alphalen == strlen(text))
    {
        return 1;
    }
    else
    {
        return 0;
    }
}  

int main(int argc, string argv[])
{
    if (argc != 2 || keyvalidator(argv[1]) != 1)
    {
        printf("That is not a valid secret key!\n");
        return 1;
    }

    if (argc == 2)
    {
        string secretKey = argv[1];
        string plainText = GetString();
        printf("%s\n", vencipher(plainText, secretKey));       
    }
    return 0;
}

较新的代码可以编译,但是当我运行它时,我得到一个“浮点异常”,根据我的研究,这是模除以 0 的结果。我多次搜索我的代码,但找不到任何除以的实例0. 我想知道是否有人可以帮助我找到我的错误并向我解释导致浮点异常的原因。

4

2 回答 2

0

我还看到内存损坏的浮点异常,所以这是更有可能的情况,因为/您的代码中没有任何字符。

我会告诉你一些你做错的事情。keycaseID()通过多次调用同一个字符串(正如您在 中所做的那样setkeycase(),您可以保证得到一个全为零的字符串(0 而不是'0')。

第一次它将所有元素转换为 1 或 0,具体取决于它们的大小写(因此您会丢失它们的原始值)。第二次,因为它们要么全部为0要么1,它们将小于 65,因此全部设置为 0。

假设您的密钥都是字母字符(大写或小写),您可以使用类似这样的方法将其转换为 0 到 25 的值:

for (int i = strlen (key) - 1; i >= 0; i--)  // needs string.h
    if (isupper (key[i]))                    // needs ctype.h
        key[i] -= 'A';
    else
        key[i] -= 'a';

或者,甚至更短:

for (int i = strlen (key) - 1; i >= 0; i--)  // needs string.h
    key[i] = toupper (key[i]) - 'A';         // needs ctype.h

这些都不是完全可移植的,因为 C 不强制要求A-Z是连续的代码点,但是,只要你避开奇怪的非 ASCII 环境,你应该没问题:-)

于 2014-07-02T04:44:47.280 回答
0

这个问题原来是由于指针的问题,我们还没有在课堂上讨论过这个问题。这里发生的事情是字符串是由指向第一个字符的内存地址的指针定义的,所以当我尝试通过初始化一个新变量来创建字符串的副本时,我是在创建该地址的副本,从而编辑原始输入字符串和新副本,因为它们共享相同的内存地址。

因此 m 的长度确实为 0,因为 keycaseID 正在修改 key 的内存地址处的值,从而擦除 key 并导致 setkeycase 返回空字符串。

于 2014-07-05T20:37:09.210 回答