Можете ли вы изменить адрес памяти типа C без указателя? - PullRequest
0 голосов
/ 29 октября 2018

Я реализовал некоторые структуры данных C, чтобы полностью понять их.

Это мое определение списка связанных строк:

typedef struct str_linked_list {

   const char*                 data;
   struct str_linked_list*     next;

} str_linked_list;

И это реализация функции, которая удаляет n-й элемент списка:

void str_remove_at(str_linked_list* list, int index) {
    // Invalid index case
    if (index < 0) {

        fprintf(stderr, "Error, array index < 0\n");
        return;

    } 

    str_linked_list* to_delete; // Always gonna need this
    // Delete head case
    if ( index == 0 ) {

        to_delete = list;
        // If this node is not the last one save the reference to the remaining ones
        if ( to_delete->next != NULL )
            list = list->next;

        //free(to_delete);
        return;

    }
    // General case
    int i = 0;

    str_linked_list* buf = list;

    for (i = 0; i != index-1; i++) {

        if (buf->next != NULL){

            buf = buf->next;

        } else {

            fprintf(stderr, "The list is not that long, aborting operation");
            return;

        }

    }

    to_delete = buf->next;

    if ( to_delete->next != NULL )
        buf->next = to_delete->next;

    free(to_delete);

}

Пока это работает хорошо, но я считаю, что, как я это называю, невозможно удалить голову, и поэтому комментируется свободный (голова). Я проверил этот код, используя следующий код:

#include "LinkedList.h"

int main() {

    str_linked_list l;
    l.data = "Hello, World";
    l.next = NULL;

    str_remove_at(&l, 1); 


    str_print(&l);

    printf("\n\n");

    str_remove_at(&l, 0);
    str_print(&l);

    return 0;
}

Я вроде как выяснил, что отсутствие инициализации списка в качестве указателя затрудняет изменение адреса памяти, в котором хранится эта переменная. Должен ли я перекодировать библиотеку, чтобы инициализировать списки в качестве указателя или Есть ли способ, которым я мог бы назначить позицию переменной памяти в другой адрес?

Подводя итог, могу ли я изменить значение "i" следующим образом?

#include "stdlib.h"

void change_value(int* i) {
   int* new_alloc = malloc(sizeof(int));
   *new_alloc = 1;
    i = new_alloc;
}

int main() {
    int i = 0;
    change_value(&i);
    return 0;
}

1 Ответ

0 голосов
/ 29 октября 2018

У вас есть несколько альтернатив для решения случая удаления заголовка списка:

A) Передать список как **list, что позволит вам назначить голову из функции, то есть вызвать как str_remove_at(&list, i) и использовать *list вместо list внутри функции.

B) Возвращает начало списка из функции, и в этом случае вызывающая сторона должна сделать list = str_remove_at(list, i).

C) Требуется, чтобы в вашем списке был элемент "sentinel" в заголовке, который никогда не удаляется, и фактический список начинается с head->next. Это «тратит» один узел списка, но может упростить и другие операции, когда фактический первый элемент больше не является особым случаем. (Преимущества этого увеличиваются, если у вас есть двусвязный список.)

D) Вместо того, чтобы передавать указатель на узел в списке, используйте отдельные str_list_node и str_linked_list, где str_list_node будет вашим текущим struct с data и next, и str_linked_list с str_list_node *head. Затем, когда вы передаете str_linked_list *list, вы можете изменить list->head без необходимости изменять list. (Это решение может быть расширено для получения других преимуществ, таких как возможность хранить str_list_node *tail для добавления O (1).)

...