我一直在try 做CS50的S课程(这是我第一次接触C语言,请多多包涵),并解决了替换问题.我已经坚持了一段时间了. 这是我的错误代码:

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

int check(string str);

int main(int argc, string argv[])
{


    if(argc < 1 || argc > 2)
    {
        printf("Usage: ./substitution key");
        return 1;
    }

    string key = argv[1];

    if(check(key) == 1)
    {
            return 1;
    }



    string plaintext = get_string("plaintext:");
    int lenght = strlen(plaintext);
    char ciphertext[lenght + 1];

    for(int i = 0; i <= lenght; i++)
    {
        if(islower(plaintext[i]))
        {
            plaintext[i] -= 97;
            ciphertext[i] = key[(int)plaintext[i]];
            if(isupper(ciphertext[i]))
            {
                ciphertext[i] = tolower(ciphertext[i]);
            }
        }

        if(isupper(plaintext[i]))
        {
            plaintext[i] -= 65;
            ciphertext[i] = key[(int)plaintext[i]];
            if(islower(ciphertext[i]))
            {
                ciphertext[i] = toupper(ciphertext[i]);
            }
        }
    }

    printf("ciphertext:%s", ciphertext);





}




int check(string str)
{
    //controlle del numero di lettere, che i caratteri della chiave non siano ripetuti o numerici hahahahah lol
   char alphabet[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
   int count[26] = { 0 };
   if(strlen(str) != 26)
   {
    printf("Key must contain 26 characters.");
    return 1;
   }
   for(int i = 0; i < 25; i++)
   {
        if(isalpha(str[i]) == 0)
        {
            return 1;
        }

        str[i] = (char)tolower(str[i]);

        for(int j = 0; j < 25; j++)
        {
            if(str[i] == alphabet[j])
            {
                count[j] += 1;
            }

        }
    }

    for(int i = 0; i < 25; )
    {
        if(count[i] != 1)
        {
            return 1;
        }
    }

    return 0;

}

主要问题是,通过存储argv[1]将其作为字符串处理似乎是不可能的,因为无论何时我运行程序,它都会无休止地运行.

这是我在调试控制台上得到的分段错误: Program received signal SIGSEGV, Segmentation fault. __strlen_evex () at ../sysdeps/x86_64/multiarch/strlen-evex.S:77

当我try 调试时,它显示在try 使用strlen()获取密钥长度时出现分段错误.另外,在调试时,它显示key已存储0x0,所以可能我不知何故也错误地将argv[1]赋值给key.我认为这可能是因为argv[1]不是以一个

空字符,但我不确定,因为我只知道c的基本知识.

推荐答案

以下是一个完整的最小示例,总结了所讨论的更改:

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

int check(string str);

int main(int argc, string argv[])
{

    if(argc != 2)
    {
        printf("Usage: ./substitution key");
        return 1;
    }

    string key = argv[1];

    if(check(key) == 1)
    {
            return 1;
    }

    string plaintext = get_string("plaintext:");
    int lenght = strlen(plaintext);
    char ciphertext[lenght + 1];
    memset(ciphertext, 0, (lenght + 1) * sizeof(char));

    for(int i = 0; i < lenght; i++)
    {
        if(islower(plaintext[i]))
        {
            plaintext[i] -= 97;
            ciphertext[i] = key[(int)plaintext[i]];
            if(isupper(ciphertext[i]))
            {
                ciphertext[i] = tolower(ciphertext[i]);
            }
        }

        if(isupper(plaintext[i]))
        {
            plaintext[i] -= 65;
            ciphertext[i] = key[(int)plaintext[i]];
            if(islower(ciphertext[i]))
            {
                ciphertext[i] = toupper(ciphertext[i]);
            }
        }
    }

    printf("ciphertext:%s\n", ciphertext);
}

int check(string str)
{
    //controlle del numero di lettere, che i caratteri della chiave non siano ripetuti o numerici hahahahah lol
   char alphabet[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
   int count[26] = { 0 };
   if(strlen(str) != 26)
   {
    printf("Key must contain 26 characters.");
    return 1;
   }
   for(int i = 0; str[i] != 0; i++)
   {
        if(isalpha(str[i]) == 0)
        {
            return 1;
        }

        str[i] = tolower(str[i]);

        for(int j = 0; j < 26; j++)
        {
            if(str[i] == alphabet[j])
            {
                count[j] += 1;
            }

        }
    }

    for(int i = 0; i < 26; i++)
    {
        if(count[i] != 1)
        {
            return 1;
        }
    }

    return 0;

}

输出:

./substitution ABCDEFGHIJKLMNOPQRSTUVWXYZ
plaintext:example
ciphertext:example
$ 

以下是对这些变化的逐步解释:

try 更改:

if(argc < 1 || argc > 2)

致:

if(argc != 2)

就像@Some程序员sibling comments 的那样.请记住,argc是命令行上的参数数量(包括程序名本身).


此外,在check()中,你假设str的长度是25,从这个判断:

for(int i = 0; i < 25; i++)
{
     if(isalpha(str[i]) == 0)
     ...

记住C-strings are NULL terminated,所以你应该这样做:

for(int i = 0; str[i] != 0; i++)
{
     if(isalpha(str[i]) == 0)
     ...

为了不超出str的界限.

此外,改变这一点:

    for(int j = 0; j < 25; j++)
    {
        if(str[i] == alphabet[j])

致:

    for(int j = 0; j < 26; j++)
    {
        if(str[i] == alphabet[j])

因为您希望从0迭代到25,而不是迭代到24.

现在在这里:

for(int i = 0; i < 25; )
{
    if(count[i] != 1)
    {
        return 1;
    }
}

除非count[0]不同于1,否则您将进入无限循环.您需要增加此for循环范围内定义的i计数器.您还需要将25更改为26,以便迭代整个counts数组(包括最后一个元素count[25]);因此将其更改为:

for(int i = 0; i < 26; i++)
{
    if(count[i] != 1)
    {
        return 1;
    }
}

您忘记了以空结尾的密文字符串,这就是为什么在使用C标准库中的字符串方法(它要求所有字符串都以空结尾)时越界的原因.因此,改变这一点:

char ciphertext[lenght + 1];

致:

char ciphertext[lenght + 1];
memset(ciphertext, 0, (lenght + 1) * sizeof(char));

正如在C compile error: "Variable-sized object may not be initialized"中所解释的那样.

然后,您希望迭代纯文本和密文,其中,您需要判断for循环的计数器是否没有超过具有最小长度的字符串的长度,在本例中为plaintext,因此请考虑更改以下内容:

for(int i = 0; i <= lenght; i++)

致:

for(int i = 0; i < lenght; i++)

有了这一更改,ciphertext的最后一个字符将始终为空,因此您可能想要重新考虑那里的逻辑,这取决于您想要实现的目标.


Minor:不需要对返回值tolower()进行强制转换,因此请更改以下设置:

str[i] = (char)tolower(str[i]);

对此:

str[i] = tolower(str[i]);

C++相关问答推荐

新的memaligning函数有什么用?

函数指针始终为零,但在解除引用和调用时有效

你能用自己的地址声明一个C指针吗?

标准的C17标准是用括号将参数包装在函数声明中吗

当打印字符串时,为什么在c中没有使用常量限定符时我会收到警告?

ATmega328P EEPROM未写入

我怎么才能用GCC编译一个c库,让它包含另一个库呢?

CC2538裸机项目编译但不起作用

为什么指针运算会产生错误的结果?

一旦运行长度超过2,编译器是否会优化";strnlen(mystring,32)>;2";以停止循环?

如何用c语言修改shadow文件hash部分(编程)?

MacOS下C++的无阻塞键盘阅读

为什么电路板被循环删除?

C中的空指针是什么(_N)?

为什么argc和argv即使在主函数之外也能工作?

将char*铸造为空**

保存有符号整数结果的变量是否会溢出(后增量的副作用),并且此后从未在任何表达式中使用过它,是否会导致 UB?

多行表达式:C 编译器如何处理换行符?

如何在 C 中的 Postgres 函数的表中 for 循环

我该如何处理这个 C 90 代码中的内存泄漏?