Получение случайного приращения при попытке подсчитать количество заглавных букв в C - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь найти номер строчных и прописных букв на входе.

вот мой код:

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

int main()
{
    char cAFirst[25];
    int k = 0,uc =0 ,lc =0 ;

    fgets(cAFirst,25,stdin);
    // printf("out: %d \n",k);

    for (size_t i = 0; i < 25; i++) {
      k = (int)cAFirst[i];
      if ((k <= 90) && (k >= 65)) {
        uc++;
      }
      if ((k >= 97) && (k <= 122)) {
        lc++;
      }
    }

    printf("Uppercase Letters=%i \nLowercase Letters=%i \n",uc,lc );
    return 0;
}

нижний регистр (lc) в порядке, но значение uc увеличивается случайным образом.

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

Ответы [ 3 ]

0 голосов
/ 14 января 2019

Вместо этого всегда повторяйте 25 раз, повторяйте до тех пор, пока не будет обнаружен конец ввода.

// for (size_t i = 0; i < 25; i++) {
for (size_t i = 0; cAFirst[i]; i++) {  // detect null character.
0 голосов
/ 14 января 2019

Сначала вы должны использовать способ итерации вашей строки только один раз, возможно, цикл while, и попытаться прочитать не только то, что вам нужно, но и то, что может быть, что не должно учитываться. Что произойдет, если есть \t или \n Нужно ли вам их тоже считать?

Вот подход, который может помочь вам понять, что:

#include <stdio.h>

int main( void )
{
    char string[] = "AbcDEfgHiJKlmnOPqrstUVWxyZ\n§$%$§";
    int uc, lc, i, others;
    uc = lc = i = others = 0;

    while ( string[i] )
    {
        if ( string[i] >= 'A' && string[i] <= 'Z'  )
        {
            uc++;
        }else if ( string[i] >= 'a' && string[i] <= 'z' ){
            lc++;
        }else{
            others++;
        }
        i++;
    }

    if ( i == ( lc + uc + others ) )
    {
        printf( "OK\n\n" );
        printf("Uppercase Letters = %i \nLowercase Letters = %i \nOthers = %d \n", uc, lc, others );
        printf("Total = %d\n", i );
    }else
    {
        printf("Something went Wrong.\n\n");
    }
}

Ваши операторы if/else могут быть легко заменены функциями isupper( string[i] ) и islower( string[i] ), которые находятся в ctype.h

if ( isupper( string[i] ) )
{
    uc++;
}else if ( islower( string[i] ) )
{
    lc++;
}else{
    others++;
}
0 голосов
/ 14 января 2019

Учитывая этот фрагмент из опубликованного кода ОП:

char cAFirst[25];          // <- Uninitialized, the contents are indeterminated
// ...
fgets(cAFirst,25,stdin);   // <- We don't know if it succeeded or not
// ...
for (size_t i = 0; i < 25; i++) { 
    // ...         ^^^^^^
}

Копирует до 24 символов из stdin в массив (включая символ новой строки, если присутствует), также добавляя нулевой терминатор (если не произошла ошибка потока), но когда цикл выполняется, он перебирает все 25 символов массива, даже если введенная строка короче, с учетом символов с неопределенным значением.

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

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

#include <stdio.h>

// I'd use a bigger value, like 256, but OP's use case is not specified.
enum {
    BUF_SIZE = 25   
};

int main(void)
{
    // All the elements of the array are set to zero, not only the first.
    char buf[BUF_SIZE] = {'\0'};
    // ...

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

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

    if ( fgets(buf, BUF_SIZE, stdin) == NULL ) {
        if (feof(stdin)) {
            fprintf(stderr, "Abnormal end of input.\n");
            // The contents of the array are not altered
        } 
        if (ferror(stdin)) {
            fprintf(stderr, "A stream error occurred.\n");
            // The contents of the array are indeterminated, maybe not even null-terminated
        }
        exit(EXIT_FAILURE);
    }

Ключевым моментом является то, чтобы убедиться, что после этого вызова массив завершается нулем. Даже чека, подобного следующему, может быть достаточно:

    if ( fgets(buf, BUF_SIZE, stdin) == NULL ) {
        fprintf(stderr, "An error occurred while reading from stdin.\n");
        buf[0] = '\0';
        // Continues the program despite the error, but with a valid (empty) string
    }

Стоит помнить, что любые другие символы, кроме прочитанных, остаются во входном потоке.

Теперь, когда у нас есть действительный массив с нулевым символом в конце, мы можем пройти по нему:

    int uc = 0, lc = 0;
    for (size_t i = 0; buf[i] != '\0'; i++) {
    // which can also be written as 'for (size_t i = 0; buf[i]; i++) {'
    // It's also more readable without magic numbers:
        if ( 'A' <= buf[i]  &&  buf[i] <= 'Z' ) {  
            uc++;
        }
        else if ( 'a' <= buf[i]  &&  buf[i] <= 'z' ) {
            lc++;
        }
    }
    printf("Uppercase Letters = %i\nLowercase Letters = %i\n", uc, lc);

    return EXIT_SUCCESS;
}

Предыдущий фрагмент может быть обобщен из кодов ASCII с использованием таких функций, как isupper и islower, определенных в заголовке <ctype.h>. Кроме того, фактическая длина строки может использоваться для ограничения цикла for:

    // Length of the maximum initial segment of the array, that consists of
    // only the characters not equal to a newline or null character
    size_t length = strcspn(buf, "\n");

    int uc = 0, lc = 0;
    for (size_t i = 0; i < length; i++) {
        unsigned char k = buf[i];
        if ( isupper(k) ) {
            uc++;
        }
        else if ( islower(k) ) {
            lc++;
        }
    }
    // ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...