Создание списка слов с последующим удалением дубликатов последнего слова в Си
Дана задача:
Описать тип "список слов" на Си. Список реализовать как цепочку динамических объектов, создаваемых стандартными функциями malloc() или calloc(). Написать программу, которая вводит строку, состояющую из непустых слов, разделенных последовательностями пробелов и табуляций, и строит список из этих слов. Слова размещать в памяти как динамические объекты. Далее из списка исключить все слова, совпадающие с последним (самое последнее остается). Список может быть пустым, если в строке не было слов, тогда результат по определению пустой. Преобразованный список слов напечатать в stdout, отделяя слова одним пробелом. В конце списка - перевод строки
Удалось реализовать динамическую строку. Возникли проблемы с разбиением. Примеры использования функции strtok позволяют лишь однократно использовать динамическую строку, а затем к ней невозможно обратиться. Как концептуально выполнить задачу? Как организовать хранение разделенных по пробелам слов? Как затем искать повторяющиеся слова?
Мое незаконченное решение:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*Функция посимвольного ввода динамической строки*/
char *get_string() {
int len = 0; // изначально строка пуста
int capacity = 1; // Нуль-терминатор
char *str = (char*) malloc(sizeof(char)); // динамическая пустая строка
char ch = getchar(); // символ для чтения данных
// посимвольное чтение до перевода строки
while ( ch != '\n') {
str[len++] = ch;
/*Увеличение зарезервированной памяти при превышении*/
if (len >= capacity) {
capacity *= 2; // увеличиваем ёмкость строки в два раза
str = (char*) realloc(str, capacity * sizeof(char));
}
ch = getchar(); // чтение символа из потока
}
return str;
}
int main() {
char *str = get_string(); // считываем динамическую строку
char * tokens;
int len = strlen(str), i=0, j;
char list[len][30];
printf("Введена строка: '%s'\n", str);
tokens = strtok(str," ");
while (tokens != NULL){
for (j=0; j<strlen(tokens); j++)
list[i][j]=tokens[j];
i++;
tokens = strtok(NULL, " ");
}
printf("Введена строка: '%s'\n", list[2]);
return 0;
}
Ответы (1 шт):
- Функций чтения строки в Си навалом, начиная от прямого взаимодействия с консолью, заканчивая intrrupt'ами
- Если ты в программе используешь русские буквы, то переведи программу на wchar_t это избавит тебя от огромного количества геморроя.
- Есть несколько реализаций бесконечного массива в Cи. Во первых это 00 строка "слово\0слово\0слово\0\0" пока не найдёшь пустую строку, во вторых это бесконечный nextPtr то есть некая структура которая оставляет данные и ссылается на следующее слово.
Вот рабочий пример написал на чистом линуксовом C минут за 20-30. Можешь проверить его на www.onlinegdb.com/online_c_compiler
ps: Комментарии принимаются.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// zero terminated char* buffer
#define ztword char*
typedef struct {
ztword word;
void* next;
} InfineMem;
InfineMem* first_simbol = NULL;
char newOrAdd(InfineMem* chunk, ztword word) {
InfineMem* owner;
while (chunk != NULL) {
if (strcmp(chunk->word, word) == 0) {
return 1; // если слово уже есть.
}
owner = chunk;
chunk = chunk->next;
}
owner->next = (InfineMem*) malloc(sizeof(InfineMem));
((InfineMem*) owner->next)->word = (char*) calloc(strlen(word) + 1, sizeof(char));
strcpy(((InfineMem*) owner->next)->word, word);
((InfineMem*) owner->next)->next = NULL;
return 0;
}
void memory_cleaner(InfineMem* chunk) {
while (chunk != NULL) {
InfineMem* next = chunk->next;
if (chunk->word != NULL) {
free(chunk->word);
}
free(chunk);
chunk = next;
}
}
void printWordDatabase(InfineMem* chunk) {
while (chunk != NULL) {
printf("$ %s\n", chunk->word);
chunk = chunk->next;
}
}
int main()
{
printf("Enter word or 'quit' to stop or 'print' to print all words in db\n");
char* input = calloc(1024, sizeof(char));
memset(input, 0, 1024);
while (strcmp(input, "quit") != 0) {
printf("Word? ");
fgets(input, 1024, stdin);
input[strlen(input)-1] = '\0'; // cut trailing '\n'
if (strcmp(input, "print") == 0) {
printWordDatabase(first_simbol);
}
else if (first_simbol == NULL) {
first_simbol = malloc(sizeof(InfineMem));
first_simbol->word = (char*) calloc(strlen(input) + 1, sizeof(char));
strcpy(first_simbol->word, input);
first_simbol->next = NULL;
printf("New: %s\n", input);
}
else if (newOrAdd(first_simbol, input) == 1) {
printf("Error: %s - already exists!\n", input);
}
else {
printf("New: %s\n", input);
}
}
memory_cleaner(first_simbol);
free(input);
return 0;
}