Я бы предложил совершенно другой подход.
Я бы использовал элемент гибкого массива C99 для хранения каждого слова.Кроме того, поскольку я не хочу, чтобы мой код передавался в качестве ответа на домашнее задание, я покажу, как это сделать с помощью широких символов .(Практически во всех ОС, кроме, возможно, Windows, он обрабатывает не-ASCII-символы, такие как Ö и Ø, как буквы, если ваша локаль говорит, что они есть.)
struct word {
struct word *next;
wchar_t data[]; /* Flexible array member */
};
Я бы использовал вспомогательную функцию, которая читает следующее словоиз широкого потока, пропуская любые несловарные символы (которые я предполагаю, что они являются буквенно-цифровыми символами, то есть буквами и цифрами):
struct word *wide_word(FILE *input)
{
struct word *w = NULL, *tempw;
size_t max = 0; /* No characters allocated in w yet */
size_t len = 0; /* No characters in w yet */
wint_t c;
/* NULL input is not allowed. */
if (!input) {
errno = EINVAL;
return NULL;
}
/* Also fail if the stream is already in an error state. */
if (ferror(input)) {
errno = EIO;
return NULL;
}
c = getwc(input);
/* Skip leading non-word characters. */
while (c != WEOF && !iswalnum(c))
c = getwc(input);
/* End of input? */
if (c == WEOF) {
errno = 0;
return NULL;
}
/* Append each wide word character. */
while (c != WEOF && iswalnum(c)) {
/* Need to reallocate? */
if (len >= max) {
/* Since words are usually short, let's allocate
in chunks of 64 wide characters. */
max = (len | 63) + 65;
tempw = realloc(w, sizeof (struct word) + max * sizeof (wchar_t));
if (!tempw) {
/* Out of memory. */
free(w);
errno = ENOMEM;
return NULL;
}
w = tempw;
}
/* Append. */
w->data[len++] = c;
c = getwc(input);
}
/* Although not useful for this particular case,
we normally want to keep the separator intact. */
if (c != WEOF)
ungetwc(c, input);
/* Optimize the memory allocated to the word. */
if (max != len + 1) {
max = len + 1;
tempw = realloc(w, sizeof (struct word) + max * sizeof (wchar_t));
if (!tempw) {
free(w);
errno = ENOMEM;
return NULL;
}
w = tempw;
}
/* Terminate the wide string in w. */
w->data[len] = L'\0';
/* Success! */
return w;
}
Я лично предпочитаю добавлять в список новые узлы, а затем полностью переворачиватьсписок после:
struct word *reverse_list(struct word *oldlist)
{
struct word *newlist = NULL;
struct word *w;
while (oldlist) {
w = oldlist;
oldlist = oldlist->next;
w->next = newlist;
newlist = w;
}
return newlist;
}
С учетом вышесказанного, программа для чтения широких слов из стандартного ввода в основном
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <locale.h>
#include <stdio.h>
#include <wchar.h>
#include <errno.h>
/* Functions listed above */
int main(void)
{
struct word *list, *node;
if (!setlocale(LC_ALL, ""))
fprintf(stderr, "Warning: Your C library does not support your current locale.\n");
if (fwide(stdin, 1) < 1)
fprintf(stderr, "Warning: Your C library does not support wide standard input.\n");
if (fwide(stdout, 1) < 1)
fprintf(stderr, "Warning: Your C library does not support wide standard output.\n");
/* Read words from standard input into reversed list. */
while (1) {
node = wide_word(stdin);
if (!node) {
if (errno) {
fprintf(stderr, "Error reading standard input: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
/* No error, just end of input. */
break;
}
/* Prepend to list. */
node->next = list;
list = node;
}
/* Reverse the list so first word is first in list. */
list = reverse_list(list);
/* Print each word in the list to standard output, in order. */
for (node = list; node != NULL; node = node->next)
wprintf(L"%ls\n", node->data);
/* We could free() each word in 'list' here. */
return EXIT_SUCCESS;
}