Форум программистов, компьютерный форум, киберфорум
C для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.55/20: Рейтинг темы: голосов - 20, средняя оценка - 4.55
1 / 1 / 0
Регистрация: 08.05.2009
Сообщений: 16
1

После компиляции VS2008 падает после удаления узла дерева, имеющего потомка

24.05.2009, 17:16. Просмотров 4092. Ответов 36
Метки нет (Все метки)

Вот код на Си:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <conio.h>
 
struct Node;
 
struct ChildNode{
        struct ChildNode *prev;
        struct ChildNode *next;
        struct Node *element;
};
typedef struct ChildNode childnode;
 
struct Node{
        int index;
        double value;
        childnode *parent;
        childnode *children;
};
typedef struct Node node;
 
struct List{
        int count;
        struct List *prev;
};
typedef struct List list;
 
node *first;
int count = 0;
 
node *GetElementByIndex(int index, node *t)
{
        node *temp = NULL;
        childnode *c;
 
        if (t==NULL)
               return NULL;
        if (t->index==index)
                return t;
        c=t->children->next;
        if (c==NULL)
                return NULL;
        while (c!=NULL)
        {
                temp=GetElementByIndex(index,c->element);
                if (temp!=NULL)
                        break;
                c=c->next;
        }
        if (temp!=NULL)
                return temp;
        return NULL;
}
 
int AddNode(int index, double value)
{
        node *t, *temp;
        childnode *c, *child;
 
        if (first==NULL)
        {
                temp = (node *)malloc(sizeof(node));
                temp->value = value;
                temp->index = 1;
                temp->children = (childnode*)malloc(sizeof(childnode));
                temp->children->prev = NULL;
                temp->children->next = NULL;
                temp->children->element = NULL;
                first=temp;
                count=1;
                return 0;
        }
       
        t = GetElementByIndex(index,first);
        if (t==NULL)
                return -1;
 
        ++count;
        temp = (node *)malloc(sizeof(node));
        child = (childnode*)malloc(sizeof(child));
        temp->value = value;
        temp->index = count;
        temp->parent = child;
        temp->children = (childnode*)malloc(sizeof(childnode));
        temp->children->prev = NULL;
        temp->children->next = NULL;
        temp->children->element = NULL;
        child->next = NULL;
        child->element = temp;
        c=t->children;
        while (c->next!=NULL)
                c=c->next;
        child->prev = c;
        c->next = child;
        return 0;
}
 
void PrintTree(const char *str, node *p)
{
        childnode *c;
        char temp[50];
 
        if (p==NULL)
                return;
        printf("%s%i: %0.2f\n",str,p->index,p->value);
        if (p->children->next==NULL)
                return;
        strcpy(temp,str);
        strcat(temp,"\t\0");
        c=p->children->next;
        while (c!=NULL)
        {
                PrintTree(temp,c->element);
                c=c->next;
        }
        return;
}
 
void DeleteTree(node *p)
{
        childnode *c, *cTemp;
 
        c=p->children->next;
        while (c!=NULL)
        {
            DeleteTree(c->element);
                cTemp = c;
            c = c->next;
                free(cTemp);                                  //Падает тут
                cTemp = NULL;
        }
        free(p->children);
        if (first==p)
                first = NULL;
        else
        {
                if (p->parent->next!=NULL)
                        p->parent->next->prev = p->parent->prev;
                p->parent->prev->next = p->parent->next;
        }
        p->parent->element=NULL;
            free(p);
}
 
void Delete(int index)
{
        node *t;
 
        if (first==NULL)
                return;
        t = GetElementByIndex(index,first);
        if (t==NULL)
                return;
        DeleteTree(t);
        return;
}
 
int main()
{
        char c;
        int index, cnt;
        double value;
        
        do
        {
                c = getch();
                switch(c)
                {
                        case '1':
                                PrintTree("", first); break;
                        case '2':
                                printf("Input index and value to input: "); scanf("%i%le",&index,&value); AddNode(index,value); break;
                        case '3':
                                printf("Input index to delete"); scanf("%i",&index); Delete(index); break;
                }
        } while (c!='4');
}
программа строит дерево, печатает его, удаляет узлы (с удалением всех дочерних узлов).

в борладне все работает. Под *nix системами после компиляции gcc и в win после компиляции VS2008 падает после удаления узла дерева, имеющего потомка. Не могу разобраться почему, вроде все корректно выделяю, да и free передаю тот же адрес, что выделил мне malloc. Помогите разобраться, пожалуйста.

Выделю место, где программа падает, на всякий:

C
1
2
3
4
5
6
7
8
9
  c=p->children->next;
        while (c!=NULL)
        {
            DeleteTree(c->element);
                cTemp = c;
            c = c->next;
                free(cTemp);                                  //Падает тут
                cTemp = NULL;
        }
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
24.05.2009, 17:16
Ответы с готовыми решениями:

Удаление узла имеющего одного потомка
Нужно добавить функцию, которая удаляет узлы имеющие одного потомка! Помогите! using namespace...

Изменение атрибутов XML после удаления узла
Такая проблема &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt; &lt;Animals&gt; &lt;Dinosaur ID=&quot;1&quot;&gt; ...

После удаления Avast'а система не запускается, падает в BSOD
после удаления аваста система не запускаеться что можно сделать выбивает экран смерти Добавлено...

Ошибка при компиляции после удаления ресурса
Делаю проект.На задний фон формы поставил изображение.Но изображение мне не понравилось и я заменил...

36
Почетный модератор
7336 / 2601 / 270
Регистрация: 29.07.2006
Сообщений: 13,588
24.05.2009, 17:18 2
поставь брейкпойнт на строчку перед free и посмотри на что cTemp указывает.
0
1 / 1 / 0
Регистрация: 08.05.2009
Сообщений: 16
24.05.2009, 17:27  [ТС] 3
Цитата Сообщение от Vourhey Посмотреть сообщение
поставь брейкпойнт на строчку перед free и посмотри на что cTemp указывает.
спасибо за дельный совет, конечно, но, прежде чем написать на форум, я отлаживал её около часа. Да и читать мой пост нужно внимательней, я же написал:

да и free передаю тот же адрес, что выделил мне malloc
0
Evg
Эксперт CАвтор FAQ
21142 / 8158 / 628
Регистрация: 30.03.2009
Сообщений: 22,467
Записей в блоге: 30
24.05.2009, 17:50 4
Лучший ответ Сообщение было отмечено Памирыч как решение

Решение

Алгоритмически удаляешь вроде бы правильно. free будет ломаться на исполнении, если ты его уже пытался удалить, или если затёр какую-либо служебную информацию. Собственно есть две идеи

1. Перед всеми free поставь печать того, что удаляешь и глазами убедись, что один и тот же узел два раза не удаляется.
2. После каждого вызова malloca поставь печать того, что вернул malloc, а так же значения по адресам на 8 меньшим, чем это значение (там обычно хранится служебная информация). Т.е. грубо говоря вместо "p = malloc(...);" в каждом месте напиши

C
1
2
3
4
p = malloc (....);
printf ("malloc res=%p\n", p);
printf ("res[-1]=0x%08x\n", *(((int*)p)-1));
printf ("res[-2]=0x%08x\n", *(((int*)p)-2));
а вместо free (p) напиши

C
1
2
3
4
printf ("free %p\n", p);
printf ("free[-1]=0x%08x\n", *(((int*)p)-1));
printf ("free[-2]=0x%08x\n", *(((int*)p)-2));
free (p);
И глазами убедись, что служебню информацию ты не затёр
0
Почетный модератор
7336 / 2601 / 270
Регистрация: 29.07.2006
Сообщений: 13,588
24.05.2009, 17:55 5
Цитата Сообщение от Pori Посмотреть сообщение
спасибо за дельный совет, конечно, но, прежде чем написать на форум, я отлаживал её около часа. Да и читать мой пост нужно внимательней, я же написал:
И что, что адрес? free адреса не меняет, умник. Обратись к объекту перед free.
0
1 / 1 / 0
Регистрация: 08.05.2009
Сообщений: 16
24.05.2009, 18:02  [ТС] 6
Цитата Сообщение от Vourhey Посмотреть сообщение
И что, что адрес? free адреса не меняет, умник. Обратись к объекту перед free.
попрошу без оскорблений "пустой набиватель постов"

я же тебе русским языком говорю, дебагал программу в борланде и студии. По адресу, который передается free находится объект, который до этого был выделен malloc'ом. Если не можешь помочь, не пиши, пожалуйста, глупые посты.

Evg, спасибо, сейчас попробую
0
Evg
Эксперт CАвтор FAQ
21142 / 8158 / 628
Регистрация: 30.03.2009
Сообщений: 22,467
Записей в блоге: 30
24.05.2009, 18:03 7
Господа, может хватит ругаться? Ей-богу как дети малые
0
Почетный модератор
7336 / 2601 / 270
Регистрация: 29.07.2006
Сообщений: 13,588
24.05.2009, 18:04 8
Адрес не меняется, а вот обратиться к объекту ты не сможешь, если он уже был освобожден однажды.
0
Evg
Эксперт CАвтор FAQ
21142 / 8158 / 628
Регистрация: 30.03.2009
Сообщений: 22,467
Записей в блоге: 30
24.05.2009, 18:11 9
Цитата Сообщение от Vourhey Посмотреть сообщение
Адрес не меняется, а вот обратиться к объекту ты не сможешь, если он уже был освобожден однажды.
Зависит от реализации malloc/free. Обычно память просто размечается как освобождённая (в менеджере amlloc'а), но физически она никуда не девается и обратиться туда можно
0
Почетный модератор
7336 / 2601 / 270
Регистрация: 29.07.2006
Сообщений: 13,588
24.05.2009, 18:33 10
Ты ошибаешься. У тебя будет выдана ошибка при попытке, например, вызвать метод. В VS так вроде было... По крайне мере, если ошибки не будет при выполнении, в дебагере ошибку увидеть полубому можно.
Я уже не говорю о возможности gcc вывода "double free corruption", когда одна область два раза освобождается, прямо на терминал, даже принтфоф не нужно.
Т. о., то, что память уже освобождена будет видно не вооруженным глазом в случае с gcc, к примеру. Хотя обратиться к методу и можно.
0
Evg
Эксперт CАвтор FAQ
21142 / 8158 / 628
Регистрация: 30.03.2009
Сообщений: 22,467
Записей в блоге: 30
24.05.2009, 18:42 11
Не очень понимаю, как к данному примеру на Си относятся методы, но тем не менее. Вызов метода вообще не зависит от того, валидный указатель или нет

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include <stdlib.h>
 
class A
{
  public:
    void func (void);
};
 
void
A::func (void)
{
  printf ("trampampam\n");
}
 
int
main (void)
{
  A *p;
 
  p = (A*) malloc (sizeof(A));
  p->func();
 
  free (p);
  p->func();
 
  p = NULL;
  p->func();
 
  ((A*)0x12345)->func();
 
  return 0;
}
Код
$ g++ a.c && ./a.out 
trampampam
trampampam
trampampam
trampampam
0
Почетный модератор
7336 / 2601 / 270
Регистрация: 29.07.2006
Сообщений: 13,588
24.05.2009, 18:51 12
Вот те трампампам, нах:
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x09b23008 ***
Безо всяких притфоф. Ну вас нафиг, белиберду какую-то пишете...
0
Evg
Эксперт CАвтор FAQ
21142 / 8158 / 628
Регистрация: 30.03.2009
Сообщений: 22,467
Записей в блоге: 30
24.05.2009, 18:55 13
Покажи исходник и как компилял/запускал
0
Почетный модератор
7336 / 2601 / 270
Регистрация: 29.07.2006
Сообщений: 13,588
24.05.2009, 18:56 14
Создаешь объект класса, например. пусть зовут b.
потом делаешь
C
1
free(b);free(b);
Все. Проверка срабатывает, все пишется на терминал, как ты видел выше.
0
Evg
Эксперт CАвтор FAQ
21142 / 8158 / 628
Регистрация: 30.03.2009
Сообщений: 22,467
Записей в блоге: 30
24.05.2009, 18:57 15
А... ты про исходный то файл
0
Почетный модератор
7336 / 2601 / 270
Регистрация: 29.07.2006
Сообщений: 13,588
24.05.2009, 18:59 16
Да, я про то, что в гсисе он бы сразу увидел, что у него даблфри. ИМХО. Если на терминал смотрел )
0
Evg
Эксперт CАвтор FAQ
21142 / 8158 / 628
Регистрация: 30.03.2009
Сообщений: 22,467
Записей в блоге: 30
24.05.2009, 19:02 17
Ты туверждал, что после free вообще с указателем делать ничего нельзя

Цитата Сообщение от Vourhey Посмотреть сообщение
а вот обратиться к объекту ты не сможешь, если он уже был освобожден однажды
Я тебе сказал, что зависит от реализации.
Далее

Цитата Сообщение от Vourhey Посмотреть сообщение
Ты ошибаешься. У тебя будет выдана ошибка при попытке, например, вызвать метод
Я тебе выдал пример, в котором обращаюсь к методу через освобождённый/битый указатель.

То, что из-под glibc пишется, что free вызван второй раз - далеко не факт, что в той версии библиотеки, которую использует автор (и наверняка это под виндой), будет то же самое. Потому и разжевал товарищу, как визуально отследить всю работу с динамической памятью

Добавлено через 1 минуту 13 секунд
Цитата Сообщение от Vourhey Посмотреть сообщение
Да, я про то, что в гсисе он бы сразу увидел, что у него даблфри. ИМХО. Если на терминал смотрел )
Блин, что-то я не обратил снимание, что раздел "С++ для линукса"
В любом случае мои возражения остаются в силе - не факт, что на его версии glibc было бы то же самое
0
Почетный модератор
7336 / 2601 / 270
Регистрация: 29.07.2006
Сообщений: 13,588
24.05.2009, 19:10 18
В любом случае мои возражения остаются в силе - не факт, что на его версии glibc было бы то же самое
Тогда не факт, что free вообще правильно работает. А эта проверка в glibc уже давно.
Я тебе выдал пример, в котором обращаюсь к методу через освобождённый/битый указатель.
Указатель нифига не битый. Указатель остается тем же. Такой пример я тебе мог написать.
Я тебе сказал, что зависит от реализации.
Я в курсе. Вот и пусть и проверит это на разных компиляторах. Один точно выкинет что-то, в случае обращения к такой области. Причем, я встречал и те которые выдавали ошибку - VC++, и те которые нет - g++.

Добавлено через 1 минуту 9 секунд
Блин, что-то я не обратил снимание, что раздел "С++ для линукса"
ну мне уж без разницы, кто тут на чем сидит.

Добавлено через 44 секунды
Да и вообще. Я не видел сообщения об ошибке, которое ему пишется.
0
Evg
Эксперт CАвтор FAQ
21142 / 8158 / 628
Регистрация: 30.03.2009
Сообщений: 22,467
Записей в блоге: 30
24.05.2009, 19:11 19
Цитата Сообщение от Vourhey Посмотреть сообщение
Указатель нифига не битый. Указатель остается тем же. Такой пример я тебе мог написать.
Я не понимаю эту фразу. Соотвественно не понимаю первые две цитаты из поста #17
Что ты этим хотел сказать?

Добавлено через 33 секунды
А ещё лучше на примере (на пальцах) - так проще понять будет
0
инженер-системотехник
111 / 111 / 5
Регистрация: 10.03.2009
Сообщений: 533
24.05.2009, 19:12 20
Evg, объясните, пожалуйста, почему после 27 строки ( p = NULL) все равно вызывается метод?
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.05.2009, 19:12

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Ошибка компиляции после удаления файла в проекте в NetBeans C++
После удаления какого либо файла из проекта из окна &quot;файлы&quot; среды NetBeans проект не компилируется....

Алгоритм удаления узла из бинарного дерева
Есть алгоритм удаления узла из бинарного дерева поиска,в нем ,если узел имеет 2 х сыновей...

Удаления узла из бинарного дерева поиска
Уже довольно много времени убил на эту задачу, теорию понимаю, на практике реализовать никак не...

Вершина бинарного дерева: Как на рисунке будут выглядеть деревья до и после удаления?
Ребят помогите разобраться. Есть массив 2 4 5 40 50 100. Если удалить 5 ( заменяем удаленный...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.