Набор символов в формате списка разбить в список чисел и список слов - C (СИ)

Узнай цену своей работы

Формулировка задачи:

Всем добрый день! Мне дали задачу написать программу, в которую вводится набор символов в формате списка. после обработки этого списка должно получиться 2 списка: список чисел и список слов (напр. вводится: qwert123 43yt, на выходе должны получиться: список чисел 123 43, список слов: qwert yt). Я смог реализовать эту программу, но для решения этой задачи я использовал выделение mallocом памяти под новые элементы списка и просто копировал туда элементы. Препод такое решение забраковал. Сказал, что необходимо модифицировать исходный список, т.е. берется элемент из списка и переносится в другой список и никаких дополнительных выделений памяти... Подскажите, как сделать правильно работающую программу? Прикладываю свой вариант решения:
#define _CRT_SECURE_NO_WARNINGS
 
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdbool.h>
 
typedef struct Item
{
    char c;
    struct Item *next;
} Item;
 
/* Ввод строки - списка */
int getList(Item **);
 
/* Вывод строки - списка */
void putList(const char *, Item *);
 
/* Освобождение памяти */
Item *deleteList(Item *);
 
/* Формирование новой строки - списка */
Item *newStringWord(Item *);
Item *newStringNum(Item *);
 
/* удаление пробелов из строки - списка */
Item *delSpace(Item *);
 
/* пропуск слова в строке - списке */
Item *skipWord(Item *);
 
/* удаление слова из строки - списка */
Item *delWord(Item *);
bool isalpha(char);
bool isdigit(char);
/* Функция для ввода строки - списка.
** Функция возвращает указатель на список, в котором размещена введенная строка.
** По условиям задачи, может быть введена пустая строка, тогда
** функция возвращает значение NULL - пустой список.
** Функция должна отслеживать состояние "Конец файла", и это состояние нельзя
** связать со значением указателя NULL - пустая строка.
** Поэтому предлагаемая функция с прототипом int getList(Item **) возвращает
** результат 1, если строка введена, или 0, если обнаружен конец файла,
** а саму строку возвращает через параметр функции.
*/
int getList(Item **pptr)
{
    char buf[21], *str;
    Item head = { '*', NULL };
    Item *last = &head;
    int n, rc = 1;
 
    do
    {
        n = scanf("%20[^\n]", buf);
        if (n < 0)
        {
            deleteList(head.next);
            head.next = NULL;
            rc = 0;
            continue;
        }
        if (n > 0)
        {
            for (str = buf; *str != '\0'; ++str)
            {
                last->next = (Item *)malloc(sizeof(Item));
                last = last->next;
                last->c = *str;
            }
            last->next = NULL;
        }
        else
        {
            scanf("%*c");
        }
    } while (n > 0);
    *pptr = head.next;
    return rc;
}

/* Вывод строки - списка */
void putList(const char *msg, Item *ptr)
{
    printf("%s: "", msg);
    for (; ptr != NULL; ptr = ptr->next)
    {
        printf("%c", ptr->c);
    }
    printf(""\n");
}

/* Освобождение памяти */
Item *deleteList(Item *ptr)
{
    Item *tmp = NULL;
    while (ptr != NULL)
    {
        tmp = ptr;
        ptr = ptr->next;
        free(tmp);
    }
    return ptr;
}
 
bool isalpha(char c) {
    if ((c >= 'a') && (c <= 'z') || (c >= 'A') && (c <= 'Z'))
        return true;
    return false;
}
 
bool isdigit(char c) {
    if ((c >= '0') && (c <= '9'))
        return true;
    return false;
}
 
int main()
{
    Item *ptr = NULL;
    Item *pword = NULL;
    Item *pnum = NULL;
    while (puts("enter string"), getList(&ptr))
    {
        putList("Entered string", ptr);
        pword = newStringWord(ptr);
        putList("Result string 1", pword);
        pnum = newStringNum(ptr);
        putList("Result string 2", pnum);
        ptr = deleteList(ptr);
        pword = deleteList(pword);
        pnum = deleteList(pnum);
    }
    return 0;
}

/* Формирование новой строки - списка */
Item *newStringWord(Item *p)
{
    char bChar;
    char eChar;
    Item head = { '*', NULL };
    Item head2 = { '*', p };
    Item *cur = &head2;
    Item *last = &head, *prev = &head; /* prev - для корректной обработки конца списка */
    int fl = 0;

    /* Используется список с головным элементом; поэтому cur указывает
    ** на элемент списка, предшествующий тому, который будет анализироваться
    */
    while (cur->next)
    {
        /* здесь надо анализировать и cur, так как в результате пропуска
        ** слова cur указывает на элемент списка, следующий за последним символом
        ** слова, а его может и не быть - последний символ слова есть последний
        ** символ списка
        */
 
        cur = cur->next;
        if (isalpha(cur->c))
        {
            last->next = (Item *)malloc(sizeof(Item));
            last = last->next;
            last->c = cur->c;
            last->next = NULL;
            prev = last;
            fl = 1;
        }
        else if (fl)
        {
            last->next = (Item *)malloc(sizeof(Item));
            last = last->next;
            last->c = ' ';
            last->next = NULL;
            fl = 0;
        }
    }
    /* возможно, в конце строки - списка остался лишний пробел */
 
    if (prev->next)
    {
        free(prev->next);
        prev->next = NULL;
    }
 
    return head.next;
}
 
Item *newStringNum(Item *p)
{
    char bChar;
    char eChar;
    Item head = { '*', NULL };
    Item head2 = { '*', p };
    Item *cur = &head2;
    Item *last = &head, *prev = &head; /* prev - для корректной обработки конца списка */
    int fl = 0;
 
    /* Используется список с головным элементом; поэтому cur указывает
    ** на элемент списка, предшествующий тому, который будет анализироваться
    */
    while (cur->next)
    {
        /* здесь надо анализировать и cur, так как в результате пропуска
        ** слова cur указывает на элемент списка, следующий за последним символом
        ** слова, а его может и не быть - последний символ слова есть последний
        ** символ списка
        */
 
        cur = cur->next;
        if (isdigit(cur->c))
        {
            last->next = (Item *)malloc(sizeof(Item));
            last = last->next;
            last->c = cur->c;
            last->next = NULL;
            prev = last;
            fl = 1;
        }
        else
            if (fl)
            {
                last->next = (Item *)malloc(sizeof(Item));
                last = last->next;
                last->c = ' ';
                last->next = NULL;
                fl = 0;
            }
    }
    /* возможно, в конце строки - списка остался лишний пробел */
 
    if (prev->next)
    {
        free(prev->next);
        prev->next = NULL;
    }
 
    return head.next;
}

/* удаление пробелов из строки - списка
** результат - указатель на элемент списка, содержащего
** непробельный символ, или NULL
*/
Item *delSpace(Item *p)
{
    Item *tmp;
    while (p && (p->c == ' ' || p->c == '\t'))
    {
        tmp = p;
        p = p->next;
        free(tmp);
    }
    return p;
}

/* пропуск слова в строке - списке
** результат - указатель в исходном списке на
** послений символ слова
*/
Item *skipWord(Item *p)
{
    while (p->next && p->next->c != ' ' && p->next->c != '\t')
    {
        p = p->next;
    }
    return p;
}

/* удаление слова из строки - списка
** результат - указатель на элемент списка, содержащего
** пробельный символ, или NULL
*/
Item *delWord(Item *p)
{
    Item *tmp;
    while (p && p->c != ' ' && p->c != '\t')
    {
        tmp = p;
        p = p->next;
        free(tmp);
    }
    return p;
}

Решение задачи: «Набор символов в формате списка разбить в список чисел и список слов»

textual
Листинг программы
    Item *item = list; // исходный список
    Item *words=NULL; // начало списка, содержащего буквы
    Item *wordsEnd=NULL; // конец списка, содержащего буквы
    Item *numbers=NULL, *numbersEnd=NULL;
 
    while (item)
    {
        Item *next = item->next;
        if (isdigit(item->c))
        {
            // нужно ещё отдельно учесть случай wordsEnd == NULL
            wordsEnd->next = item;
            wordsEnd = item;
        }
        else if (isalpha(item->c))
        {
            numbersEnd->next = item;
            numbersEnt = item;
        }
 
        item = next;
    }
 
    list = NULL;

Объяснение кода листинга программы

Предполагая, что входной список представлен в виде последовательности чисел и слов, код выполняет следующие действия:

  1. Создает три указателя: item указывает на текущий элемент входного списка, words указывает на начало списка слов (букв), wordsEnd указывает на конец списка слов. Указатель numbers указывает на начало списка чисел, а указатель numbersEnd указывает на конец списка чисел.
  2. В цикле while перебирает элементы входного списка. Для каждого элемента выполняется следующее:
    • Создается новый указатель next, который указывает на следующий элемент в списке.
    • Если текущий элемент является числом (проверка isdigit(item->c)), он добавляется в список слов, начиная с wordsEnd. В этом случае wordsEnd обновляется, чтобы указывать на последний добавленный элемент.
    • Если текущий элемент является буквой (проверка isalpha(item->c)), он добавляется в список чисел, начиная с numbersEnd. В этом случае numbersEnd обновляется, чтобы указывать на последний добавленный элемент.
  3. После завершения цикла, все указатели обнуляются, что означает, что список слов и список чисел теперь являются независимыми списками. Вот список действий в виде нумерованного списка с названиями и значениями переменных:
  4. Item *item = list; - Инициализирует указатель item для первого элемента входного списка.
  5. Item *words=NULL; - Инициализирует указатель words для начала списка слов (букв) с значением NULL.
  6. Item *wordsEnd=NULL; - Инициализирует указатель wordsEnd для конца списка слов (букв) с значением NULL.
  7. Item *numbers=NULL, *numbersEnd=NULL; - Инициализирует указатель numbers для начала списка чисел с значением NULL, и обновляет numbersEnd для указания на конец списка чисел.
  8. while (item) - Начинает цикл, который перебирает элементы входного списка.
  9. Item *next = item->next; - Создает новый указатель next для следующего элемента в списке.
  10. if (isdigit(item->c)) - Если текущий элемент является числом, выполняется следующая операция.
  11. wordsEnd->next = item; - Добавляет текущий элемент в список слов (букв), начиная с wordsEnd.
  12. wordsEnd = item; - Обновляет wordsEnd, чтобы указывать на последний добавленный элемент в списке слов (букв).
  13. else if (isalpha(item->c)) - Если текущий элемент является буквой, выполняется следующая операция.
  14. numbersEnd->next = item; - Добавляет текущий элемент в список чисел, начиная с numbersEnd.
  15. numbersEnt = item; - Обновляет numbersEnt, чтобы указывать на последний добавленный элемент в списке чисел.
  16. item = next; - Переходит к следующему элементу входного списка.
  17. list = NULL; - После завершения цикла, обнуляет указатель list, что означает, что список слов и список чисел теперь являются независимыми списками. Это интерпретация кода на основе предположений о постановке задачи и синтаксисе языка программирования.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

6   голосов , оценка 4.167 из 5
Похожие ответы