我将 运行 保留为一个我似乎无法修复的分段错误

I keep running into a segmentation error that I can't seem to be able to fix

对于我正在学习的课程,我应该创建一个程序,使用用户作为命令行参数输入的密钥从明文创建一个简单的密文。

这是代码,它是用 C 语言编写的

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

int main(int argc , string argv[])
{
    string key = argv[1];
    char keyL[2][26];
    char keyU[2][26];
    int normL = 97;
    int normU = 65;
    for (int i = 0;i <= 25;i++ , normL++, normU++)
    {
        keyL[0][i] = tolower(key[i]);
        keyU[0][i] = toupper(key[i]);
        keyL[1][i] = (char) normL;
        keyU[1][i] = (char) normU;
    }
    string plaint = get_string("plaintext:);
    string ciphert = "";
    int lengplain = strlen(plaint);
    for (int f = 0 ; f <= lengplain ; f++)
    {
        if (isupper(plaint[f]) == true)
        {
            for (int d = 0;d<=25;d++)
            {
                if (plaint[f] == keyU[0][d])
                {
                    ciphert[f] = keyL[1][d];
                }
            }
        }
        else if (islower(plaint[f]) == true)
        {
            for (int x = 0;x<=25;x++)
            {
                if (plaint[f] == keyU[0][x])
                {
                    ciphert[f] = keyL[1][x];
                }
            }
        }
        else
        {
            ciphert[f] = plaint [f];
        }
    }
    printf("ciphertext: %s\n" , ciphert);
}

这可以编译,但是当我 运行 它时,我 运行 变成了一个分段错误。如果您发现任何逻辑错误,请自行保留。这是我优先修复的分段错误。

谢谢!

string ciphert = "";

这将用“”初始化字符串。问题?它位于只读部分。你在这一行中写: ciphert[f] = plaint [f]; 到这个数组==> 你写到一个只读部分==> 崩溃。 (此外,您应该检查 argc 中提供的参数数量,否则它会在这一行中崩溃 (keyL[0][i] = tolower(key[i]);)

c 中的字符串与其他语言中的字符串不同。在 c 中,字符串是指向字符数组的指针,其中最后一个字符是空终止符 '[=10=]'。当您声明字符串 ciphert = ""; 时,您实际上是在创建一个长度为 1 的字符数组,其中只有空终止符。当您尝试访问不存在的密码元素时会发生段错误 ciphert[f] = plaint[f]

您必须将 ciphert 声明为长度为 lengplain + 1 的数组,这使得它与明文(加上空终止符)的长度相同,并且允许您这样做 ciphert[f] = plaint[f]。 我建议您看一下有关 c.

中字符串的一些指南

发布的代码有几个问题。这是一个典型的问题:

string plaint = get_string("plaintext:);

get_string() 的参数必须是指向以 NUL 结尾的字符数组的指针。

这个参数:

"plaintext:

缺少结尾的双引号:"

你试过编译贴出的代码吗?我想不会,因为编译会因为这个问题而失败。

编译时,始终启用警告,然后修复这些警告。

对于gcc建议:

gcc -c -g -Wall -Wextra -Wconversion -pedantic -std=gnu11

请注意,其他编译器使用不同的选项来产生相同的结果。

关于;

int lengplain = strlen(plaint);

函数:strlen()returns一个size_t,不是一个int

关于;

string key = argv[1];

切勿在未首先检查 argc 以确保用户实际输入了预期的命令行参数的情况下访问 argv[0] 以外的内容。

关于:

int normL = 97;
int normU = 65;

使用 'magic' 数字是一种糟糕的编程习惯,因为它们会使代码更难以理解、调试等。建议;

int normL = 'a';
int normU = 'A';

关于:

char keyL[2][26];
char keyU[2][26];

'magic'数26没有意义。建议(在 #include 语句之后)定义一个有意义的名称:

#define alphabetLen 26

然后在整个代码中使用该有意义的名称。

您可以通过更改以下内容来避免您的代码读者的烦恼:

for (int i = 0;i <= 25;i++ , normL++, normU++)
{
    keyL[1][i] = (char) normL;
    keyU[1][i] = (char) normU;

for ( int i = 0; i < alphabetLen; i++ )   
{
    keyL[1][i] =  normL + 'a';
    keyU[1][i] =  normU + 'A';

并且:

int normL = 97;
int normU = 65;  

至:

int normL = 'a';
int normU = 'A';  

当然,为了消除一些警告,这个

keyL[1][i] = normL;
keyU[1][i] = normU;

最好通过以下方式编写(并且没有编译器警告):

keyL[1][i] = (char) normL;
keyU[1][i] = (char) normU;

关于;

string ciphert = "";

这会生成一个指向只读内存的指针,指向一个只有 1 个字符长的文字。因为它在只读内存中,代码不能写入它,也不能从它偏移。建议:

string ciphert[ 26+1 ];