1

私はそのようなメソッドを作成しようとしています(シーザー暗号を使用してメッセージを暗号化し、ユーザーが入力して表示します):

void encrypt(char *message, int shift);

私のコード:

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

char num(char c)
{
    const char upper_alph[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'};
    const char lower_alph[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'};

    if(isupper(c)) {
        for(int i = 0; i < 26; i++)
            if(upper_alph[i] == c)
                return i;
    } else {
        for(int i = 0; i < 26; i++)
            if(lower_alph[i] == c)
                return i;
    }
    return 0;
}

void encrypt(char *message, int shift)
{
    int i = 0;
    const char upper_alph[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'};
    const char lower_alph[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'};
    while(message[i] != NULL)
    {
        if(isalpha(message[i]))
        {
            if(isupper(message[i])) {
                printf("%c", upper_alph[(num(message[i])+shift)%26]);
            } else {
                printf("%c", lower_alph[(num(message[i])+shift)%26]);
            }
        } else {
            printf("%c", message[i]);
        }
            i++;
    }
}

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2

static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

int main()
{
    //reverse();
    //printf("\n\n");
    int rc;
    char mes[1024];
    int sh = 0;
    rc = getLine ("Enter message to be encrypted: ", mes, sizeof(mes));
    if (rc == NO_INPUT) {
        // Extra NL since my system doesn't output that on EOF.
        printf ("\nNo input\n");
        return 1;
    }
    if (rc == TOO_LONG) {
        printf ("Input too long [%s]\n", mes);
        return 1;
    }
    encrypt(mes, 1);
    fflush(stdin);
    getchar();
    return 0;
}

助けてくれる人、助けようとする人に感謝します。

:)

編集:多くの修正を行いました。まだ動作していません :/

EDIT2:さらに多くの修正を行いました。アクセス違反の取得@"while(* message!='\ 0')"

EDIT3:上記のコードを動作するコードに更新しました。みなさん、ありがとうございました!

4

4 に答える 4

2

にメモリを割り当てていないため、機能しませんmes:

char mes[512]; // Enough space!

使い方std::stringは簡単です:

string mes;
int sh = 0;
cout << "Enter message to be encrypted: " << endl;
getline(cin, mes);
cout << "Enter a shift amount (1-25): " << endl;
cin >> sh;
encrypt(mes, sh);

encrypt関数を次のように変更します。

void encrypt(const string &message, int shift)

そして、あなたのキャラクターを範囲内に保ちます:

 upper_alph[(num(message[i])+shift)%26]
 lower_alph[(num(message[i])+shift)%26]
于 2013-03-22T08:15:52.023 に答える
2

ここには、OP が理解していないという根本的な問題があります。つまり、コンピューターにとって、文字は単なる数字です。それらの数字に意味を割り当てるのは私たち人間であり、どの数字が何を意味するかを判断することさえできません(ASCII、EBDIC、およびUnicodeに関する質問のコメントを参照)。

次の表は、ASCII 標準が数字を文字にマッピングする方法を示しています。

文字「a」は 97、「b」は 98、「c」は 99 などであることに注意してください。大文字は 65 から始まり、そこから上がります。文字「a」と「A」が同じ行にあることにも注意してください。これは、大文字と小文字の下位 5 ビットのビット パターンが同じであることを意味します。最後に、コンピューターは文字を数字としてしか認識しないため、文字に対して数値演算を実行できます。

'd' - 'a' == 3
100 - 97

2 番目に注意すべきことは、数学的には、Caeser 暗号はモジュロを加えたものに過ぎないということです。

encoded character = (plain text character + shift) mod 26

これで、コードをより効率的に記述できるようになりました:-

void Encode (char *message, int shift)
{
  while (*message)
  {
    char c = *message;

    if (isalpha (c)) // check c is a letter
    {
      // get the letter index: this maps 'A' to 0, 'B' to 1, etc
      // it also maps 'a' to 32 (97 - 65), 'b' to 33, etc
      c -= 'A'; 

      // this is 32 for lower case characters and 0 for upper case
      char case_of_c = c & 32; 

      // map 'a' to 'A', 'b' to 'B'
      c &= 31; 

      // the caeser shift!
      c = (c + shift) % 26; 

      // restore the case of the letter
      c |= case_of_c; 

      // remap the character back into the ASCII value
      c += 'A'; 

      // save the result of the shift
      *message = c; 
    }

    ++message;
  }
}
于 2013-03-22T09:09:51.503 に答える
2

1 つの問題は、ラップアラウンドしないことです。「Z」や「z」などの正のシフトが渡された場合、配列の外側でインクリメントするだけです。

次のようなことをする必要があります:

upper_alph[(num(message[i])+shift)%26]
    and
lower_alph[(num(message[i])+shift)%26]

また、次のメモリを割り当てる必要がありますmes

char mes[1024];

あなたscanfも間違っていると思います(cは文字、s文字列です):

scanf("%s", mes);

ただし、を使用%sすると、空白になるまでしか読み取れません。より良いオプションは、 を使用して行全体を読み取ることgetline()です。

于 2013-03-22T08:15:52.127 に答える
2

次の行で「範囲外のインデックス」エラーが発生します。

        if(isupper(message[i])) {
            printf("%c", upper_alph[num(message[i])+shift]);
        } else {
            printf("%c", lower_alph[num(message[i])+shift]);
        }

事前にインデックスを計算し、それが 0 から 25 の間であることを確認する必要があります。

int shiftedIndex = (num(message[i]) + shift) % 26;

コードが入力言語として英語でのみ機能するという事実を認識していますか?

于 2013-03-22T08:16:24.777 に答える