首页 > 解决方案 > cs50 PSET2 替换:仅在使用 DWUSXNPQKEGCZFJBTLYROHIAVM 作为密钥加密所有字母字符时出现问题

问题描述

我是cs50的初学者。这是我第二周的工作。这是问题集替换。

所以这是我的代码。除这道题外,所有题都编译成功。输出为“分段错误”

这是我的代码:

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

int main (int argc, string argv[])

{
    string key1 = argv[1];

//check for only 2 arguments//
if (argc != 2)
{
    printf("Usage: ./substitution key\n");
    return 1;
}

//check key length, must 26 lenght//
if (strlen(key1) != 26)
{
    printf("Key must contain 26 characters.\n");
    return 1;
}

for (int i=0; i < strlen(key1); i++)
{
    //check for non alphabet//
    if (!(isalpha(key1[i])))
    {
        printf("Key must contain only letters.\n");
        return 1;
    }

    //convert all word to uppercase to make encryption easier//
    else
    {
        key1[i] = toupper (key1[i]);
    }

    //check for not repeated word//
    for (int j=0; j < i; j++)
    {
        if (key1[i] == key1[j])
        {
            printf("Key must not contain repeated letters.\n");
            return 1;
        }
    }
}

//ask input//
string input1 = get_string("plaintext: ");
string input2 = input1;

//check if the word is lower or uppercase//
int checker[25];
for (int s = 0; s < strlen (input1); s++)
{
    if (isupper(input1[s]) == 0)
    {
        checker[s] = 0; //false

        //convert to uppercase to make encryption easier//
        input1[s] = toupper (input1[s]);
    }
    else
    {
        checker[s] = 1; //true
    }

    //printf("Input %d: %c is %d\n", s, input1[s], checker[s]); //debug//

}

//printf("word is %s\n", input1); //debug//

//CONVERTTTT//
int new_ascii = 0;
printf("ciphertext: ");

for (int k = 0; k < strlen(input1); k++)
{
    char x = input1[k];
    int ascii = (int) x;

    //check if it's alphabet or not//
    if (isalpha(x))
    {
        ascii -=  65;
        new_ascii = key1[ascii];

        //restore to upper/lowercase
        if (checker[k]==0)
        {
           new_ascii = (int) tolower ((char) new_ascii); //we use tolower cause all word has converted to upper
        }

    }
    else //if not just continue
    {
        new_ascii = ascii;
    }

    printf("%c", (char) new_ascii);
}

printf("\n");

return 0;
}

这是输出:

./substitution DWUSXNPQKEGCZFJBTLYROHIAVM

plaintext: The quick brown fox jumps over the lazy dog

Segmentation fault

我不知道我的问题在哪里,因为这是唯一一个无法编译的。有人有线索吗?

标签: ccs50substitution

解决方案


(不幸的是,我无法在 onlinegdb.com 上重现分段错误。)

数组的大小checker必须至少是输入的字符串长度。这是有问题的,因为您不知道输入将持续多长时间。您的示例输入比数组的大小 25 长,因此您的代码将写入数组末尾并(尝试)覆盖存储在此内存位置的任何内容。这可能导致分段错误。

为避免对数组的这种越界访问,您可以检查输入字符串的长度并截断它或打印一条错误消息,通知用户有关限制。

更好的解决方案是将大写/小写检查集成到加密输入的函数中。使用这种方法,您必须只知道刚刚处理的字符的大写/小写信息,而不是输入字符串的所有字符。

由于这是一项学习任务,因此我没有展示现成的解决方案,而只是将算法作为伪代码:

for all characters of the input string
{
    get the next character

    if alphabetic (or better if it is in range 'A'..'Z' or 'a'..'z')
    {
        if lowercase
        {
            set lowercase flag
            key index = character - 'a'
        }
        else
        {
            clear lowercase flag
            key index = character - 'A'
        }

        get encrypted character based on key index

        if lowercase flag
        {
            convert to lowercase
        }

        print encrypted character
    }
    else /* not alphabetic */
    {
        print original character
    }
}

请注意,函数的结果isalpha取决于您的语言环境设置。对于英语以外的语言,其他字符可能被归类为字母字符。这可能会导致对您的密钥数组的越界访问。为避免这种情况,您可以为..或..添加检查isascii或使用显式检查。'A''Z''a''z'


推荐阅读