Программа Шифр Цезаря на C


Я новичок-промежуточный программиста C++, и я никогда не использовал или не понял, с ввода и проверки. Я просто всегда использовал потоки с++.

В любом случае, я просто хочу, чтобы код критика, как я никогда не использовал c ввод функции (признаюсь, я использовал и как функции printf()! Я даже сделал мои собственные функции sprintf(), совместимый с C++ класс String.)

Я надеюсь, что мой код-это хорошо. Я, как правило, чтобы получить код, чтобы работать должным образом, полностью игнорируя форматирование и производительность, то позже после того, как он работает я сделать его выглядеть и работать приятно.

Цезарь.с

#include <string.h> /* for strlen() */
#include "caesar.h"

char *getCipherText(char *src, int key) {
    int len = strlen(src);
    int i = 0;
    int ch = 0;

    /* Loop over each char in src */
    for (i = 0; i < len; i++) {
        ch = (int)src[i]; /* Convert the char to int to prevent many uneccecary casts */
        if (ch >= 65 && ch <= 90) { /* If the char is uppercase */
            ch += key; /* add the key */
            if (ch > 90) ch -= 26; /* if the char is higher than the highest uppercase char, sub 26 */
            if (ch < 65) ch += 26; /* if the char is lower than the lowest uppercase char, add 26 */
            src[i] = (char)ch; /* set the current char in src to the char value of ch */
        } else if (ch >= 97 && ch <= 122) { /* else if it's lowercase */
            ch += key; /* add the key */
            if (ch > 122) ch -= 26; /* if the char is higher than the highest lowercase char, sub 26 */
            if (ch < 97) ch += 26; /* if the char is lower than the lowest lowercase char, add 26 */
            src[i] = (char)ch; /* set the current char in src to the char value of ch */
        } 
        /* an else case is not needed, since we are modifying the original. */
    }
    /* Return a pointer to the char array passed to us */
    return src;
}

char *getPlainText(char *src, int key) {
    /* Since getCipherText adds the key to each char, adding a negative key 
     * is equivalent to subtracting a positive key. Easier than re-implementing.
     */
    return getCipherText(src, -key);
}

Цезарь.ч

char *getCipherText(char *src, int key);
char *getPlainText(char *src, int key);

главная.с

#include <stdio.h> /* for printf(), sscanf(), fgetc() and fgets() */
#include <stdlib.h> /* for malloc() and free() */
#include <string.h> /* for strlen() */
#include "caesar.h"

/* Size of text buffer to read into */
#define BUFS 1024

/* Size of buffer for reading misc. items, i.e. for the get_int() function */
#define TBUFS 128

/* Get char, no new lines */
int getc_nnl() {
    int ch = '\n';

    /* While ch is a newline or carriage return, read another char */
    while (ch == '\n' || ch == '\r')
        ch = fgetc(stdin);

    /* Return the char, promoted to an integer */
    return ch; 
}

/* Get an integer */
int get_int() {
    char *s = (char*)malloc(TBUFS); s[0] = '\0';
    int i = 0;
    /* Read a string, and later parse the int in case there are no ints to read */
    while (strlen(s) <= 1) 
        fgets(s, TBUFS, stdin);

    /* Parse the int. Using sscanf because scanf on stdin leaves the file caret at a unknown position. */
    sscanf(s, "%d", &i);

    /* Return the int - if sscanf found nothing, it's already 0 */
    return i;
}

int main(int argc, char *argv[]) {
    char *text = NULL;
    int key = 0;
    int ch = 0;

    while(1) {  /* Forever loop, until we break; out */

        /* Prompt for an option */
        printf("Encrypt, Decrypt, or Quit? (e/d/q) ");
        ch = getc_nnl(); 

        /* Make sure they gave us a valid option - if not, keep prompting! */
        while (ch != 'e' && ch != 'E' && ch != 'd' && ch != 'D' && ch != 'q' && ch != 'Q') {
            printf("Invalid option. Encrypt, Decrypt, or Quit? (e/d/q) ");
            ch = getc_nnl();
        }

        /* If the user wants to quit... */
        if (ch == 'q' || ch == 'Q') 
            break; /* ...then break out of the loop */

        /* Allocate buffer for text (I set text[0] to a null-terminator due to later strlen() calls) */
        text = (char*)malloc(BUFS); text[0] = '\0';

        /* Get the text to encrypt - If user entered nothing,
         * or fgets() is reading only a newline (from the fgetc calls), keep reading.
         */
        printf("Please enter your text: ");
        while (strlen(text) <= 1)
            fgets(text, BUFS, stdin);

        /* Get the integer key to encrypt/decrypt with. If it's invalid, keep prompting! :) */
        printf("Ok, now what key should I use? (1 - 25) ");
        key = get_int();
        while (key < 1 || key > 25) {
            printf("Invalid key. Please enter a number between 1 and 25: ");
            key = get_int();
        }

        /* Ok, we have our data - now, did they say encrypt or decrypt? */
        if (ch == 'e' || ch == 'E') {
            /* Encrypt, and print the result */
            getCipherText(text, key);
            printf("Ok. Here's your encrypted text: %s\n", text);
        } else if (ch == 'd' || ch == 'D') {
            /* Decrypt, and print the result */
            getPlainText(text, key);
            printf("Ok. Here's your decrypted text: %s\n", text);
        }

        /* Free our malloc, so we don't have a memory overrun */
        free(text);
    }

    return 0;
}


32655
10
задан 8 мая 2011 в 08:05 Источник Поделиться
Комментарии
3 ответа

/* Loop over each char in src */
for (i = 0; i < len; i++) {

Для некоторых программистов, написание работы со строками, как это любят говорить в иностранный акцент. Рассматривайте это:

while (*src)
{
// TODO: do something with *src

src++;
}

Кроме того, вы написали, что вы перебора всех символов в два раза. (функция strlen будет цикл через все символы, чтобы найти длину, и тогда вы будете перебрать еще раз, чтобы проанализировать шифр.) Приведенный выше код перебирает только один раз.

ch = (int)src[i]; /* Convert the char to int to prevent many uneccecary casts */

Я не уверен, что означает этот комментарий, или где путаница лежит. Я бы сказал, что сделать это без скинется, если вы можете. (Похоже, вы можете.)

if (ch >= 65 && ch <= 90) { /* If the char is uppercase */

Ты хардкодить в ASCII? Это немного странно. Вы можете сделать ч >= 'А' и т. д. Еще лучше, isupper из ctype для.сек.

while (strlen(s) <= 1) 
fgets(s, TBUFS, stdin);

Это выглядит очень странно. Прежде всего функция strlen(с) <= 1 следует производить результат, эквивалентный !с[0] || !с[1], за исключением того, что функция strlen будет проходить всю строку, а это плохо. Но в целом, "в то время как длина строки <= 1" подход является немного запутанным... я думаю, чище код вызова помощи fgets сначала, потом наблюдать за результатом.

Обновление, заглянув в код еще раз: кроме того, размеры буферов небольшой и фиксированный размер. На эти размеры вероятно, более разумно, чтобы сделать их стеке массивы вместо вызова функции malloc.

7
ответ дан 9 мая 2011 в 01:05 Источник Поделиться

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

Во-вторых, я думаю, что сегмент проблема в функции немного по-другому. На нижнем уровне, я бы иметь функцию, которая просто принимает один входной символ, и возвращает один кодированный/декодированный символ:

int cipher(int ch, int key) {   
if (islower(ch)) return (ch-'a' + key) % 26 + 'a';
if (isupper(ch)) return (ch-'A' + key) % 26 + 'A';
return ch;
}

Затем, если вы действительно хотите разобраться в строках, как слой на вершине, что, я бы что-то, что знает, как бороться со строками символов:

void encode(char *s, int key) { 
while (*s)
*s = cipher(*s++, key);
}

void decode(char *s, int key) {
while (*s)
*s = cipher(*s++, -key);
}

Затем, в качестве верхнего слоя достаточно, чтобы открыть файлы, и действовать в качестве фильтра:

int main(int argc, char **argv) { 
char buffer[256];
// skipping error checking for now.
int key = atoi(argv[1]);

while (fgets(buffer, 256, stdin))
if (tolower(argv[2][0] == 'd')
puts(decode(buffer));
else
puts(encode(buffer));
return 0;
}

Или, если вы не возражаете, немного хитрости:

typedef int (*func)(int);

func f = tolower(argv[2][0]) == 'd' ?
decode :
encode;

while (fgets(buffer, 256, stdin))
puts(f(buffer));

Кроме того, вы можете игнорировать, подвязав его на всех, и дело только в одиночных символов на протяжении:

int encode(int ch, int key) { 
if (islower(ch)) ch = (ch-'a' + key) % 26 + 'a';
else if (isupper(ch)) ch = (ch-'A' + key) % 26 + 'A';
return ch;
}

int decode(int ch, int key) {
return encode(ch, -key);
}

int main(int argc, char **argv) {
int ch;
int key = atoi(argv[1]);

int (*f)(int) = argv[2][0] == 'd' ?
decode :
encode;

while (EOF != (ch=getchar()))
putchar(f(ch));

return 0;
}

4
ответ дан 10 мая 2011 в 09:05 Источник Поделиться


  • после Танос проверить результат на null

  • getCipherText проверить ГРЦ значение NULL, если функция strlen получить нулевую строку его придавило.

  • функция get_int бесплатно с строку перед возвратом результата

3
ответ дан 8 мая 2011 в 09:05 Источник Поделиться