LINUX.ORG.RU

[C] Не могу понять где ошибка

 


0

0

Друг пол часа назад обратился ко мне за помощью:

элементы списка освобождаются в цикле:
for(p=head; p!=NULL; p=q){
  q=p->next;
  free(p);
}
почему это неправильно?

Керниган, Ритчи 2-е издание, стр.179:
ошибка - обращение по указателю после его освобождения, 
но я ее не вижу
Т.е. это пример неправильного кода из книжки. Но я ошибки тоже не вижу. То ли я невероятно торможу, то ли в книжке опечатка. Прошу помощи.

Deleted

Ассемблер посмотри - вдруг оптимизатор решил поменять местами строчки тела. Да и в valgrind могут быть ошибки :)

tailgunner ★★★★★
()

>Нельзя также использовать те области памяти, которые уже освобождены. Следующий пример демонстрирует
> типичную ошибку в цикле, освобождающем элементы списка.

>

> for (p = head; p != NULL; p = p->next) /* НЕВЕРНО */

> free(p);

>

> Правильным будет, если вы до освобождения сохраните то, что вам потребуется, как в следующем цикле:

>

> for (p = head; p != NULL; p = q) {

> q = p->next;

> free(p);

> }

Написано, что 3-е издание.

mdraven
()
Ответ на: комментарий от tailgunner

Ассемблер посмотри - вдруг оптимизатор решил поменять местами строчки тела. Да и в valgrind могут быть ошибки :)

Это не реальная программа, это пример неправильного кода из книги. И эти четыре строчки - это и есть весь код. Предполагается, что в этих четырёх строках скрывается страшная ошибка - «обращение по указателю после его освобождения». Но походу в книге опечатка и ошибки нет...

Deleted
()
Ответ на: комментарий от Deleted

ну надо же сохранить указатель на следующую ноду , который ты прибиваешь вместе с нодой вот присер :
[code]
// Remove duplicates from a sorted list
void RemoveDuplicates(struct node* head) {

struct node* current = head;

if (current == NULL) return; // do nothing if the list is empty

// Compare current node with next node
while(current->next!=NULL) {

if (current->data == current->next->data) {
struct node* nextNext = current->next->next;
free(current->next);
current->next = nextNext;

}
else {
current = current->next; // only advance if no deletion
}
}
}
[/code]

kto_tama ★★★★★
()
Ответ на: комментарий от kto_tama

ну надо же сохранить указатель на следующую ноду

Он сохраняется в q.

Deleted
()

Нет там ошибки. Редакторы скорее всего перепутали строчки.

Legioner ★★★★★
()

> Друг пол часа назад обратился ко мне за помощью:
> Керниган, Ритчи 2-е издание, стр.179:


Твой друг звиздит. Это не 2-ое издание.
Второе издание на русском, это "Финансы и статистика", 1992.
Во втором издании этот код приведен в качестве _правильного_ и идентичен приведенной выдержке из третьего. Стр. 163.

Да, педант inb4.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

Второе издание на русском, это «Финансы и статистика», 1992.

издательский дом «Вильямс», 2006

Во втором издании этот код приведен в качестве _правильного_ и идентичен приведенной выдержке из третьего. Стр. 163.

Значит это баг переводчиков.

Deleted
()
Ответ на: комментарий от Deleted

> издательский дом "Вильямс", 2006

Это не "Вильямс". Это "Диалектика" со своим общеизвестным качеством на нашу беду выиграла тендер на переводы "Вильямса" для СНГ.


> Значит это баг переводчиков.


В таком бардаке, что у них - это может быть чей угодно баг. И "переводчиков", криво скопипастивших или распознавших, и "выпускающего редактора", который резал "лишнее".

Пидарасы.

LamerOk ★★★★★
()

> почему это неправильно?

ну вот смотри:

p!=NULL

где p уже освобожден.
Сюрприз, но с указателем p после free(p) нельзя делать почти ничего,
а не только разыменовать, как обычно считают.

Цитатим:

The value of a pointer becomes indeterminate when
the object it points to reaches the end of its lifetime.

The behavior is undefined in the following circumstances:
........
— The value of a pointer to an object whose lifetime has ended is used (6.2.4).
— The value of an object with automatic storage duration is used while it is
indeterminate (6.2.4, 6.7.8, 6.8).

dilmah ★★★★★
()

Похоже в книге действительно опечятка. Вот расписал все по шагам для 2-х узлов. Все нормально:

[code] #include <stdio.h> #include <stdlib.h>

struct node { struct node *next; };

int main() { // создадим 2 узла: node0,node1 struct node *node0; node0=malloc(sizeof(struct node));

struct node *node1; node1=malloc(sizeof(struct node));

node0->next=node1; node1->next=NULL;

// распишем цикл по шагам struct node *p, *q; int i = 0; p = node0;

begin: if (p != NULL) { q = p->next; printf("1) i=%d p=%p q=%p \n", i,p,q); free(p); printf("2) i=%d p=%p q=%p \n", i,p,q); p =q; printf("3) i=%d p=%p q=%p \n\n", i,p,q); i +=1; goto begin; } printf("Все ОК \n"); return 0; } [/code]

mike_711
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.