Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблемы с памятью в динамическом массиве, функция realloc 
:(
    Опции темы
MaXL
Дата 20.9.2008, 05:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Developer
**


Профиль
Группа: Участник
Сообщений: 380
Регистрация: 24.10.2005
Где: Владивосток

Репутация: нет
Всего: 2



Всем привет. Поискал на форуме ничего не нашёл. Вообще проблема такая:
пишу библиотеку для работы с динамическим массивом на Си.
Определены следующие типы данных:
Код


/* Тип хранимых в контейнере значений */
typedef int LSQ_BaseTypeT;

/* Дескриптор контейнера */
typedef void* LSQ_HandleT;

/* Неинициализированное значение дескриптора контейнера */
#define LSQ_HandleInvalid NULL

/* Дескриптор итератора */
typedef void* LSQ_IteratorT;

/* Тип целочисленного индекса контейнера */
typedef int LSQ_IntegerIndexT;

typedef struct _LSQ_ArrayT {
    LSQ_BaseTypeT* arrCont;
    LSQ_IntegerIndexT elementsCount;
} LSQ_ArrayT, *PLSQ_ArrayT;

typedef struct _LSQ_ArrIteratorT {
    PLSQ_ArrayT cont;
    LSQ_IntegerIndexT index;
} LSQ_ArrIteratorT, *PLSQ_ArrIteratorT;

Ну и вот функции, которые уже написаны(ну и в которых уже есть проблемы) :
Код

/* Функция, создающая пустой контейнер. Возвращает назначенный ему дескриптор */
LSQ_HandleT LSQ_CreateSequence(void) {
    PLSQ_ArrayT newCont;
    newCont = (PLSQ_ArrayT) malloc(sizeof(LSQ_ArrayT));
    if(newCont != LSQ_HandleInvalid)
        newCont->elementsCount = 0;
    return newCont;
}

/* Функция, добавляющая элемент в начало контейнера */
void LSQ_InsertFrontElement(LSQ_HandleT handle, LSQ_BaseTypeT element) {
    if(handle != LSQ_HandleInvalid) {
        PLSQ_ArrayT t_handle;
        int i;

        t_handle = (PLSQ_ArrayT)handle;
        t_handle->arrCont = (LSQ_BaseTypeT*)realloc((void*)t_handle->arrCont, sizeof(LSQ_BaseTypeT) * (t_handle->elementsCount + 1));
        if(t_handle->arrCont != LSQ_HandleInvalid) {
            t_handle->elementsCount++;
            for(i = t_handle->elementsCount; i > 0; i--)
                t_handle->arrCont[i] = t_handle->arrCont[i - 1];
            t_handle->arrCont[0] = element;
        }
    }
}

/* Функция, уничтожающая контейнер с заданным дескриптором. Освобождает принадлежащую ему память */
void LSQ_DestroySequence(LSQ_HandleT handle) {
    if(handle != LSQ_HandleInvalid) {
        free(((PLSQ_ArrayT)handle)->arrCont);
        free(handle);
    }
}


Ну а вот так я его использую:
Код

#include <stdio.h>
#include <stdlib.h>
#include "linear_sequence.h"

int main()
{
    LSQ_IteratorT conteiner;
    conteiner = LSQ_CreateSequence();
    printf("Elements count: %d\n", LSQ_GetSize(conteiner));
    int i;
    for(i = 0; i < 100; i++) {
        LSQ_InsertFrontElement(conteiner, (i + 1) * 18);
    }
    printf("Elements count: %d\n", LSQ_GetSize(conteiner));

    LSQ_DestroySequence(conteiner);
    return 0;
}

Ну и как было выяснено в цикле, при втором вызове функции добавления элемента, функция realloc возвращает 0.
Куда копать я даже и не знаю =(


--------------------
MaXL
PM MAIL   Вверх
J0ker
Дата 20.9.2008, 06:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 986
Регистрация: 17.9.2008

Репутация: 4
Всего: 14



ну на вскидку - вы arrCont не инициализируете (если я ниче не упустил)

Добавлено @ 06:16
...и стиль какой-то из каменного века - дефайн на NULL, типы переопределены... ну зачем вот переопределен void *? чтоб потомков запутать? или вы мелкомягким подражаете  smile ?
а может лучше C++заюзать и не мучить задницу? там и вектор есть темплейтный

Это сообщение отредактировал(а) J0ker - 20.9.2008, 06:16


--------------------
user posted image
PM MAIL   Вверх
MaXL
Дата 20.9.2008, 08:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Developer
**


Профиль
Группа: Участник
Сообщений: 380
Регистрация: 24.10.2005
Где: Владивосток

Репутация: нет
Всего: 2



Цитата(J0ker @  20.9.2008,  06:09 Найти цитируемый пост)
ну на вскидку - вы arrCont не инициализируете (если я ниче не упустил)

ну вот вписал в функцию создания такую строчку:
Код

        newCont->arrCont = 0;

только вот это не исправило ситуации. Пытался сделать инициализацию через malloc, путм передачи ей в качестве параметра "0" но эффект тот же(ну это и так понятно, потому что  malloc вернёт ноль, если ей передать нулевой размер).
Так вот ещё получилось небольшой прикол. Я пишу в Code::Blocks, с использованием компилятора MinGW. Если запускать программу "средой", т.е. просто нажать F9 подождать пока скомпилица и запуститься то отлетает на втором проходе цикла и при этом программа вылетет с кодом, отличным от нуля. А если запустить через Far то на 72-ом проходе цикла, и выходет всё как нужно. Что же всё таки такое может быть ?

Цитата(J0ker @  20.9.2008,  06:09 Найти цитируемый пост)
...и стиль какой-то из каменного века - дефайн на NULL, типы переопределены... ну зачем вот переопределен void *? чтоб потомков запутать? или вы мелкомягким подражаете  smile ?

видите ли в чём дело, нам препод в универе дал файл *.h в котором объявлены эти типы данных(кроме моих структур) а также сигнатуры функций. А мне нужно сделать реализацию именно на языке Си. Ну т.е. получиться библиотека. Её нужно отослать на сервак, там юнит тесты, если всё пройдёт то Ok, потом преподу ещё код отдельно сдавать, он будет спрашивать чо да как. 
Цитата(J0ker @  20.9.2008,  06:09 Найти цитируемый пост)
а может лучше C++заюзать и не мучить задницу? там и вектор есть темплейтный

преподу задавли вапрос "Можно на Си++ или Делфи ?", Делфи - обойдетесь. Си++ там есть уже готовый STL. ну впринципе я с ним частично согласен, хоть понять можно будет чо такое Си, Си++ будет в следующем семестре.


--------------------
MaXL
PM MAIL   Вверх
MaXL
Дата 20.9.2008, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Developer
**


Профиль
Группа: Участник
Сообщений: 380
Регистрация: 24.10.2005
Где: Владивосток

Репутация: нет
Всего: 2



Ну и ещё, если убрать строчку 
Код

t_handle->arrCont = (LSQ_BaseTypeT*)realloc((void*)t_handle->arrCont, sizeof(LSQ_BaseTypeT) * (t_handle->elementsCount + 1));

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

void LSQ_InsertFrontElement(LSQ_HandleT handle, LSQ_BaseTypeT element) {
    if(handle != LSQ_HandleInvalid) {
        PLSQ_ArrayT t_handle;
        LSQ_BaseTypeT* arr;
        int i;

        t_handle = (PLSQ_ArrayT)handle;
        arr = (LSQ_BaseTypeT*)malloc(sizeof(LSQ_BaseTypeT) * (t_handle->elementsCount + 1));
        if(arr != LSQ_HandleInvalid) {
            t_handle->elementsCount++;
            for(i = 1; i < t_handle->elementsCount; i++)
                arr[i] = t_handle->arrCont[i - 1];
            arr[0] = element;
            free(t_handle->arrCont);
            t_handle->arrCont = arr;
        }
    }
}

и всё стало работать. А теперь внимание вапрос, что не так было ранее ? ведь я так понимаю функция realloc работает именно так, как я тут показал(ну там может ещё проверки какие-нить есть).

Это сообщение отредактировал(а) MaXL - 20.9.2008, 11:38


--------------------
MaXL
PM MAIL   Вверх
vinick
Дата 20.9.2008, 12:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 9.6.2005

Репутация: 3
Всего: 22



Вот здесь косяк был

Код

 for(i = t_handle->elementsCount; i > 0; i--)
                t_handle->arrCont[i] = t_handle->arrCont[i - 1];
            t_handle->arrCont[0] = element;


Элемент  t_handle->arrCont[t_handle->elementsCount] лежит за границей массива

PM MAIL ICQ Jabber   Вверх
J0ker
Дата 20.9.2008, 17:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 986
Регистрация: 17.9.2008

Репутация: 4
Всего: 14



Цитата(vinick @ 20.9.2008,  12:45)
Вот здесь косяк был

Код

 for(i = t_handle->elementsCount; i > 0; i--)
                t_handle->arrCont[i] = t_handle->arrCont[i - 1];
            t_handle->arrCont[0] = element;


Элемент  t_handle->arrCont[t_handle->elementsCount] лежит за границей массива

да точно
в логику не углублялся   smile 
и цикл вам не нужен - замените на memmove
только граицы правильно считайте на сей раз  smile

Добавлено @ 17:46
Цитата(MaXL @  20.9.2008,  10:32 Найти цитируемый пост)
переписал момент выделения памяти, под новый массив, получилось вот так:
    
Код

arr = (LSQ_BaseTypeT*)malloc(sizeof(LSQ_BaseTypeT) * (t_handle->elementsCount + 1));
        if(arr != LSQ_HandleInvalid) {
            t_handle->elementsCount++;
            for(i = 1; i < t_handle->elementsCount; i++)
                arr[i] = t_handle->arrCont[i - 1];
            arr[0] = element;
            free(t_handle->arrCont);
            t_handle->arrCont = arr;

и всё стало работать.


это не эффективно
верните realloc и замените цикл на memmove

Это сообщение отредактировал(а) J0ker - 20.9.2008, 17:55


--------------------
user posted image
PM MAIL   Вверх
MaXL
Дата 22.9.2008, 17:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Developer
**


Профиль
Группа: Участник
Сообщений: 380
Регистрация: 24.10.2005
Где: Владивосток

Репутация: нет
Всего: 2



J0ker, vinick, пасиб за помощь. Переписал, но вот только бес использования memmove. Почему-то она не заработало. Пробовал просто для одного массива потестить всё работает, а если с той структурой то не работает. Ну да ладно, уже полностью написал библиотеку, залил в систему, прошла все 34 теста. Всем пасиб.
P.S. вот такой код получился:
Код

void LSQ_InsertFrontElement(LSQ_HandleT handle, LSQ_BaseTypeT element) {
    if(handle != LSQ_HandleInvalid) {
        PLSQ_ArrayT t_handle;
        int i;

        t_handle = (PLSQ_ArrayT)handle;
        t_handle->arrCont = (LSQ_BaseTypeT*)realloc(t_handle->arrCont, sizeof(LSQ_BaseTypeT) * (t_handle->elementsCount + 1));
        if(t_handle->arrCont != NULL) {
            for(i = t_handle->elementsCount - 1; i >= 0; i--)
                t_handle->arrCont[i + 1] = t_handle->arrCont[i];
            t_handle->arrCont[0] = element;
            t_handle->elementsCount++;
        }
    }
}



--------------------
MaXL
PM MAIL   Вверх
vinick
Дата 22.9.2008, 19:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 9.6.2005

Репутация: 3
Всего: 22



sorry, фигню здесь написал. У J0ker'а  ниже  правильный вариант.



Это сообщение отредактировал(а) vinick - 22.9.2008, 20:55
PM MAIL ICQ Jabber   Вверх
J0ker
Дата 22.9.2008, 20:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 986
Регистрация: 17.9.2008

Репутация: 4
Всего: 14



Цитата(MaXL @  22.9.2008,  17:00 Найти цитируемый пост)
Код

        for(i = t_handle->elementsCount - 1; i >= 0; i--)
                t_handle->arrCont[i + 1] = t_handle->arrCont[i];


Код

memmove(&t_handle->arrCont[1], &t_handle->arrCont[0], t_handle->elementsCount * sizeof(LSQ_BaseTypeT));




--------------------
user posted image
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0936 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.