Если у вас все еще есть проблема, это только потому, что вы переосмысливаете проблему.Всякий раз, когда вы считаете, определяете частоту и т. Д., Вы обычно можете упростить вещи, используя «State-Loop».Цикл состояний - это не что иное, как цикл, в котором вы зацикливаете каждый символ (или любой другой) и обрабатываете любое состояние, в котором находитесь, например:
- Я прочитал какие-нибудь символы?(если нет, обработайте это состояние);
- является ли текущий символ пробелом?(если это так, если для простоты не использовать несколько пробелов, вы достигли конца слова, обработайте это состояние);
- является ли текущий символ непробельным и не гласным?(если так, если моим последним символом был гласный, увеличьте количество слогов);и
- что мне нужно делать независимо от классификации текущего символа?(выведите его, установите last = current и т. д.)
По сути, это все и может быть переведено в один цикл с несколькими тестами для обработки каждого состояния.Вы также можете добавить проверку, чтобы убедиться, что такие слова, как "my"
и "he"
, считаются как один слог, проверяя, равен ли ваш слог нулю, когда вы достигаете конца слова.
Если поставить его полностью, вы могли бы написать базовую реализацию, например:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main (void) {
char c, last = 0; /* current & last char */
const char *vowels = "AEIOUYaeiouy"; /* vowels (plus Yy) */
size_t syllcnt = 0, totalcnt = 0; /* word syllable cnt & total */
while ((c = getchar()) != EOF) { /* read each character */
if (!last) { /* if 1st char (no last) */
putchar (c); /* just output it */
last = c; /* set last */
continue; /* go get next */
}
if (isspace (c)) { /* if space, end of word */
if (!syllcnt) /* if no syll, it's 1 (he, my) */
syllcnt = 1;
printf (" - %zu\n", syllcnt); /* output syll cnt and '\n' */
totalcnt += syllcnt; /* add to total */
syllcnt = 0; /* reset syllcnt to zero */
} /* otherwise */
else if (!strchr (vowels, c)) /* if not vowel */
if (strchr (vowels, last)) /* and last was vowel */
syllcnt++; /* increment syllcnt */
if (!isspace (c)) /* if not space */
putchar (c); /* output it */
last = c; /* set last = c */
}
printf ("\n total syllables: %zu\n", totalcnt);
}
( note: , как упоминалось выше, в этом простом примере реализации не учитывается несколько пробелов между словами - которые вы можете просто добавить какЕще одно необходимое условие, проверив, !isspace (last)
. Можете ли вы выяснить, где должна быть добавлена эта проверка, подсказка: она добавлена к существующей проверке с помощью &&
- вам оставлена точная настройка)
Пример использования / Вывод
$ echo "my dog eats banannas he peels while getting juked" | ./syllablecnt
my - 1
dog - 1
eats - 1
banannas - 3
he - 1
peels - 1
while - 1
getting - 2
juked - 2
total syllables: 13
Если вам нужно прочитать слова из файла, просто перенаправьте файл в качестве ввода в программу на stdin
, например,
./syllablecnt < inputfile
Редактировать - Чтение из файла в динамически распределенный буфер
Следуя комментариям о желании прочитать из файла (или stdin
) в динамически изменяемый буфер и т.Затем, пройдя через буфер для вывода слогов по каждому слову и общего слога, вы можете сделать что-то вроде следующего: просто считывает все символы из файла в буфер, первоначально выделенный с 8 символами, и перераспределяется по мере необходимости (удваивая размер выделения каждыйвремя realloc
необходимо).Это довольно стандартная и достаточно эффективная стратегия роста буфера.Вы можете увеличивать его до любого размера, который вам нравится, но избегайте множества небольших перераспределений кроличьих шариков, поскольку выделение памяти относительно дорого с вычислительной точки зрения.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NCHAR 8 /* initial characters to allocate */
int main (int argc, char **argv) {
char c, last = 0, *buffer; /* current, last & pointer */
const char *vowels = "AEIOUYaeiouy"; /* vowels */
size_t syllcnt = 0, totalcnt = 0, /* word syllable cnt & total */
n = 0, size = NCHAR;
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("fopen-file");
return 1;
}
/* allocate/validate initial NCHAR buffer size */
if (!(buffer = malloc (size))) {
perror ("malloc-buffer");
return 1;
}
while ((c = fgetc(fp)) != EOF) { /* read each character */
buffer[n++] = c; /* store, increment count */
if (n == size) { /* reallocate as required */
void *tmp = realloc (buffer, 2 * size);
if (!tmp) { /* validate realloc */
perror ("realloc-tmp");
break; /* still n good chars in buffer */
}
buffer = tmp; /* assign reallocated block to buffer */
size *= 2; /* update allocated size */
}
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (size_t i = 0; i < n; i++) { /* loop over all characters */
c = buffer[i]; /* set to c to reuse code */
if (!last) { /* if 1st char (no last) */
putchar (c); /* just output it */
last = c; /* set last */
continue; /* go get next */
}
if (isspace(c) && !isspace(last)) { /* if space, end of word */
if (!syllcnt) /* if no syll, it's 1 (he, my) */
syllcnt = 1;
printf (" - %zu\n", syllcnt); /* output syll cnt and '\n' */
totalcnt += syllcnt; /* add to total */
syllcnt = 0; /* reset syllcnt to zero */
} /* otherwise */
else if (!strchr (vowels, c)) /* if not vowel */
if (strchr (vowels, last)) /* and last was vowel */
syllcnt++; /* increment syllcnt */
if (!isspace (c)) /* if not space */
putchar (c); /* output it */
last = c; /* set last = c */
}
free (buffer); /* don't forget to free what you allocate */
printf ("\n total syllables: %zu\n", totalcnt);
}
(вы можете сделать то же самое, используя fgets
или используя POSIX getline
, или выделите все сразу с помощью fseek/ftell
или stat
и затем fread
всего файла в буфер за один вызов - до вас)
Использование памяти / проверка ошибок
В любом написанном вами коде, который динамически распределяет память, у вас есть 2 обязанностей в отношении любого выделенного блока памяти: (1) всегда сохраняйтеуказатель на начальный адрес для блока памяти, поэтому (2) он может быть освобожден , когда он больше не нужен.
Обязательно, чтобы вы использовали памятьпрограмма проверки ошибок, чтобы убедиться, что вы не пытаетесь получить доступ к памяти или писать за пределами / за пределами выделенного блока, пытаться прочитать или основать условный переход на неинициализированном значении и, наконец, подтвердитьЕсли вы освободите всю память, которую вы выделили.
Для Linux valgrind
- нормальный выбор.Для каждой платформы есть похожие проверки памяти.Все они просты в использовании, просто запустите вашу программу через нее.
$ valgrind ./bin/syllablecnt_array dat/syllables.txt
==19517== Memcheck, a memory error detector
==19517== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==19517== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==19517== Command: ./bin/syllablecnt_array dat/syllables.txt
==19517==
my - 1
dog - 1
eats - 1
banannas - 3
he - 1
peels - 1
while - 1
getting - 2
juked - 2
total syllables: 13
==19517==
==19517== HEAP SUMMARY:
==19517== in use at exit: 0 bytes in 0 blocks
==19517== total heap usage: 5 allocs, 5 frees, 672 bytes allocated
==19517==
==19517== All heap blocks were freed -- no leaks are possible
==19517==
==19517== For counts of detected and suppressed errors, rerun with: -v
==19517== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Всегда подтверждайте, что вы освободили всю выделенную память и что ошибок памяти нет.
Посмотрите вещии дайте мне знать, если у вас есть дополнительные вопросы.