caesar加密(分段错误)

时间:2017-08-05 00:27:21

标签: c segmentation-fault cs50 caesar-cipher

我正在尝试编写一个Caesar对用户提供的字符串进行加密的程序,但每次尝试运行它时都会弹出错误“Segmentation Fault”。我做错了什么?

    int main(int argc, string argv[])
{
    if (argc != 2)
    {
        return 1;
    }

    int key = atoi(argv[1]);

    printf("Plaintext: ");
    string Ptext = get_string();
    string cipher = 0;

    if(Ptext != NULL)
    {
        for(int i = 0, n = strlen(Ptext); i < n; i++)
        {
            if(isalpha(i))
            {
                if(isupper(i))
                {
                    cipher += toupper(((i + key) % 26));
                }
                else
                {
                    cipher += tolower(((i + key) % 26));
                }
            }
            cipher += i;
        }
        printf("Ciphertext: %s", cipher);
        printf("\n");
    }
}

2 个答案:

答案 0 :(得分:2)

根据我在评论中阅读的内容,我们可以解决您的帖子最初缺失的一些信息。有一个typedef char* string以及一个提供的get_string()函数。根据这些假设,您首先要分配足够的空间来存储生成的密码字符串。

C中的字符串只是分配了字符数组,因此您需要以某种方式分配该内存。最好的方法是使用malloc在堆上分配它。

更改此行:string cipher = 0;string cipher = malloc(strlen(Ptext) + 1);这将分配足够的空间来存储生成的密文。现在,您需要以某种方式跟踪索引。添加int size = 0;现在,将循环更改为:

for(int i = 0, n = strlen(Ptext); i < n; i++)
    {
        if(isalpha(i))
        {
            if(isupper(i))
            {
                cipher[size++] = toupper(((i + key) % 26));
            }
            else
            {
                cipher[size++] = tolower(((i + key) % 26));
            }
        }
        else 
        {
            cipher[size++] = i;
        }
    }
    cipher[size] = 0; // for the null terminator

这样做会与您认为+=会做的事情相同。它会将字符插入分配的字符数组中的正确位置,然后将大小增加1,以便下一个插入位于下一个位置。打印字符串后最后要做的就是调用free(cipher);以基于malloc释放分配的内存

我建议查看mallocfree的工作原理,以及字符数组在C中的工作方式。这是typedef char* string的一个陷阱,即摘要离开C中的string实际上是什么,它是指向char数组的指针。

答案 1 :(得分:0)

我写了一个工作的Ceasar-cypher-function,它和我的代码一样接近你的代码。

以下是在线测试功能略有改变的变体。我只测试了第二个变体,并且仅使用在线c ++编译器(链接在下面),尽管它是c代码。

我希望你可以用它来推理程序的几个部分。

我试图解释的一点是计算密码字符。

对于大写字符,计算是

'A'+((26 + c -'A' + (key%26)) % 26);

第二个词是

(26 + c -'A' + (key%26)) % 26 //结果是0到25之间的数字,

如果key仅在-25到25之间,则(key%26)这个词可能只是key

如果key总是正数或零,则不需要添加26(即(26 +)。

因此对于0..25的密钥,该术语将是

(c -'A' + key) % 26

c -'A'将字符c转换为0..25的数字,然后添加键(=偏移或移位),然后将所有26或更高的数字向下移动术语% 26

所以现在你有一个从0到25的数字,它代表了密码字符。 但你真的想要一个从'A'到'Z'的角色,而不是0..25的数字。

你希望0为'A',1为'B',2 - &gt; 'C'...... 24-> Y和25->'Z'。 因此,您将“A”的ascii值添加到数字中。这就是术语'A' +(源代码中的第一项)的原因。这产生了所需的Ceasar-cipher-char。

正如您可能已经注意到的那样,类型string有点令人困惑。 我将string替换为char*。如果你提供类型string和函数get_string的声明,我们可以将它合并到代码中,但在我看来,string也不是c中类型的好名字

如果您对该代码有任何疑问,请询问。

您仍然可以对代码进行一些改进,因为几乎总能做到,例如

  • 将文字26放入const变量
  • 执行(key%26)操作一次而不是多次
  • 使用cipher[..]表示法而不是*pb
  • ......等。

所以这是程序:

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        return 1;
    }

    int key = atoi(argv[1]);

    const char * Ptext = get_string();

    if(Ptext != NULL)
    {
        char * cipher = 0;       
        size_t n = strlen(Ptext);

        printf("Plaintext: %s\n", Ptext);

        cipher = (char *) malloc((n+1)*sizeof(char));

        if (!cipher)
            return 1;

        char * pb = cipher;
        char c;

        for(int i = 0 ; i < n; i++)
        {
            c = Ptext[i];

            if(isalpha(c))
            {
                if(isupper(c))
                {
                    *pb = 'A'+((26 + c -'A' + (key%26)) % 26);
                }
                else
                {
                    *pb = 'a'+((26 + c -'a' + (key%26)) % 26); 
                }
            }
            else
            {
                *pb = c; 
            }
            ++pb;
        }

        *pb='\0';

        printf("Ciphertext: %s", cipher);
        printf("\n");

        free(cipher);
    }
    return 0;
}

使用

进行在线测试时,几乎相同的代码略有改动

https://www.onlinegdb.com/online_c++_compiler

#include <iostream>
#include <cstring>

using namespace std;

const char hw[]  = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG";

const char * get_string()
{
    return hw;
}

int main()
{
    int key = atoi("-3");

    const char * Ptext = get_string();

    if(Ptext != NULL)
    {
        char * cipher = 0;       
        size_t n = strlen(Ptext);

        printf("Plaintext: %s\n", Ptext);

        cipher = (char *) malloc((n+1)*sizeof(char));

        if (!cipher)
            return 1;

        char * pb = cipher;
        char c;

        for(int i = 0 ; i < n; i++)
        {
            c = Ptext[i];

            if(isalpha(c))
            {
                if(isupper(c))
                {
                    *pb = 'A'+((26 + c - 'A' + (key%26)) % 26);
                }
                else
                {
                    *pb = 'a'+((26 + c -'a' + (key%26)) % 26); 
                }
            }
            else
            {
                *pb = c; 
            }
            ++pb;
        }

        *pb='\0';

        printf("Ciphertext: %s", cipher);
        printf("\n");

        free(cipher);
    }
    return 0;
}

结果与https://en.wikipedia.org/wiki/Caesar_cipher

显示的结果相同