Ошибка сегментации в функции C, необходимая для редактирования узла в связанном списке, а также для алфавитного размещения самого списка - PullRequest
0 голосов
/ 29 апреля 2020

Мне было поручено написать функцию, которая должна редактировать узел в связанном списке. Пока у меня есть следующий код, который, кажется, несколько работает, но все еще есть некоторые проблемы:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct flavor {
    char *name;
    int available;
    struct flavor *next;
};

// "Head" node
struct flavor *first = NULL;
// Current node
struct flavor *current = NULL;

void insert(char *name, int available) {
    struct flavor *node = (struct flavor*)malloc(sizeof(struct flavor));

    node->name = name;
    node->available = available;
    node->next = NULL;

    if (first == NULL) {
        first = node;
        return;
    }

    current = first;

    while (current->next != NULL) {
        current = current->next;
    }

    current->next = node;
}

void sort(struct flavor *first) {
    char *i;

    struct flavor *temp1;
    struct flavor *temp2;

    for (temp1 = first; temp1 != NULL; temp1 = temp1->next) {
        for (temp2 = temp1->next; temp2 != NULL; temp2 = temp2->next) {
            if (temp2->name < temp1->name) {
                i = temp1->name;
                temp1->name = temp2->name;
                temp2->name = i;
            }
        }
    }
}

void display() {
    struct flavor *ptr = first;

    printf("Available shake flavors\n");

    while (ptr != NULL) {
        printf("\nName: %s\n", ptr->name);
        printf("Available: %d\n", ptr->available);
        ptr = ptr->next;
    }
}

struct flavor *edit_flavor(struct flavor *first, char *old_name, char *new_name) {

    if (first == NULL) {
        printf("List is empty");
        return;
    }

    current = first;

    while (current->next != NULL) {
        if (current->name == old_name) {
            current->name = new_name;
            printf("\nFlavor %s replaced with %lu\n", old_name, new_name);
            return;
        }

        current = current->next;
    }

    printf("\n%s does not exist in the list\n", old_name);
}

int main(void) {

    char *old = "";
    char *new = "";

    insert("Banana", 1);
    insert("Mango", 0);
    insert("Strawberry", 1);
    insert("Apple", 1);

    sort(first);
    display();
    printf("\nPlease enter old flavor: ");
    scanf("%s", &old);
    printf("Please enter new name: ");
    scanf("%s", &new);
    edit_flavor(first, old, new);
    sort(first);
    display();

    return 0;
}

Всякий раз, когда я пытаюсь использовать программу вообще, я получаю ошибку segmentation fault (core dumped), и я не уверен что я сделал не так?

Кроме того, моя вставка в «Связанный список», кажется, работает нормально, но мне нужно, чтобы список был в алфавитном порядке, а также, когда узел имеет был отредактирован. Я попытался реализовать функцию sort(), но она вообще не работает, и я думаю, что это может быть связано с тем, что я не сравниваю имена правильно (так как они являются строками?). Как я могу исправить функцию сортировки, чтобы правильно расположить алфавитный список?

1 Ответ

0 голосов
/ 29 апреля 2020

Для начала, не используйте глобальные переменные, такие как first и current.

Интерфейс функции несовместим. Например, функция edit_flavo, с одной стороны, сначала принимает головной узел через свой первый параметр. С другой стороны, он использует глобальную переменную current.

Функция sort неверна. Он не меняет значения элемента данных available. Это сравнение в операторе if

if (temp2->name < temp1->name) {

не имеет смысла, поскольку сравниваются адреса строковых литералов вместо сравнения самих указанных строковых литералов с использованием строковой функции C strcmp.

В списке не должны храниться адреса строковых литералов, но должны создаваться копии переданных строк в динамически выделенной памяти.

И правильнее будет менять местами целые узлы в функции сортировки вместо замены элементов данных. из заостренных узлов.

В функции edit_flavor это если оператор

if (current->name == old_name) {

в целом также неверен. Сохранение компилятором одинаковых строковых литералов в виде отдельных символьных массивов или в виде одного массива зависит от параметров компилятора. Поэтому нет необходимости, чтобы, например, условие в таком операторе if

if ( "Hello" == "Hello" )

приводило к истине. Опять же, вам нужно использовать стандартную строковую функцию C strcmp для сравнения строковых литералов.

В Main вы объявили два указателя на строковые литералы.

char *old = "";
char *new = "";

Вы не можете изменить строковые литералы. Любая попытка изменить строковый литерал приводит к неопределенному поведению. Вам необходимо объявить символьные массивы, в которых будут храниться введенные пользователем строки. Итак, еще один список должен хранить глубокие копии строк, а не их адреса.

Эти утверждения

scanf("%s", &old);
scanf("%s", &new);

неверны. Во-первых, выражения аргументов должны иметь тип char * в качестве типа переменных old и new вместо типа char **, который имеют выражения &old и &new. И, во-вторых, такой вызов вызывает неопределенное поведение, потому что функция scanf будет пытаться изменить строковые литералы, на которые указывают указатели.

Так что вам нужно изменить свой список. Начните с удаления глобальной переменной first, и указатель на головной узел создает в локальной переменной переменную, инициализируя ее NULL. Затем измените функцию insert, динамически выделяя память для копии, переданной в строку функции. Перепишите функцию sort, которая будет заменять целые узлы вместо отдельных элементов данных. А для введенных строк используйте символьные массивы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...