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

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

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

    #include <stdio.h>

int main()
{
    int n,i;
    char word[100][100];
    char tmp;
    int counter[100];

    printf("Enter the number of words ");
    scanf("%d", &n);

    for(i=0; i<n; i++)
    {
        printf("Enter the word ");
        scanf("%s", word[i]);
    }

    for(i='a'; i<'z'; i++)
    {
        counter[i]=0;
    }

    for(i=0; i<n; i++)
    {
        tmp=word[i][0];
        counter[tmp]=counter[tmp]+1;
    }

    for(i='a'; i<'z'; i++)
    {
        printf("%d", counter[i]);
    }

    return 0;
}
#
Источник
  • 0
    Что ж, может у вас первое слово начинается с заглавной буквы. В вашем коде учитываются только строчные буквы!
  • 0
    Нет причин для counter иметь 100 элементов, верно? Может 26 или 2 * 26 .
  • 2
    При обнулении массива counter происходит переполнение буфера. например, значение 'z' (в ASCII) равно 122, тогда как массив может содержать только 100 элементов. Этот цикл обнуления можно пропустить, если вы инициализируете его с помощью int counter[100] = {0}; .
Codelisting
за 0 против

Вы индексируете массивcounter[] со значениями кода символа'a' (97) до'z' (122), но длина массива равна 100. Вы переполняете буфер и наступаете на соседние переменные - в этом случае началоword[0] , и вероятноtmp , но на данный момент он не инициализирован, поэтому на него не влияет.

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

Цикл инициализации не нужен; вы можете обнулить весь массив таким образом:

int counter[100] = {0} ;

Есть и другие проблемы безопасности кода и стиля, но семантические ошибки включают в себя ваши циклы, останавливающие один из'z' . Включать'z' тебе нужно<= 'z' или< 'z'+1 :

for( int i = 'a'; i <= 'z'; i++ )
{
    printf("%d", counter[i]);
}

Размещение более 26 элементовcounter массив не нужен. Лучше вычислить диапазон из значений символов:

int counter['z'-'a' + 1] = {0} ;

Затем вы должны сгенерировать индекс, вычтя'a' от значения кода символа:

for( int i = 0; i < n; i++ )
{
    char index = word[i][0] - 'a' ;
    counter[index]++ ;
}

Чтобы обрабатывать верхний и нижний регистр одинаково, вы можете игнорировать регистр:

char index = tolower(word[i][0]) - 'a' ;

Ваш вывод не будет иметь смысла, если какая-либо буква имеет счетчик> 10. Вам нужно разделить каждое значение, например, пробелом или запятой.

for( int i = 'a'; i <= 'z'; i++ )
{
    printf("%-3d", counter[i]);
}

Вы можете добавить ясности, определив константу для количества символов:

#define NUM_COUNTERS ('z'-'a' + 1)

упрощениеcounter[] объявление и цикл вывода:

int counter[NUM_COUNTERS] = {0} ;

...

for( int i = 0; i < NUM_COUNTERS; i++ )
{
    printf( "%-3d ", counter[i - 'a'] ) ;
}

Для предотвращения перегрузкиwords[] вам следует ограничить значение, еслиn а также предотвратить ввод более 99 символов в слове.

Все вместе:

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

#define MAX_WORDS 100
#define NUM_COUNTERS ('z'-'a' + 1)

int main()
{
    int n = 0 ;
    printf( "Enter the number of words " ) ;
    scanf( "%d", &n ) ;
    if( n > MAX_WORDS )
    {
        n = MAX_WORDS ;
    }

    char word[MAX_WORDS][100] ;
    for( int i = 0; i < n; i++ )
    {
        printf( "Enter the word: " );
        scanf( "%99s", word[i] ) ;
    }

    int counter[NUM_COUNTERS] = {0} ;
    for( int i = 0; i < n; i++ )
    {
        char index = word[i][0] - 'a' ;
        counter[index]++ ;
    }

    for( int i = 0; i < NUM_COUNTERS; i++ )
    {
        printf( "%-3d ", counter[i - 'a'] ) ;
    }

    return 0;
}
за 0 против

Трудно сказать, почему первое слово не учитывается, не увидев ввод, который вы передаете программе, но я вижу здесь 2 проблемы:

  1. Вы обрабатываете значения ASCII каждого символа как индекс. В ASCII "A" имеет значение 65, "Z" - 90, "a" - 97, "z" - 122. Ваш массив счетчиков достигает только 100, поэтому попытка доступа к counter ['z'] приведет к выйти за пределы массива и повредить память в стеке и вызвать неожиданные результаты. Поскольку мы рассматриваем только буквы, а не все символы ASCII, мы должны сделать наш массив размером 26, и мы должны получить к нему доступ, преобразовав каждый символ ASCII в индекс. Это можно сделать путем вычитания 'a' (таким образом, 'a' - 'a' даст индекс 0, 'b' - 'a' даст индекс 1 и т. Д.)

  2. Вы не учитываете прописные буквы. Это другой диапазон значений ASCII от строчных букв, и рекомендуется преобразовать все буквы в нижний регистр перед индексацией в наш массив.

Вот версия кода с этими двумя изменениями:

int main()
{
    int n,i;
    char word[100][100];
    char tmp;
    const int numLetters = 'z' - 'a' + 1;
    int counter[numLetters];

    printf("Enter the number of words ");
    scanf("%d", &n);

    for(i=0; i<n; i++)
    {
        printf("Enter the word ");
        scanf("%s", word[i]);
    }

    for(i=0; i<numLetters; i++)
    {
        counter[i]=0;
    }

    for(i=0; i<n; i++)
    {
        tmp=word[i][0];
        //convert the letter to lowercase
        tmp=tolower(tmp);
        
        //subtract tmp-'a' to get the array index
        counter[tmp-'a']++;
    }

    for(i=0; i<numLetters; i++)
    {
        printf("%d", counter[i]);
    }

    return 0;
}
Codelisting
Популярные категории
На заметку программисту