凯撒密码算法中 C 中的分段错误

Segmentation fault in C in Caesar cipher algorithm

正在尝试解决 CS50 的 Ceasar 解决方案。 我遇到分段错误。

更正式地说,凯撒算法(即密码)通过将每个字母“旋转”k 个位置来加密消息。更正式地说,如果 p 是一些明文(即未加密的消息),pi 是 p 中的第 i 个字符,k 是密钥(即非负整数),那么密文 c 中的每个字母 ci 计算为

ci = (pi + k) % 26

这是我的代码:

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

string cipher(string ptext, int k);

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        printf("Usage: ./caesar key\n");
        return 1;
    }
    else
    {
        string ptext = NULL;
        string ctext = NULL;

        for (int i = 0, n = strlen(argv[1]); i < n; i++)
        {
            if (isdigit(argv[1][i]) == 0)
            {
                return 1;
            }
            else
            {
                ptext = get_string("Text:");
                int k = atoi(argv[1]);
                ctext = cipher(ptext, k);
            }
        }

        printf("Plain Text: %s \n Cipher Text: %s", ptext, ctext);
        return 0;
    }
}


string cipher(string ptext, int k)
{
    string ctext = NULL;
    for (int i = 0, n = strlen(ptext); i < n; i++) {
        // check if lower / upper is true if yes then shift chars by k % 26 and append to ctext
        if (islower(ptext[i]))
        {
            ctext[i] = (ptext[i] + k - 96) % 26 + 96;
        }
        else if (isupper(ptext[i]))
        {
            ctext[i] = (ptext[i] + k - 65) % 26 + 65;
        } // else append as it is
        else
        {
            ctext[i] = ptext[i];
        }
    }
    return (ctext);
}

输入 Hi!。我想要一个输出 Ij! 我无法弄清楚这个错误。请帮忙

with debug my code is exiting at ctext1[i] = (ptext[i] + k1 - 65) % 26 + 65;

您还没有为您的字符串分配任何内存。这是分段错误的原因,因为 ctext[i] 访问了无效的内存地址。

要解决这个问题,您必须将内存分配给 ctext

CS50 introduces a type string hiding a char pointer. This creates confusion as this string type is very different from what other languages name as such. Pointers are a fundamental concept that must be mastered to write programs in C.

The statement ptext = get_string("Text:"); sets ptext to the pointer value returned by the function get_string() declared in <cs50.h>. This function allocates memory for an array of char, reads user input into this array, sets a null terminator (a byte with a zero value) at the end of the array and returns a pointer to the first element of this array.

For your program to work, you can either:

  • modify the array in place, replacing each byte with its cipher value, or
  • allocate another array and store the cipher values into it, appending a null terminator after them. You chose this approach, but did not allocate the array.

Note also these problems:

  • the for loop validating the key string should be separate from the code calling the cypher function.
  • you should use character values such as 'a' and 'A' instead of hard coding their ASCII values. It improves portability and readability.

Here is a modified version:

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

char *cipher(char *ptext, int k);

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: ./caesar key\n");
        return 1;
    } else {
        char *key = argv[1];

        for (int i = 0, n = strlen(key); i < n; i++) {
            if (isdigit(key[i]) == 0) {
                return 1;
            }
        }
        int k = atoi(key);
        char *ptext = get_string("Text:");
        char *ctext = cipher(ptext, k);

        printf("Plain Text: %s\nCipher Text: %s", ptext, ctext);
        free(ctext);
        return 0;
    }
}

char *cipher(char *ptext, int k) {
    int n = strlen(ptext);
    char *ctext = malloc(n + 1);  // allocate memory for the cipher string
    if (ctext == NULL)
        return NULL;
    for (int i = 0; i < n; i++) {
        unsigned char pi = ptext[i];
        // check if lower / upper is true if yes then shift chars by k % 26 and append to ctext
        if (islower(pi))
        {
            // handle lowercase letter
            ctext[i] = (pi - 'a' + k) % 26 + 'a';
        }
        else if (isupper(pi))
        {
            // handle uppercase letter
            ctext[i] = (pi - 'A' + k) % 26 + 'A';
        }
        else
        {
            // else append as it is
            ctext[i] = pi;
        }
    }
    ctext[n] = '[=10=]';  // set the null terminator
    return ctext;
}