Как удалить элемент из структурного массива в C ++? - PullRequest
0 голосов
/ 02 мая 2010

У меня есть следующая структура массива (связанный список):

    struct str_pair   
     {  
       char ip  [50] ;  
       char uri [50] ;  
       str_pair *next ;  
     } ;

str_pair *item;

Я знаю, чтобы создать новый предмет, мне нужно использовать

item = new str_pair;

Однако мне нужно иметь возможность циклически проходить по массиву и удалять определенный элемент. У меня есть часть зацикливания. Но как мне удалить элемент из массива структур?

Ответы [ 5 ]

5 голосов
/ 02 мая 2010

То, что вы показали, это не массив struct, а связанный список struct, содержащий массивы (типа char).


Массив из struct будет выглядеть следующим образом:

str_pair array_of_structs[10];
    // or:
str_pair* dynamically_allocated_array_of_structs = new str_pair[10];

Если у вас действительно что-то подобное, вам не нужно delete выделять отдельные элементы из массива. Допустим, вы инициализировали свой массив следующим образом:

str_pair* array_of_structs = new str_pair[10];

Затем вы удаляете весь массив (включая все его элементы), используя:

delete[] array_of_structs;

Опять же, вы не можете delete отдельные элементы в массиве, выделенном с new[]; Вы выполняете delete[] для всего массива.


Если, с другой стороны, вы намеревались сказать « связанный список struct», то вы обычно удаляете элемент, аналогично следующему:

str_pair* previous_item = ...;
str_pair* item_to_delete = previous_item->next;

if (item_to_delete != 0)
{
    previous_item->next = item_to_delete->next;  // make the list "skip" one item
    delete item_to_delete;                       // and delete the skipped item
}

Или по-английски: найдите элемент ( A ), предшествующий элементу, который вы хотите удалить ( B ), затем настройте A 's' следующий «указатель», так что B будет пропущен в списке, затем удалите B .

Вы должны быть осторожны с особыми случаями , т. Е. Когда элемент, который будет удален из списка, является первым или последним. Приведенного выше кода недостаточно, если вы хотите удалить первый элемент в списке, потому что не будет previous_item. В этом случае вам нужно изменить указатель на первый элемент списка на второй элемент.


Ваш код:

void deleteitem(char *uri)
{
    str_pair *itemtodelete;
    curr = head;

    while (curr->next != NULL) {
    if ((strcmp(curr->uri, uri)) == 0) {
        itemtodelete = curr;
        curr = itemtodelete->next;
        delete itemtodelete;

        curr = head;
        return;
    }

    curr = curr->next;
    }
}

Некоторые вещи здесь не так:

  • Если head равно нулю, проверка curr->next != NULL вызовет ошибку сегмента. (Вы никогда не должны разыменовывать нулевой указатель!)

  • Ваш код для удаления элемента из списка совершенно неверный. Хуже всего то, что вы удаляете узел без изменения следующего указателя предыдущего элемента. Таким образом, предыдущий элемент будет ссылаться на элемент, которого больше нет.

  • Подробно: curr = head; перед оператором return вообще ничего не делает.

Предлагаемый код:

Сделайте это в два шага: одна функция, чтобы найти узел, который будет удален через прикрепленный uri, и одна функция, чтобы удалить узел. Вы можете отделить его даже лучше, чем приведенный ниже код, но это должно стать отправной точкой:

str_pair* finditemwithuri(char* uri)
{
    str_pair* current = head;
    while (current)
    {
        if (strcmp(current->uri, uri) == 0) return current;
        current = current->next;
    }
    return 0;
}

void deleteitem(char* uri)
{
    // find linked list node with that uri; abort if uri not in list
    str_pair* itemtodelete = finditemwithuri(uri);
    if (!itemtodelete) return;

    // special case: node to be deleted is the list's head
    if (itemtodelete == head)
    {
        head = itemtodelete->next;
        delete itemtodelete;
        return;
    }

    // else, iterate over list nodes
    // up to the one preceding the node to be deleted
    str_pair* current = head;
    while (current)
    {
        if (itemtodelete == current->next)
        {
            current->next = itemtodelete->next;
            delete itemtodelete;
            return;
        }
        current = current->next;
    }
}
1 голос
/ 02 мая 2010

Просто используйте std :: list. Нет смысла писать такую ​​конструкцию вручную.

http://msdn.microsoft.com/en-us/library/802d66bt(VS.80).aspx

std :: список предложений удалить.

0 голосов
/ 02 мая 2010

Возможно, это не по теме, но почему вы не используете библиотеку std::list?

0 голосов
/ 02 мая 2010

Как уже отмечали другие, это связанный список, а не массив. Чтобы ответить на ваш вопрос по связанным спискам:

Чтобы вставить элемент:

str_pair* p = // iterate over the linked list to your insertion point
str_pair* item = new str_pair;
item->next = p->next;
p->next = item;

Вставляет новый str_pair после p.

Чтобы удалить предмет:

str_pair* p = // iterate to just before your deletion point
str_pair* item = p->next;
p->next = p->next->next;
delete item;

Это удалит элемент после p

Чтобы сделать это с вашим кодом:

void deleteitem(char *uri)
{
    str_pair *previous = NULL;
    curr = head;

    while (curr != NULL) {
        if ((strcmp(curr->uri, uri)) == 0) {

            // modify the previous element to skip over our deleted one
            if (previous)
                previous->next = curr->next;
            else
                head = curr->next;

            // safely delete the element, now that no one points to it
            delete curr;

            curr = head;
            return;
        }

        // always remember our previous element, so we can fix its 'next' pointer
        previous = curr;
        curr = curr->next;
    }
}

Вам также нужен лучший метод добавления:

void additem(char *uri, char *ip)
{
    curr = head;

    // traverse the list until we're at the last item
    while (curr->next != NULL) {
        curr = curr->next;
    }

    // attach a new element to the list
    curr->next = new str_pair;

    // go to that new element
    curr = curr->next;

    // set the values of the new element
    strcpy(curr->ip, ip);
    strcpy(curr->uri, uri);
    curr->next = NULL;

    curr = head;

}
0 голосов
/ 02 мая 2010

Вы можете удалить его, используя обычное ключевое слово delete, но это не сместит всех остальных членов массива. Если вы хотите такого рода поведение, посмотрите на std :: vector или что-то в этом роде.

...