Как лучше это сделать? Программа азбуки Морзе

В качестве домашнего задания я написал программу на C, которая должна принимать текст и переводить его в азбуку Морзе с помощью светодиода. Для справки, я заменил предопределенную продолжительность мигания светодиода на: «Это __». Это работает так, как сейчас, и я получу полный кредит, но мой вопрос в том, есть ли лучший способ сделать это? Я знаю, что должно быть, вместо того, чтобы использовать все эти операторы «если». Но я новичок в C. (Единственный недостаток этого кода в том, что он длинный, и вы не можете вводить пробелы.) В настоящее время он работает следующим образом: он берет строку и разбивает ее на отдельные буквы, а затем в «для» цикл проверяет эти отдельные буквы на соответствие азбуке Морзе. Дайте мне знать, что вы думаете.

// MorseCode_Attempt1.cpp : Defines the entry point for the console application.
//

include<stdio.h>
include<conio.h>
include<string.h>


void main() {

    char str[500];

    printf("Enter a string you want in Morse Code with underscores as spaces: ");
    scanf("%s", &str);

    int i;
    int stringLength = strlen(str);

    for (i = 0; i < stringLength; i++) {
        printf("\n[%c]\n", str[i]);


        if (str[i] == 'a') {
            printf("\nIt is an a.\n");
        }

        if (str[i] == 'b') {
            printf("\nIt is an b.\n");
        }

        if (str[i] == 'c') {
            printf("\nIt is an e.\n");
        }

        if (str[i] == 'd') {
            printf("\nIt is an d.\n");
        }

        if (str[i] == 'e') {
            printf("\nIt is an e.\n");
        }

        if (str[i] == 'f') {
            printf("\nIt is an f.\n");
        }

        if (str[i] == 'g') {
            printf("\nIt is an g.\n");
        }

        if (str[i] == 'h') {
            printf("\nIt is an h.\n");
        }

        if (str[i] == 'i') {
            printf("\nIt is an i.\n");
        }

        if (str[i] == 'j') {
            printf("\nIt is an j.\n");
        }

        if (str[i] == 'k') {
            printf("\nIt is an k.\n");
        }

        if (str[i] == 'l') {
            printf("\nIt is an l.\n");
        }

        if (str[i] == 'm') {
            printf("\nIt is an m.\n");
        }

        if (str[i] == 'n') {
            printf("\nIt is an n.\n");
        }

        if (str[i] == 'o') {
            printf("\nIt is an o.\n");
        }

        if (str[i] == 'p') {
            printf("\nIt is an p.\n");
        }

        if (str[i] == 'q') {
            printf("\nIt is an q.\n");
        }

        if (str[i] == 'r') {
            printf("\nIt is an r.\n");
        }

        if (str[i] == 's') {
            printf("\nIt is an s.\n");
        }

        if (str[i] == 't') {
            printf("\nIt is an t.\n");
        }

        if (str[i] == 'u') {
            printf("\nIt is an u.\n");
        }

        if (str[i] == 'v') {
            printf("\nIt is an v.\n");
        }

        if (str[i] == 'w') {
            printf("\nIt is an w.\n");
        }

        if (str[i] == 'x') {
            printf("\nIt is an x.\n");
        }

        if (str[i] == 'y') {
            printf("\nIt is an y.\n");
        }

        if (str[i] == 'z') {
            printf("\nIt is an z.\n");
        }

        if (str[i] == '_') {
            printf("\nIt is a SPACE.\n");
        }

    }

    return 0;

}

person Ibrahim M. Eshera    schedule 12.09.2015    source источник
comment
Вы могли бы уменьшить все, кроме пробела, до printf("It is a(n) '%c'\n", str[i]);, не так ли? Такое количество повторений — верный признак того, что что-то серьезно не так.   -  person Jonathan Leffler    schedule 12.09.2015
comment
@ Джонатан Леффлер, то, что вы указали, примечательно, но OP написал в вопросе: For now I have substituted the pre-determined lengths of a blink from an LED with: "It is a(n) __." Ему действительно нужно указывать уникальные данные во всех разных случаях.   -  person Riddhesh Sanghvi    schedule 12.09.2015
comment
Есть еще лучшие способы сделать это, чем 26-позиционный оператор if или switch. Например, массив можно инициализировать для хранения соответствующих уникальных данных.   -  person Jonathan Leffler    schedule 12.09.2015


Ответы (3)


Когда вы используете много if's и после одного совпадения вам нужно двигаться дальше, используйте if-else-if ladder, так что если найдено слово "b", то не будут проверяться все остальные условия.

Но лучшим решением здесь является switch case.

Попробуйте что-нибудь подобное в файле yourfor-loop.

switch (str[i])
{
 case 'a':
   printf("\nIt is an a.\n");
   break;

 case 'b':
   printf("\nIt is a b.\n");
   break;

  /* etc. etc. etc.*/

 default:
 //default will work when the input to the switch->here str[i] does not match any case.
   printf("\nNot a character or space!");
   break;
}
person Riddhesh Sanghvi    schedule 12.09.2015
comment
Использование оператора switch также дает выигрыш в производительности. В ассемблере он представлен в виде таблицы переходов, поэтому поиск каждого оператора case происходит за постоянное время, а не как функция количества операторов if / else if. - person DIMMSum; 12.09.2015
comment
При обработке всех случаев, кроме пробела, с помощью printf("It is a(n) '%c'\n", str[i]); можно добиться большей ясности. - person Jonathan Leffler; 12.09.2015
comment
@ Джонатан Леффлер, то, что вы указали, примечательно, но OP написал в вопросе: For know I have substituted the pre-determined lengths of a blink from an LED with: "It is an __." Ему действительно нужно указывать уникальные данные во всех разных случаях. - person Riddhesh Sanghvi; 12.09.2015

Попробуй это:

    for (...)
    {
       char c = str[i];
       unsigned Num;

       /* If c is a letter map it to 0..25 */
       Num = (unsigned)(toupper(c)-'A');
       if (Num<26) //This matches only with letters, as Num is unsigned.
       {
          //Each letter is represented by max four symbols 
          static const char MorseCodes[26][5]= 
          {
             "._",   //Morsecode for 'a'
             "_...", //Morsecode for 'b'
          ...
             "__..", //Morsecode for 'z'
          };
          printf("You have entered the letter %c. The morse code is %s\n", Num+'A', MorseCodes[Num]);
       }
       else 
       if (c=='_')
       {
          printf ("Space\n");
       } 
       else 
       {
          printf ("What You Are Doing?\n");
       } 
    }
person Ulli    schedule 12.09.2015
comment
для начала есть только 2 действительных объявления для main() (и одно необязательное объявление. Это: int main( int argc, char *argv[]) и int main( void ) плюс необязательное объявление: int main() Обратите внимание, что ВСЕ они имеют тип возврата 'int', а не void - person user3629249; 13.09.2015
comment
Для вывода на светодиод необходимо учитывать следующее: Если длительность точки принята за одну единицу, то продолжительность тире равна трем единицам. Пробел между компонентами одного символа составляет одну единицу, между символами — три единицы, а между словами — семь единиц. Чтобы указать, что была допущена ошибка, и чтобы получатель удалил последнее слово, отправьте ........ (восемь точек). - person user3629249; 13.09.2015
comment
азбука Морзе содержит глифы длиной до 9 точек и тире. Таким образом, таблица с битовым шаблоном из точек и тире должна иметь ширину 10 (чтобы учесть завершающий байт NUL в каждой строке. - person user3629249; 13.09.2015
comment
помимо алфавита A...Z (без заглавных букв) есть также знаки препинания, прознаки и специальные/иностранные буквы - person user3629249; 13.09.2015

учитывая ваш вопрос, следующий код должен привести вас в правильном направлении.

Обратите внимание, что function: out(), function: delay(), #define ON и #define OFF зависят от вашей среды.

include<stdio.h>
//include<conio.h> -- dont include header files that are not used
include<string.h>

// adjust DELAY_UNIT as necessary
#define DELAY_UNIT (1000)
#define DOT_TIME   (1)
#define DASH_TIME  (3)
#define INTER_WORD_TIME (7)
#define INTER_CHAR_TIME (3)
#define DOT        ('.')
#define DASH       ('-')

// OP needs to define function 'out()', LED, ON, OFF and DELAY_UNIT
// to suit the environment

// prototypes
char *findIndex( struct morseStruct *morse, char ch);
void MorseToLed( char *sequencePtr);
void delay( long unsigned int );

/*
 * If the duration of a dot is taken to be one unit
 * then that of a dash is three units.
 *
 * The space between the components of one character is one unit,
 *
 * between characters is three units and between words seven units.
 *
 * To indicate that a mistake has been made and for the receiver to delete the last word,
 * send ........ (eight dots).
 */

// see <http://morsecode.scphillips.com/morse2.html> for source list
// of morse code char formats

struct morseStruct
{
    char  searchChar;
    char *morseSequence;
};

static const struct morseStruct *alphanumeric[] =
{
    {'A', ",-"   };
    {'B', "-..." };
    {'C', "-.-." };
    ...  // add other alphameric definitions here
    {0, NULL};
};

static const struct morseStruct *punctuation[] =
{
    {'.', ".-.-.-" }; // period
    {',', "--..--" }; // comma
    {':', "---..." }; // colon
    {'?', "..--.." }; // question mark
    {'\'', ".----."}; // apostrophe (note: must escape certain characters)
    {'-', "-....-" }; // hyphen
    {'/', "-..-."  }; // right slash
    {'\"', ".-..-."}; // quotation mark
    {'@', ".--.-." }; // at sign
    {'=', "-...-"  }; // equals sign
    {0, NULL};
};

static const struct morseStruct *prosigns[] =
{
    ... // add prosigns here
    {0, NULL};
};



int main( void )
{

    char str[500];

    printf("Enter a string you want in Morse Code with underscores as spaces: ");
    if( NULL == fgets(str, sizeof( str ), stdin );
    { // then fgets failed
        perror( "fgets for user input string failed");
        exit( EXIT_FAILURE );
    }

    // implied else, fgets successful

    //eliminate trailing newline, if any
    if( char *pNewline = strstr( str, "\n")
    {
        pNewline = '\n';
    }

    size_t stringLength = strlen(str);
    int i;

    for (i = 0; i < stringLength; i++)
    {
        printf("\n[%c]\n", str[i]);


        // handle special cases
        if '_' == str[i] )
        { // then between words
            //out(LED, OFF); // should already be OFF
            delay( INTER_WORD_TIME*DELAY_UNIT );
            continue;
        }

        int sequencePtr;

        if( NULL == (sequencePtr = findIndex( alphaNumeric, str[i] ) ) )
        {// then not alphanumeric value
            if( NULL == (sequencePtr = findIndex( punctuation, str[i] ) ) )
            { // then not punctuation value
                if( NULL == (sequencePtr = findIndex( prosigns, str[i] ) ) )
                { // then not prosign value
                    printf( "char: %0X is not recognized\n", str[i]);
                    continue;
                }
            }
        }

        MorseToLed (sequencePtr);
    } // end for

    return 0;
} // end function: main


char *findIndex( struct morseStruct *morse, char ch)
{
    char *pSequence = NULL;
    int  i = 0;

    while( NULL != morse[i].morseSequence )
    {
        if( ch == morse[i].searchChar )
        { // then found desire morse code sequence
            pSequence = morse[i].morseSequence;
            break;
        }
        i++;
    }
    return( pSequence );
} // end function: findIndex


void MorseToLed( char *sequencePtr)
{
    size_t i = strlen( sequencePtr );

    for( size_t j = 0; j<i; j++)
    {
        if( DOT == sequencePtr[j] )
        {
            out(LED, ON);
            delay( DOT_TIME * DELAY_UNIT );
            out(LED, OFF);
        }
        else if( DASH == sequencePtr[j] )
        {
            out(LED, ON);
            delay( DASH_TIME * DELAY_UNIT );
            out(LED, OFF);
        }
        delay( DELAY_UNIT ); // delay between components of one char
    } // end for

    delay( INTER_CHAR_TIME * DELAY_UNIT ); // delay between characters
} // end function: MorseToLed


void delay( long unsigned int delayUnits )
{
    ?????
} // end function: delay
person user3629249    schedule 13.09.2015