Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Работа с переменными (с++)

44K
22 марта 2009 года
Serreg@
4 / / 15.12.2008
Великие программисты, подскажите кто знает, пожалуйста.

Проблема, с которой я столкнулся, заключается в следующем: на c++ реализован пользовательский класс; в главной процедуре создается его экземпляр и с ним происходит работа через интерфейсные функции класса.

Внутри этих процедур динамически выделяются массивы (средствами выделения динамической памяти new). Т.е. каждый экземпляр класса хранит указатель на массив, который в ходе работы меняется (и структурно и информационно). Проблема возникла в том, что при выделении очередного массива все теми же средствами new, компилятор размещает новый массив на месте, казалось бы, уже занятым другим массивом. Это несколько неожиданно, на мой взгляд т.к. ранее размещенный массив безвозвратно теряется.

Вопрос в следующем - что бы сделать такого, что бы компилятор отдавал себе отчет в том, что ранее выделенные области памяти (до соответствующего вызова оператора detele) заняты и не пригодны для размещения в них новых данных.

На всякий случай приведу выписки из кода:

Код:
class myClass
{
    // В классе описаны структуры
    struct somestruct1
    {
        char* string1;
        char* string2;
        int integer1;
    };
   
    struct somestruct2
    {
        somestruct1* somestruct1_pointer;
        int integer;
    };
   
    // Каждый экземпляр содержит
    somestruct1* struct1_pointer;
    somestruct2* struct2_pointer;
    int main_integer;
   
    // Процедуры, которые вызываются при работе c объектом
    int myClass::g()
    {
        if (main_integer == 0)
        {
            struct2_pointer = new somestruct2;
            struct2_pointer[0].somestruct1_pointer = NULL;
            struct2_pointer[0].integer = 0;
        } else {
            if ((struct2_pointer[main_integer - 1].integer) == 0)
                return 1;
            somestruct2* new_struct2;
            new_struct2 = new somestruct2[main_integer];
            for (int i=0; i<main_integer; i++)
            {
                new_struct2.somestruct1_pointer = struct2_pointer.somestruct1_pointer;
                new_struct2.integer = struct2_pointer.integer;
            }
            new_struct2[main_integer].somestruct1_pointer = NULL;
            new_struct2[main_integer].integer = 0;
            delete[]struct2_pointer;
            struct2_pointer = new_struct2;
        }
        main_integer++;
        return 0;
    }

    int myClass::h (char* chars1, char* chars2)
    {
        somestruct1* struct1 = new somestruct1;
        struct1_pointer->integer1++;

        // !!!
        struct1->string1 = new char[strlen(chars1)]; // !!! Тут происходит выделение ранее используемое памяти
        // !!!
        struct1->string2 = new char[strlen(chars2)];
        strcpy(struct1->string1, chars1);
        strcpy(struct1->string2, chars2);
        ...
        return 0;
    }
    ...
}

// И сама процедура, из которой это все вызывается
void f()
{
    myClass mc;
    ...
    mc.g();
    mc.h();
    ...
}

В момент выполнения процедуры h в указаной строке происходит затирание выделенной в g памяти (строка struct1->string1 заменяет ранее созданный массив struct2_pointer). Что я делаю не так? :)

P.S. Компилятор - CodeGear C++Builder 2009 (Update 1)
1.9K
22 марта 2009 года
GreenRiver
451 / / 20.07.2008
Поверьте, если вы выделили память, то никто на нее не покусится, пока вы сами не освободите ее...

А в целом код, просто мясо... Можно было хотя бы дать осмысленные имена переменным? Или думаете кому-то интересно копаться в somestruct1, somestruct2, somestruct1_pointer, main_integer... ужас...

P.S. Используйте std:string или String (раз уж пишите в билдере...)
87
22 марта 2009 года
Kogrom
2.7K / / 02.02.2008
Я не великий программист, но все же.
Цитата: Serreg@
Что я делаю не так?


Много чего. Например, вы неправильно думаете, что (main_integer == 0) это true.

44K
22 марта 2009 года
Serreg@
4 / / 15.12.2008
Цитата: GreenRiver
Поверьте, если вы выделили память, то никто на нее не покусится, пока вы сами не освободите ее...

А в целом код, просто мясо... Можно было хотя бы дать осмысленные имена переменным? Или думаете кому-то интересно копаться в somestruct1, somestruct2, somestruct1_pointer, main_integer... ужас...

P.S. Используйте std:string или String (раз уж пишите в билдере...)


Вот полный исходный код. Тут полно комментариев, но зато имена такие, наверное, более удобные для вас.
По-сути дела, при пошаговом выполнении у меня не работает добавление элемента (v.add_son(a, b) и то, что в демке идет далее). При этом сбой происходит при попытке записать в информационную часть элемента дерева полученной строки через создание дубликата полученной строки - сбивается массив, хранящий структуру дерева - уровни (по крайней мере первый уровень затирается).

Цитата: Kogrom
Я не великий программист, но все же.

Много чего. Например, вы неправильно думаете, что (main_integer == 0) это true.


:) В конструкторе, который тут не приведен, я определяю его изначально равным нулю. В компилятор я, конечно, не верю и не доверяю ему обнуление всех созданных переменных.

Спасибо за отклики!

1.9K
22 марта 2009 года
GreenRiver
451 / / 20.07.2008
Это какое-то нестандартное дерево? Просто немного не понял, зачем нужны уровни - вроде если есть root и у него есть "отростки" (например, массив Child)- они автоматически образуют слой.
Сразу непонятно где ошибка, но все же почему не использовать String? :)
87
22 марта 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Serreg@
В конструкторе, который тут не приведен, я определяю его изначально равным нулю.


Между прочим, делаете это не самым лучшим способом.

Цитата: Serreg@
В компилятор я, конечно, не верю и не доверяю ему обнуление всех созданных переменных.



Компилятор по стандарту не должен обнулять локальные переменные.

Но все это мелочи. Все же хотелось бы услышать ответ на вопрос, который задал GreenRiver - почему вы не используете STL?

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

44K
22 марта 2009 года
Serreg@
4 / / 15.12.2008
Цитата: GreenRiver
Это какое-то нестандартное дерево? Просто немного не понял, зачем нужны уровни - вроде если есть root и у него есть "отростки" (например, массив Child)- они автоматически образуют слой.
Сразу непонятно где ошибка, но все же почему не использовать String? :)


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

Цитата:
Элементу (i, j) в дереве (і – номер уровня, j – номер элемента на j-м уровне) может быть присвоено некоторое значение. Так же, например вариант:
d(i,j)=d2; //где d, d2 – деревья


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

Цитата: Kogrom
Между прочим, делаете это не самым лучшим способом.

Компилятор по стандарту не должен обнулять локальные переменные.

Но все это мелочи. Все же хотелось бы услышать ответ на вопрос, который задал GreenRiver - почему вы не используете STL?

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


Ну я понимаю, что компилятор не обязян обнулять. Я просто отметил, что делаю это вручную (с долей иронии в высказывании о том, что не доверяю компилятору), как оказывается, не лучшим спобобом :) А как, по-вашему, лучше обнулить счетчик уровней?

За совет по поводу создания миниатюрного класса спасибо - попробую.

87
22 марта 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Serreg@
А как, по-вашему, лучше обнулить счетчик уровней?


На счет счетчика уровней ничего не знаю, но советую предпочитать инициализацию вместо присваивания в конструкторах. Например:

 
Код:
struct MyClass{
    int n;
    MyClass():n(15){/*...*/}
};

иначе все равно конструктор сам произведет инициализацию по умолчинию, а потом еще и присвоит значение. Лишнее действие.
44K
24 марта 2009 года
Serreg@
4 / / 15.12.2008
Решил проблему отказом от принятой тут структуры, на которой основывалось дерево и переходу к более логичной:

 
Код:
struct node
{
    // Информационная часть
    char* key;
    char* relation;
    // Cсылка на следующего соседа по уровню (конец уровня опреледяет ссылка на ноль)
    node* next;
    // Ссылка на первого сына (конец списка сыновей опреледяет ссылка на ноль)
    node* son;
};


Это позволило обойтись без необходимости создавать и перестраивать массив уровней. Немного усложнился поиск i-ого элемента j-ого уровня, но это того стоило. Другие процедуры за счет облегчения структуры стали значительно проще и понятнее.

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

Всем отписавшимся большое спасибо за помощь и поддержку. Всем посетителям желаю удачи в реализации проектов.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог