Код компилируется нормально. Я попытался использовать отладчик, но не смог понять проблему. Каждая итерация «c» заполняется, но похоже, что так, как я пытаюсь назначить эту переменную «c», в массиве ничего не происходит, так что конечный оператор печати заканчивается «зашифрованный текст: ПУСТОЙ НИЧЕГО»

Любая помощь или идеи очень приветствуются. Я прохожу курсы и пытаюсь решить поставленную задачу. Я только начинаю, пожалуйста, не осуждайте :)

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

int main (int argc, string argv[])
{
    //check if there is exactly 2 agruments passing, otherwise promt for a valid key(+return 1, to signal mistake)
    if(argc < 2 || argc<2 )
    {
        printf("Usage: ./caesar key \n");
        return 1;
    }
    //otherwise check if the key is only a digit and promt for a valid key(+return 1, to signal mistake)
    //loop thorugh each character in the second agrument and validate
    else if(argc == 2)
    {
        for (int i = 0; i < strlen(argv[1]); i++)
        {
            if(!isdigit(argv[1][i]))
            {
                printf("Usage: ./caesar key \n");
                return 1;
            }
        }
    }


    //convert a string to int variable to be used in transformation of letters
    int key = atoi(argv[1]);

    //promt for plaintext
    string initial_text = get_string("plaintext: ");

    //create an array of int to store encrypted letters to then be converted in print by (char)
    int cipher[strlen(initial_text)];
    int i = 0;
    int n = strlen(initial_text);

    for (i = 0; i < n; i++)
    {
        int c = 0;

        if (isupper(initial_text[i]))
        {
            c = (((int)initial_text[i] - 65 + key) % 26) + 65;
            cipher[i] += c;
        }

        else if (islower(initial_text[i]))
        {
            c = (((int)initial_text[i] - 97 + key) % 26) + 97;
            cipher[i] += c;
        }

        //for all none alphabetic symbols leave them as they are
        else
        {
            c=initial_text[i];
            cipher[i] += c;
        }
    }

    //////////////////
    printf("ciphertext: %c\n", (char)cipher);

}
0
KabdeshK 17 Сен 2021 в 21:45

2 ответа

Лучший ответ

Есть ряд вопросов:

  1. Использование int для cipher, когда вы [вероятно] хотите char.
  2. Не указано достаточно места в cipher для завершающего признака конца строки 0x00 [EOS]
  3. Не установка EOS в конце.
  4. Использование %c вместо %s в вашем printf.
  5. if ((argc < 2) || (argc < 2)) неверен и может быть заменен на if (argc != 2).
  6. Поскольку этот if выполняет return, последующая проверка else if больше не требуется.
  7. "аппаратные" десятичные значения (например, 65 для 'A').
  8. Использование strlen в выражении условия в цикле for. Это увеличивает время работы цикла с O (n) до O (n ^ 2).
  9. Это можно заменить (например) сравнением элемента массива с 0x00.
  10. Использование strtol вместо atoi и проверка конца позволяет декодировать и за одну операцию.
  11. Не используйте string при определении argv - используйте char **argv.
  12. В конце вашего main отсутствует return 0;.
  13. Есть много реплицированного кода, который можно упростить.

Вот код после рефакторинга:

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

// I don't have cs50 handy, so a quick hack ...
#define string  char *
string
get_string(const char *prompt)
{
    char buf[1000];
    char *cp;

    printf("%s",prompt);
    fflush(stdout);

    do {
        cp = fgets(buf,sizeof(buf),stdin);
        if (cp == NULL)
            break;

        // strip newline
        buf[strcspn(buf,"\n")] = 0;

        // IIRC, [real] get_string does heap allocation (vs. static buffer) but
        // for demo purposes here, doesn't really matter
        cp = strdup(buf);
    } while (0);

    return cp;
}

int
main(int argc, char **argv)
{

    // check if there is exactly 2 arguments passing, otherwise prompt for a
    // valid key(+return 1, to signal mistake)
    if (argc != 2) {
        printf("Usage: ./caesar key \n");
        return 1;
    }

    // otherwise check if the key is only a digit and prompt for a valid
    // key(+return 1, to signal mistake)
    // loop through each character in the second argument and validate
    char *arg = argv[1];

    // convert a string to int variable to be used in transformation of letters
    int key = strtol(arg,&arg,10);
    if (*arg != 0) {
        printf("Usage: ./caesar key \n");
        return 1;
    }

    // prompt for plaintext
    string initial_text = get_string("plaintext: ");

    // create an array of int to store encrypted letters to then be converted
    // in print by (char)
    // NOTE: we need one extra to make room for the trailing EOS
    char cipher[strlen(initial_text) + 1];

    const char *src = initial_text;
    char *dst = cipher;

    for (int chr = *src++;  chr != 0;  chr = *src++, ++dst) {
        if (isupper((unsigned char) chr)) {
            *dst = (((chr - 'A') + key) % 26) + 'A';
            continue;
        }

        if (islower((unsigned char) chr)) {
            *dst = (((chr - 'a') + key) % 26) + 'a';
            continue;
        }

        // for all none alphabetic symbols leave them as they are
        *dst = chr;
    }

    // set the trailing EOS
    *dst = 0;

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

    return 0;
}
0
Craig Estey 17 Сен 2021 в 20:14

Вы могли бы написать, например,

if ( argc < 2 || argc<2 || argc < 2 )

Вместо того

if ( argc < 2 || argc<2 )

И это будет правильно, но не имеет смысла.

Просто пиши

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

Это еще заявление

else if(argc == 2)

Является избыточным. Убери это.

Вместо этого цикла for

for (int i = 0; i < strlen(argv[1]); i++)
{
    if(!isdigit(argv[1][i]))
    {
        printf("Usage: ./caesar key \n");
        return 1;
    }
}

Проще написать

char *p;
unsigned long ley = strtoul( argv[1], &p, 10 );

if ( *p || key == ULLONG_MAX )
{
    puts( "Usage: ./caesar key" );
    return 1;   
}

Нет необходимости определять массив переменной длины. Вы можете изменить исходную строку, на которую указывает указатель initial_text.

Введение переменной n излишне

int n = strlen(initial_text);

Вместо петли

for (i = 0; i < n; i++)

Вы можете использовать этот цикл

for ( size_t i = 0; initial_text[i] != '\0'; i++ )

Вместо этих операторов if

if (isupper(initial_text[i]))

А также

else if (islower(initial_text[i]))

Безопаснее будет написать

if ( isupper( ( unsigned char )initial_text[i]))

А также

else if ( islower( ( unsigned char )initial_text[i] ) )

Также использование магических чисел, таких как 65, делает код нечитаемым. Например, вы могли
записывать

C = (initial_text [i] - 'A' + клавиша)% ('Z' - 'A' + 1) + 'A';

А также

c = ( initial_text[i] - 'a' + key ) % ( 'z' - 'a' + 1) + 'a';

И вместо составного оператора присваивания

cipher[i] += c;

Тебе нужно написать

initial_text[i] = c;

Также в вызове printf вы используете неверный спецификатор преобразования% c и приведение

printf( "ciphertext: %c\n", (char)cipher);

Поскольку строка должна быть обновлена ​​на месте, вызов printf будет выглядеть так:

printf( "ciphertext: %s\n", initial_text );
0
Vlad from Moscow 17 Сен 2021 в 20:14