Проблемы при написании программы шифрования строк Basi c в C - Индексирование массивов символов - PullRequest
1 голос
/ 29 января 2020

Я немного застрял, пытаясь написать программу, которая "шифрует" строку, в C. Цель программы - позволить пользователю зашифровать строку, введя шифр, который будет использоваться для замены букв в исходной строке и ее искажения. Моя оригинальная программа была намного более сложной, чем эта, с logi c для обработки паролей пользователя и поддержки кейса (что все работало, шокирующе!). Однако проблема с абсолютным основанием c, которую я не могу решить, заключается в том, что строка, возвращаемая моей функцией шифрования, неверна.

Я переписал еще одну базовую версию функции, чтобы попытаться отладить ее; это была моя наивная версия программы, прежде чем я начал искать информацию:

// Barebones character swap for the encryption program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define GET_CHARS_MAX 100

const char plainAlphabet[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 prebakedCypher[26] = {'v', 'c', 'h', 'p', 'r', 'z', 'g', 'j', 'n', 't', 'l', 's', 'k',
                                 'f', 'b', 'd', 'q', 'w', 'a', 'x', 'e', 'u', 'y', 'm', 'o', 'i'};

int encryptString(char *encryptStr, int stringLength)
{
    for (int i = 0; i < 26; i++)    // For each letter in the alphabet
    {
        for (int j = 0; j < stringLength; j++)    
        {
            if (encryptStr[j] == plainAlphabet[i]) // Find and replace that letter on each pass
            {
                encryptStr[j] = prebakedCypher[i];
            }
        }
    }
}

int main()
{
    char *userString      = malloc(GET_CHARS_MAX);
    char *stringToEncrypt = malloc(GET_CHARS_MAX); 
    // Get user input into string
    printf("\n Enter a string, 100 characters long maximum: ");
        fgets(userString, GET_CHARS_MAX, stdin);
        int stringLength = strlen(userString) - 1;    // Remove null I think?

    // Make a copy of the input to encrypt
    strcpy(stringToEncrypt, userString);
        printf("\n Copied string: %s", stringToEncrypt);

    // Check that indexing the alphabet and cypher actually works
    // the way that you think it does
    printf("\n Alphabet element 1: %c \n Cypher element 1: %c", plainAlphabet[0], prebakedCypher[0]);
    printf("\n Alphabet element 't': %c \n Cypher element 't': %c", plainAlphabet[19], prebakedCypher[19]);

    // 'Encrypt' string and display result
    printf("\n Plaintext string: %s", userString);
        encryptString(stringToEncrypt, stringLength);
    printf("\n Encrypted string: %s", stringToEncrypt);

    return 0;
}

Как видите, logi c очень прост; если для каждой буквы алфавита (i) мы находим эту букву в нашей строке (j), замените ее на букву в соответствующей позиции от шифра (то есть «a» следует заменить на «v», et c Однако вывод был запутанным:

 Enter a string, 100 characters long maximum: this is a string

 Copied string: this is a string

 Alphabet element 1: a
 Cypher element 1: v
 Alphabet element 't': t
 Cypher element 't': x
 Plaintext string: this is a string

 Encrypted string: mmfa fa u amoffg

Мне нравится проверять столько, сколько я могу, с помощью printf, массивы символов, похоже, корректно индексируются, но не правильно назначаются в for-loops ( и 't', и 'h' являются ' m ', 'a' присваивается символ '' 1015 * u 'и т. д.) Я посмотрел, как индексировать массивы символов и нашел несколько сообщений, в которых указывалось, что я должен сделать дополнительным указателем на начало массива , а затем выполнить арифметику указателей c со счетчиком l oop, чтобы задержать указатель на нужный вам элемент. Моя ужасная попытка это была:

int encryptString(char *encryptStr, int stringLength)
{
    char *cypherPointer = &prebakedCypher[0];

    for (int i = 0; i < 26; i++)    // For each letter in the alphabet
    {
        for (int j = 0; j < stringLength; j++)    
        {
            if (encryptStr[j] == plainAlphabet[i]) // Find and replace that letter on each pass
            {
                encryptStr[j] = (*cypherPointer) + i;
            }
        }
    }
}

, которая просто производит мусор.

В простых примерах, которые я обнаружил, люди просто использовали for-loops для распечатки значений из массива символов, используя ptr, чтобы объяснить, что они делают / ч теперь они работают.

Я новичок и, вероятно, слишком долго смотрю на мою оригинальную программу, чтобы определить, в чем заключается моя проблема. Может кто-нибудь объяснить, где моя логика c пошла не так, и если мое первоначальное наивное индексирование массива символов (которое я понимаю как указатель на элемент в charArr[0]) было в правильных строках или нет? Потому что, по сути, я думаю, что мое недоразумение заключается в том, что делать с указателем на массив (ы) символов и как правильно их индексировать / назначать.

Спасибо!

Редактировать: я должен упомянуть что, так как строка искажена, я думал, что моя программа работала сначала. Затем я попытался abcdef, чтобы убедиться, что правильные элементы считывались / заменялись, и обнаружил, что ввод не соответствует ожиданиям, учитывая, что операторы printf, кажется, индексируют alphabet и cypher arrays:

 Enter a string, 100 characters long maximum: abcdef

 Copied string: abcdef

 Alphabet element 1: a
 Cypher element 1: v
 Alphabet element 't': t
 Cypher element 't': x
 Plaintext string: abcdef

 Encrypted string: ummdoi

В шифре нет повторяющихся букв, поэтому и 'b', и 'c' нельзя заменить на ' m '. Мы также знаем, что «а» следует заменить на « v », а не « u ».

1 Ответ

2 голосов
/ 29 января 2020

Вы заменяете строку на месте, проверяете каждый символ 26 раз и заменяете его от 1 до 26 раз в зависимости от шифра и начального символа.

Например, именно поэтому и «b», и «c» в вашем примере становятся «m»:

  • «b» заменяется на «c» .
  • Следующая итерация, в которой 'c' заменяется на 'h'.
  • 5 итераций спустя, что «h» заменяется на «j».
  • 2 итерации позже, что «j» заменяется на «t».
  • 10 итераций позже этот «t» заменяется на «x».
  • 4 итерации позже, этот «x» заменяется в последний раз на «m».

Вместо этого просто проверьте каждый символ до 26 раз и замените его ровно один раз:

int encryptString(char *encryptStr, int stringLength)
{
    for (int i = 0; i < stringLength; i++)    // For each letter in input
    {
        for (int j = 0; j < 26; j++)    
        {
            if (encryptStr[i] == plainAlphabet[j]) // Find and replace that letter 
            {
                encryptStr[i] = prebakedCypher[j];
                break;
            }
        }
    }
}
...