#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/*
This program finds the N most frequently appearing words in a text
after removing stopwords. It demonstrates clean structure, clear
comments, and efficient use of C dynamic arrays and sorting.
*/
typedef struct {
char *word;
int count;
} WordFreq;
/* ---------------------------------------------------------------
Helper: check punctuation
--------------------------------------------------------------- */
int is_punct(char c) {
return ispunct((unsigned char)c);
}
/* ---------------------------------------------------------------
Tokenize text into words (simple whitespace split)
--------------------------------------------------------------- */
char **tokenize(const char *text, int *count) {
char *copy = strdup(text);
char *token = strtok(copy, " \t\n");
char **words = NULL;
int size = 0;
while (token) {
char *w = strdup(token);
/* Remove punctuation at edges */
while (w[0] && is_punct(w[0]))
memmove(w, w + 1, strlen(w));
while (strlen(w) > 0 && is_punct(w[strlen(w) - 1]))
w[strlen(w) - 1] = '\0';
if (strlen(w) > 0) {
/* Convert to lowercase */
for (char *p = w; *p; ++p)
*p = tolower((unsigned char)*p);
words = realloc(words, sizeof(char*) * (size + 1));
words[size++] = w;
} else {
free(w);
}
token = strtok(NULL, " \t\n");
}
free(copy);
*count = size;
return words;
}
/* ---------------------------------------------------------------
Check if a word is a stopword
--------------------------------------------------------------- */
int is_stopword(const char *word, char **stopwords, int stop_count) {
for (int i = 0; i < stop_count; i++)
if (strcmp(word, stopwords[i]) == 0)
return 1;
return 0;
}
/* ---------------------------------------------------------------
Count word frequencies, skipping stopwords
--------------------------------------------------------------- */
WordFreq *count_words_frequencies(char **words, int word_count,
char **stopwords, int stop_count,
int *freq_count) {
WordFreq *freq = NULL;
int size = 0;
for (int i = 0; i < word_count; i++) {
if (is_stopword(words[i], stopwords, stop_count))
continue;
int found = -1;
for (int j = 0; j < size; j++) {
if (strcmp(freq[j].word, words[i]) == 0) {
found = j;
break;
}
}
if (found >= 0) {
freq[found].count++;
} else {
freq = realloc(freq, sizeof(WordFreq) * (size + 1));
freq[size].word = strdup(words[i]);
freq[size].count = 1;
size++;
}
}
*freq_count = size;
return freq;
}
/* ---------------------------------------------------------------
Sort and extract top N most frequent words
--------------------------------------------------------------- */
int compare_freq(const void *a, const void *b) {
const WordFreq *wa = a;
const WordFreq *wb = b;
if (wa->count != wb->count)
return wb->count - wa->count; /* descending */
return strcmp(wa->word, wb->word); /* alphabetical */
}
WordFreq *top_n(WordFreq *freq, int freq_count, int n) {
qsort(freq, freq_count, sizeof(WordFreq), compare_freq);
if (freq_count > n)
freq_count = n;
WordFreq *top = malloc(sizeof(WordFreq) * freq_count);
for (int i = 0; i < freq_count; i++) {
top[i].word = strdup(freq[i].word);
top[i].count = freq[i].count;
}
return top;
}
/* ---------------------------------------------------------------
Main
--------------------------------------------------------------- */
int main() {
const char *text =
"C is a general-purpose programming language created in 1972 by "
"Dennis Ritchie. C gives programmers direct access to the features "
"of CPU. It has been and continues to be used to implement "
"operating systems (especially kernels) and device "
"drivers. C programming language used on computers ranging from "
"supercomputers to microcontrollers and embedded systems.";
char *stopwords[] = {
"the","is","a","to","how","after","but","this","for","by","in",
"and","can","content","be","you","yes","no","next","about","used",
"access","been","continues"
};
int stop_count = sizeof(stopwords) / sizeof(stopwords[0]);
int word_count = 0;
char **words = tokenize(text, &word_count);
int freq_count = 0;
WordFreq *freq = count_words_frequencies(words, word_count,
stopwords, stop_count,
&freq_count);
int n = 7;
WordFreq *topn = top_n(freq, freq_count, n);
printf("Top %d most frequent non-stopwords:\n", n);
for (int i = 0; i < n && i < freq_count; i++) {
printf("%s : %d\n", topn[i].word, topn[i].count);
}
return 0;
}
/*
run:
Top 7 most frequent non-stopwords:
c : 3
language : 2
programming : 2
systems : 2
1972 : 1
computers : 1
cpu : 1
*/