Ваша функция обрабатывает токены не по порядку.Вы пропускаете первую token
, полностью перезаписывая указатель token
, прежде чем он будет использован с:
char* token = strtok(buffer, " \n");
while (token != NULL){
token = strtok(NULL, " \n");
Следующая следующая строка является лишней, если ваш разделитель равен " \n"
.'\n'
, который вы пытаетесь перезаписать с помощью следующего кода, никогда не являясь частью token
:
buffer[strlen(buffer)-1]='\0';
Вы используете '.'
, чтобы отметить конец ввода, поэтому вам не нужнообработать последнюю строку.Чтобы избежать этой проблемы, вы разрываете вложенный цикл с помощью простого оператора goto
, например:
while (fgets (buffer, MAXC, stdin)) {
...
while (token != NULL) {
if (!strcmp (token, ".")) /* compare != '.' */
goto done;
...
}
done:;
return line_count;
}
Предполагая, что entry_count
- это количество элементов в entries
, тогда ваш +1
заставляет васчитать за пределами entries
, что может привести к SegFault.Хотя невозможно проверить, предоставив полный код, который отсутствует в вашем вопросе, похоже, что вы намеревались:
while (i < entry_count) { /* +1 causeses UB */
Ваш звонок на token = strtok(NULL, " \n");
для получения следующего токена должен быть последним утверждением в вашем вопросе.цикл, а не первый, иначе вы пропустили токен.
Если сложить его целиком, похоже, вам нужно что-то похожее на:
#define MAXC 128 /* max number of characters per word/line */
...
int process_stream (WordCountEntry entries[], int entry_count)
{
short line_count = 0;
char buffer[MAXC];
const char *delim = " \n"; /* set delim once */
while (fgets (buffer, MAXC, stdin)) {
char *token = strtok(buffer, delim);
while (token != NULL) {
if (!strcmp (token, ".")) /* compare != '.' */
goto done;
int i = 0;
while (i < entry_count) { /* +1 causeses UB */
if (!strcmp(entries[i].word, token))
entries[i].counter++;
i++;
}
line_count++;
token = strtok(NULL, delim); /* now get next token */
}
}
done:;
return line_count;
}
Short Example
В соответствии с вашими комментариями вы хотели иметь возможность обрабатывать отдельные слова или несколько слов в каждой строке.Функция выше делает это, но у вас могут быть другие проблемы в коде, который вы не опубликовали.Чтобы проверить вышеописанную функцию, была написана короткая реализация.До тех пор, пока ваш код обеспечивает аналогичный ввод, приведенная выше функция будет удовлетворять ваши потребности.Был использован короткий пример:
#include <stdio.h>
#include <string.h>
#define NENT 16 /* max number of entries (no. elements in array) */
#define MAXC 128 /* max number of characters per word / line */
typedef struct {
char word[MAXC];
int counter;
} WordCountEntry;
int process_stream (WordCountEntry entries[], int entry_count)
{
short line_count = 0;
char buffer[MAXC];
const char *delim = " \n"; /* set delim once */
while (fgets (buffer, MAXC, stdin)) {
char *token = strtok(buffer, delim);
while (token != NULL) {
if (!strcmp (token, ".")) /* compare != '.' */
goto done;
int i = 0;
while (i < entry_count) { /* +1 causeses UB */
if (!strcmp(entries[i].word, token))
entries[i].counter++;
i++;
}
line_count++;
token = strtok(NULL, delim); /* now get next token */
}
}
done:;
return line_count;
}
int main (int argc, char **argv) {
WordCountEntry wce[NENT] = { { .word = "" } };
int n = 0;
if (argc < 2) {
fputs ("error: insufficient arguments.\n", stderr);
return 1;
}
for (int i = 1; i < (argc < NENT ? argc : NENT); i++) {
for (int j = 0; j < i; j++) {
if (!strcmp (wce[j].word, argv[i]))
goto next;
}
strcpy (wce[i-1].word, argv[i]);
n++;
next:;
}
puts ("Looking for words:");
if (!process_stream (wce, n))
fputs ("(user canceled input)\n", stderr);
puts ("\nResult:");
for (int i = 0; i < n; i++)
printf ("%s: %d\n", wce[i].word, wce[i].counter);
}
Пример использования / вывода
$ ./bin/wordcountentry cat nap dog
Looking for words:
cat
cat
nap
.
Result:
cat: 2
nap: 1
dog: 0
или с несколькими словами в строке:
$ ./bin/wordcountentry cat nap dog
Looking for words:
cat dog dog
cat dog
nap .
Result:
cat: 2
nap: 1
dog: 3
Могут быть другие проблемы в вашем коде, и невозможно быть уверенным, что это исправит все проблемы из-за отсутствия Минимального, Полного и Проверяемого примера (MCVE) , но с учетом того, что у вас былоэто должно решить проблемы, которые можно идентифицировать, хотя могут быть и другие.
Дайте мне знать, если у вас есть дополнительные вопросы.