Подсчитайте количество гласных в ряду строк в C - PullRequest
0 голосов
/ 23 апреля 2020

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

Вот код:

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

int vowels(char str[]);

int main(){
    int n, i, x;

    printf("How many strings do you want to insert?");
    scanf("%d", &n);

    printf("How many characters per string?");
    scanf("%d", &x);
    char str[x];

    if(x < 10){
        for(i = 0; i < n; i++){
            printf("Insert a string:");
            scanf("%s", str);

            if(strlen(str) == x){
                vowels(str);
            }
            else{
                printf("Error\n");
            }
        }
    }
    else{
        printf("Error: the number of characters must be < 10");
    }

    return 0;
}

int vowels(char str[]){
    int i, j;

    while(str[i] != '\0'){
        if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' || 
           str[i] == 'E' || str[i] == 'i' || str[i] == 'I' || 
           str[i] == 'o' || str[i] == 'O' || str[i] == 'u' || 
           str[i] == 'U'){
            j++; }
    i++;
    }

    printf("Number of vowels in the string:%d\n", j); 

return 0;
}

Ответы [ 3 ]

1 голос
/ 23 апреля 2020

Проблемы в функции vowels вызваны неинициализированными переменными. Ни i, ни j не имеют начального значения. Хороший компилятор выдаст предупреждение об этом. Если вы компилируете с помощью g cc или clang, обязательно компилируйте с -Wall -Wextra. Затем прочитайте предупреждения и исправьте все предупреждений.

Переменная i может быть объявлена ​​и инициализирована с помощью for l oop, как показано ниже. Переменная j должна иметь более описательное имя, например count, и инициализироваться перед l oop. Вы также можете захотеть вернуть count из функции vowels и разрешить main выполнить печать. Таким образом, вы можете повторно использовать функцию vowels в другой программе, которая должна считать гласные, но не хочет печатать счет.

int vowels(char str[]){
    int count = 0;

    for (int i=0; str[i] != '\0'; i++){
        if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' || 
           str[i] == 'E' || str[i] == 'i' || str[i] == 'I' || 
           str[i] == 'o' || str[i] == 'O' || str[i] == 'u' || 
           str[i] == 'U'){
             count++; 
        }
    }

    return count;
}

Другая проблема в программе заключается в том, что str массив слишком мал. Строка C использует нулевой байт (известный как терминатор NUL), чтобы отметить конец строки. Так, например, если strlen строки равно 5, то массив, содержащий строку, должен быть не менее 6 байтов, 5 для строки плюс один для NUL.

В вашей программе, Вы ограничиваете длину строки числом меньше 10, так что вы можете просто объявить массив str с фиксированным размером, например, char str[16], и он всегда будет достаточно большим. OTOH, scanf не ограничивает количество символов, записанных в строку, если вы не укажете это. Приведенный ниже код показывает, как ограничить количество символов, которые scanf записывает в строку.

int main(){
    int n, x;

    printf("How many strings do you want to insert?");
    scanf("%d", &n);

    printf("How many characters per string?");
    scanf("%d", &x);
    char str[16];

    if(x < 10){
        for(int i = 0; i < n; i++){
            printf("Insert a string:");
            if (scanf("%15s", str) != 1) {
                printf("That wasn't a valid input\n");
                break;
            }
            else if(strlen(str) == x){
                int count = vowels(str);
                printf("Number of vowels in the string:%d\n", count); 
            }
            else{
                printf("Error\n");
                break;
            }
        }
    }
    else{
        printf("Error: the number of characters must be < 10");
    }

    return 0;
}
1 голос
/ 23 апреля 2020

Ваш код содержит две ошибки:

  1. i и j индексы функции vowels() не инициализируются, поэтому они содержат мусор и приведут к непредсказуемому поведению ваших циклов. Это потому, что локальные переменные, в отличие от глобальных переменных, по умолчанию не инициализируются равными 0.

Используйте вместо

int i=0, j=0;
Буфер char str[x]; не сможет содержать строку с символами x. Фактически, пространство, требуемое символом конца строки '\0'.

Так должно быть

char str[x+1];

С этими изменениями ваш код будет работать.

Но ...

... но этого недостаточно. Фактически, когда вы получаете входную строку, вы не выполняете никакой проверки количества полученных символов:

scanf("%s", str);

Вставляя очень длинную строку, вы go выходите за пределы далеко за пределами строки str, вызывая неопределенное поведение и, вероятно, программу cra sh.

Как это исправить? Поскольку ваша входная строка может иметь максимум длина 9, просто определите массив фиксированной длины :

char str[11];

Почему размер 11? Прежде всего ваш массив должен содержать максимум 9 символов и терминатор. Таким образом, 10. Но он также должен содержать дополнительный символ, чтобы входные данные были длиннее 9 символов.

После этого просто получите входную строку с

scanf("%10s", str);

Таким образом все входные строки le git могут быть сохранены (от размера 1 до размера 9). Все строки длиной 10 или более символов будут усечены до строки длиной в десять символов, и ваша проверка длины завершится неудачно, как и ожидалось.

Обратите внимание, что в случае длинной строки все символы, превышающие первые 10, останутся непрочитанными в stdin буфер. Так что в случае ошибки вам нужен механизм для потребления этих символов, в противном случае вы найдете их на следующем scanf. Я написал этот трюк:

while( fgets( str, 10, stdin ) != NULL )
{
    if( strlen(str) < 10 )
        break;
}

Полученный код со всеми описанными мною изменениями следующий:

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

int vowels(char str[]);

int main(){
    int n, i, x;

    printf("How many strings do you want to insert?");
    scanf("%d", &n);

    printf("How many characters per string?");
    scanf("%d", &x);

    if(x < 10){
        char str[11];
        for(i = 0; i < n; i++){
            printf("Insert a string:");
            scanf("%10s", str);

            if(strlen(str) == x){
                vowels(str);
            }
            else{
                printf("Error\n");
                while( fgets( str, 10, stdin ) != NULL )
                    if( strlen(str) < 10 )
                        break;
            }
        }
    }
    else{
        printf("Error: the number of characters must be < 10");
    }

    return 0;
}

int vowels(char str[]){
    int i=0, j=0;

    while(str[i] != '\0')
    {
        if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' || 
           str[i] == 'E' || str[i] == 'i' || str[i] == 'I' || 
           str[i] == 'o' || str[i] == 'O' || str[i] == 'u' || 
           str[i] == 'U')
        {
            j++;
        }
    i++;
    }

    printf("Number of vowels in the string:%d\n", j); 

    return 0;
}
1 голос
/ 23 апреля 2020

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

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

int vowels(char str[]);

int main(){
  int n, i, x;

  printf("How many strings do you want to insert?");
  scanf("%d", &n);  // Consider a more descriptive variable name than 'n'

  printf("How many characters per string?");
  scanf("%d", &x);  // Consider a more descriptive name here too.
  char str[x];  // Note, a string needs 1 extra character for the NUL character.

  if(x < 10){  // 10 is a very magic number.  Consider making a constant.  
    for(i = 0; i < n; i++){
      printf("Insert a string:");
      scanf("%s", str);

      if(strlen(str) == x){
        vowels(str);
      }
      else{
        printf("Error\n"); // Consider breaking or returning here if error...
      }
    }
  }
  else{
    printf("Error: the number of characters must be < 10");
  }

  return 0;
}

int vowels(char str[]){  // Do you need a return value?  What does it represent?
  int i, j;

  while(str[i] != '\0'){  // i and j are not initialized (to 0).  Turning on compiler warnings would catch this.  
//  a for() loop may make more sense
    if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' || 
       str[i] == 'E' || str[i] == 'i' || str[i] == 'I' || 
       str[i] == 'o' || str[i] == 'O' || str[i] == 'u' || 
       str[i] == 'U'){
      j++; }
    i++;
  }

  printf("Number of vowels in the string:%d\n", j); 

  return 0;  // Again, maybe this function returns void if we don't need a return.
}
...