C ошибка при удалении массива

GetHelp, ну смотри.

Есть у нас такая штука

Что здесь делает new? Находит место в памяти под один объект типа T, выделяет память в необходимом кол-ве, вызывает конструктор по умолчанию и возвращает указатель на участок памяти в котором находится наш объект типа T. Так? Так.

Что делает delete? Вызывает деструктор одного объекта на который указывает ptr и освобождает память. Так? Так.

Что делает new[]? Находит место в памяти под n объектов типа T, выделяет память под n объектов типа T, для каждого объекта вызывает конструктор по умолчанию и возвращает указатель на первый объект типа T. Так? Так.

Что делает delete[]? Вызывает деструктор для кажд.. погоди ка, а откуда delete[] знает что нужно вызвать деструкторы для нескольких объектов? А оттуда что он delete[], а не delete. А еще delete[] знает сколько деструкторов вызвать, и какое кол-во памяти освободить. А это, в свою очередь, говорит о том что new[] как то сообщает delete[], чего и сколько освобождать. Но вот чего delete[] не знает, так это того, как себя вести, если его попросят освободить память выделенную при помощи new, который общается с delete, но не с delete[]. По этому он будет вести себя как обычно, т.е пытаться освобождать память выделенную под несколько элементов, что в свою очередь ведет к неопределённому поведению. Тоже самое касается и освобождения памяти, выделенной new[], при помощи delete.

Верить или не верить это конечно дело твоё, но если ты обращаешься за помощью на форум, то, наверное, нужно хоть немножко обращать внимание на то, что тебе советуют.

По коду:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
town::town()
{
    name = new char; // выделили память под один символ
    *name = 0;
    ...
    transport = new char; // выделили память под один символ
    *transport = 0;
}
 
town::town(char* _name)
{
    ...
    transport = new char; // выделили память под один символ
    *transport = 0;
}
 
town::~town()
{
    if (name) delete[] name; // освобождаем память как будто name это массив
    ...
    if (transport) delete[] transport; // освобождаем память как будто transport это массив
}

Если объект типа town был инициализирован конструктором town() или town(char*), то в деструкторе возникает неопределенное поведение.

Решается очень просто:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
town::town()
{
    name = 0; // нет имени, нулевой указатель
    ...
    transport = 0; // нет транспорта, нулевой указатель
}
 
town::town(char* _name)
{
    ...
    transport = 0; // нет транспорта, нулевой указатель
}
 
town::~town()
{
    delete[] name; // освобождаем память
    ...
    delete[] transport; // освобождаем память
}

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

Далее:

C++
1
2
3
4
5
6
7
8
9
10
11
bool town::Input()
{
    char *filename;
    char *tmp, *str;
    ... // выделение памяти под имя файла и путь
    ifstream stream(tmp);
    if (!stream.is_open()) return false;
    delete[] filename;
    delete[] tmp;
    ...
}

Если поток ввода не открылся, то функция завершает своё выполнение и оставляет выделенной память под имя файла и путь. Утечка.

Решение:

C++
1
2
3
4
5
6
7
8
bool town::Input()
{
    ...
    delete[] filename;
    delete[] tmp;
    if (!stream.is_open()) return false;
    ...
}

Переместить условие завершения функции.

И здесь же:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool town::Input()
{
    ...
    //читаю название
    str = GetString(stream);
    sscanf(str, "name=%s", name);
    delete[] str;
    ...
    //читаю виды транспорта
    str = GetString(stream);
    sscanf(str, "transport=%s", transport);
    delete[] str;
 
    return true;
}

Функция sscanf ведь не выделяет память под новый контент, она пытается записать его по переданным адресам.
Но если объект типа town был инициализирован конструктором town() или town(char*), то в вашем варианте name и transport это указатели на один символ, в моем нулевые указатели. Что делать? Выделять память в нужном количестве.

Как вариант:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bool town::Input()
{
    ...
    //читаю название
    str = GetString(stream);
    if (name)
        delete[] name;
    name = new char[strlen(str) - strlen("name=") + 1];
    sscanf(str, "name=%s", name);
    delete[] str;
    ...
    //читаю виды транспорта
    str = GetString(stream);
    if (transport)
        delete[] transport;
    transport = new char[strlen(str) - strlen("transport=") + 1];
    sscanf(str, "transport=%s", transport);
    delete[] str;
 
    return true;
}

Зачем освобождать память выделенную под имя и транспорт? Что бы не было утечек.

Если в town() и town(char *) инициализировать name и transport нулями то при выводе вылезут нули.
Исправим:

C++
1
2
3
4
5
6
7
8
9
bool town::Output()
{
    cout << "name="       << (name ? name : "") << endl;
         << "population=" << population         << endl
         << "latitude="   << latitude           << endl
         << "longitude="  << longitude          << endl
         << "transport="  << (transport ? transport : "") << endl << endl;
    return true;
}

Ну и на последок. GetString можно чуток сократить:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
char* GetString(istream& stream)
{
    char* str = new char;
    size_t length = 1;
    while ((stream.get(str[length - 1])) && (str[length - 1] != 'n'))
    {
        char* tmp = new char[length + 1];
        memcpy(tmp, str, length++);
        delete[] str;
        str = tmp;
    }
    str[length - 1] = 0;
    return str;
}

Вроде все. Что узрел, то узрел.

Не по теме:

Портянка хороошая вышла, длииинная.

столкнулся с такой проблемой при удалении массива программа крашиться .
Заранее благодарен.

#include <iostream>
#include <Windows.h>

using namespace std;

void Filling(double *Array, int size) 
{
    for (int i = 1; i <= size; i++)
    {
        cout << "Enter " << i << " element: ";
        cin >> Array[i];
    }
}

void Print(double *Array, int size) 
{
    cout << "Array printing:n";
    for (int i = 1; i <= size; i++)
        cout << "[" << Array[i] << "]";
}

double* NewArray(int size) 
{
    double* Array = new double[size];
    return Array;
}


void Work(double* rez, double* sum, double * sum1, int size) // Функция которая выполняет задание 
{
    for (int i = 1; i <= size; i++)
    {
        rez[i] = ((sum[i] + sum1[i]) / 2);
    }
}

int main()
{
    double a[20], b[20], c[20];
    int n;
    double *x, *y;

    cout << "Enter n:";
    cin >> n;
    if (n > 20)
    {
        cout << "Error, number n must be less than 20. Please enter a valid number(n<=20): ";
        cin >> n;
    }

    cout << "Working with array a:n";
    Filling(a, n);
    Print(a, n);

    cout << "nWorking with array b:n";
    Filling(b, n);
    Print(b, n);

    cout << "nWorking with array c:n";
    Filling(c, n);
    Print(c, n);

    //Создание новых массивов для выполнения задания;
    x = NewArray(n);
    y = NewArray(n);
    
    //Вызов фукции выполняющая задания; 
    Work(x, a, b, n);
    Work(y, b, c, n);

    cout << "nView of the array x after the task is completed:n";
    Print(x, n);
    cout << "nView of the array y after the task is completed:n";
    Print(y, n);

    delete[]x;
    delete[]y;

    system("PAUSE");

    return 0;
}

Тест

You haven’t shown us where paObject is declared … or where it’s (re)initialized …

… but that’s almost certainly the problem.

If you haven’t initialized it to NULL, it might contain random garbage. In which case it won’t evaluate to NULL, and Bad Things will happen.

Similarly, if don’t explicitly reset it to NULL, then Bad Things will also happen.

Of course, we don’t even know if paObject is an array (allocated with «new []») … because you haven’t shown us.

BOTTOM LINE:

1) Make sure paObject is initialized before you use it, and correctly initialized before you re-use it.

2) If you treat it as an array object, make sure it’s initialized as an array object

3) You also need to be careful about the differences between «Object», «Object references» (&Object or Object *), arrays of Objects. In particular, you need to consider when you’re passing a reference to an existing object, or when you’re (perhaps unintentially) creating a new object.

These links should help:

  • http://cplus.about.com/od/learning1/ss/constructors.htm

  • http://www.tutorialspoint.com/cplusplus/cpp_copy_constructor.htm

==================================================================

ADDENDUM:

It sounds like the error Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) is occurring because you’re overwriting your array.

Object* paObject = new Object[1]  // This is really easy to overwrite!

I don’t see where in the code you’re writing to paObject (or writing to some alias of paObject), but I’m almost certain that’s the problem.

IMHO…

char *s = new char[strlen(source) + 1];
...
strcpy_s(s, strlen(s), source);

strlen(s) — вообще за гранью добра и зла и возвращает случайное число, по большому счёту. Потому что s — только что выделенный неинициализированный массив.

Вызов strcpy_s совершенно бессмысленный и неправильный. Бессмысленный, потому что ты только что выделил столько памяти, сколько данных в строке. strcpy_s имеет смысл, если буфер в который ты копируешь — это массив фиксированной длины. Неправильный, потому что даже если ты имел в виду strlen(source), а не strlen(s), то должен был передать strlen(source) + 1, чтобы было куда 0-терминатор скопировать. Кроме всего прочего, strcpy_s ещё и возвращает код ошибки, который имеет смысл проверить.

Лучше всего в этом месте было бы вызвать memcpy(s, source, strlen(source) + 1); или вообще выкинуть s = new char [...]; strcpy_s ... delete [] s; и заменить на s = strdup(source); ... free(s);
Если очень хочется strcpy_s, то хотя бы так: strcpy_s(s, strlen(source) + 1, source);

Исправление этого места починит и delete, потому что delete валится из-за того, что ты поломал heap.


Ошибка пр удалении массива

От:

uzzy

Россия

 
Дата:  09.05.03 15:25
Оценка:

Здравствуйте.
Сидел прогил тихо мирно… на MSVC 6.0 и бум прикол на голову (следует сначала бегло все прочесть, а потом повторно еще раз… так как изложение мыслей будет возможно непоследовтельным
В общем проблема в следующем:

имеется некий core.h файл с своей core.cpp, из которых в результате манимуляций создаются core.dll и core.lib

core.h

...
template<TYPE> int new2dArr (int h, int w, TYPE**& ppArr)
{
   ppArr = new int*[h];
   for (int i = 0; i < h; i++)
      ppArr[i] = new int[w];
}

void __declspec(dllexport) delete2darr (int h, void**& ppBuf);
...

core.cpp

void delete2darr (int h, void**& ppBuf)
{
   for (int i = 0; i < h; i++)
      delete[] ppBuf[i];
   delete[] ppBuf;
   ppBuf = NULL; // вот здесь вываливается ошибка
}

вооот … потом создал модуль io, в котором считывается некий файл, инициализируются две матрицы при помощи new2dArr примерно так :
io.cpp

#include "core.h"
...
int** ppM1 = NULL;
int** ppM2 = NULL;
int   res;
...
res = new2dArr (h1, w1, ppM1);
res = new2dArr (h1, w1, ppM2);
...
// после инициализации, и дальнейшей манипуляции с матрицами ppM2 удалется:
delete2dArr (h1, ppM2); // вот здесь вываливается ошибка
/* манипуляции следующего рода 
ppM1[i][j]++; 
ppM1[i][j]+=a; 
и прочее, то есть не было никаких изменений самих указателей.
*/

модуль io создает io.dll. В некотором файле tex.exe есть следующее: Функции io подгружаются через LoadLibrary + GetProcAddress. Функии core берутся из core.lib. Похоже на извращение, но это такой тест проги и библиотеки… который они не проходят. В общем ошибка такая:
В результате работы test.exe грузится io.dll (удачно), берется адрес некоторой функции load из этой библиотеки (часть кода этой функции представлено в примере io.cpp)… во время исполнения вываливается ошибка там показано в коде.
Более глубокий дебаг показал… что ошибка возникает в ntdll… в результате изучения ошибки наткнулся на ихний комментарий:

_CRTIMP void __cdecl _free_dbg(

#endif  /* _MT */

        void * pUserData,
        int nBlockUse
        )
        ...
        /*
         * If this ASSERT fails, a bad pointer has been passed in. It may be
         * totally bogus, or it may have been allocated from another heap.
         * The pointer MUST come from the 'local' heap.
         */
        _ASSERTE(_CrtIsValidHeapPointer(pUserData));
        ...

Причем данная ошибка возникает при DEBUG линковки… при RELEASE-е все пучком…
можно ли избавиться от подобной ошибки если даже и работает при RELEASE


Re: Ошибка пр удалении массива

От:

WFrag

США

 
Дата:  10.05.03 01:21
Оценка:

3 (1)

Здравствуйте, uzzy, Вы писали:

Удаление, я так понимаю, происходит в функции, находящейся в core.dll. А создание — в io.dll, у них, скорее всего, кучи разные. Т.е указатель при удалении показывает на верную структуру, только в другой куче. В дебаге, видимо, есть праверка на кучу, а в релизе — нет.

U>Причем данная ошибка возникает при DEBUG линковки… при RELEASE-е все пучком…

U>можно ли избавиться от подобной ошибки если даже и работает при RELEASE

Исправить не только можно, но и нужно! Попробуй создавать там же, где и удаляешь — в core.dll.

7. О чем невозможно говорить, о том следует молчать.


Re[2]: Ошибка пр удалении массива

От:

uzzy

Россия

 
Дата:  10.05.03 06:08
Оценка:

Здравствуйте, WFrag, Вы писали:

WF>Здравствуйте, uzzy, Вы писали:

WF>Удаление, я так понимаю, происходит в функции, находящейся в core.dll. А создание — в io.dll, у них, скорее всего, кучи разные. Т.е указатель при удалении показывает на верную структуру, только в другой куче. В дебаге, видимо, есть праверка на кучу, а в релизе — нет.


Да все верно, именно так.

WF>Исправить не только можно, но и нужно! Попробуй создавать там же, где и удаляешь — в core.dll.

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

Все равно спасибо за совет.


Re[3]: Ошибка пр удалении массива

От:

WFrag

США

 
Дата:  10.05.03 06:32
Оценка:

Здравствуйте, uzzy, Вы писали:

U>Здравствуйте, WFrag, Вы писали:


WF>>Здравствуйте, uzzy, Вы писали:


U>

WF>>Удаление, я так понимаю, происходит в функции, находящейся в core.dll. А создание — в io.dll, у них, скорее всего, кучи разные. Т.е указатель при удалении показывает на верную структуру, только в другой куче. В дебаге, видимо, есть праверка на кучу, а в релизе — нет.
U>Да все верно, именно так.

Я, кажется, делал выделение/освобождение в разных .dll, только при этом ставил RuntimeLibrary в Multithreaded DLL/Multithreaded Debug DLL для всех своих .dll. Вроде работало , только не знаю, насколько это законно.

P.S. А вообще, это, имхо, плохой стиль — в одной dll-ке выделять, а вдругой освобождать память…

7. О чем невозможно говорить, о том следует молчать.

Внесены дополнения автора. — ПК.


Re[3]: Ошибка пр удалении массива

От:

WolfHound

 
Дата:  10.05.03 06:37
Оценка:

Здравствуйте, uzzy, Вы писали:

U>Вот этого я не могу… к сожалению… пока не могу … единственно… пока поставил заглушку, чтобы не орала.

Что не можешь? new2darr в core.dll засунуть?

… << RSDN@Home 1.0 beta 6a >>

Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн


Re[4]: Ошибка пр удалении массива

От:

uzzy

Россия

 
Дата:  10.05.03 10:27
Оценка:

Здравствуйте, WolfHound, Вы писали:

WH>Что не можешь? new2darr в core.dll засунуть?

именно, дело в том, что тама все это добро обрамляется

extern "C"

, и при компилировании он ругается на то что мол шаблоны нельзя .
проблема еще в том что подобное наблюдается не только с этими функциями, но и с другими указателями
пример:
в some1.dll создаю CClass1* pStruct1 = new CClass1();, затем возравщаю,
используется в some2.dll
и не может удалиться в some3.dll а очень надо.


Re[5]: Ошибка пр удалении массива

От:

Сомов Александр

Россия

 
Дата:  11.05.03 13:31
Оценка:

Попробуй посмотреть CoTaskMemAlloc. Разумеется придётся писать в классе operator new и operator delete, а то и ещё серьёзнее извращаться, но зато память созданная таким образом может быть освобождена в том же процессе из любого потока, да ещё её и COM умеет маршалить.


Re[4]: Ошибка пр удалении массива

От:

Кодт

Россия

 
Дата:  12.05.03 09:28
Оценка:

Здравствуйте, WFrag, Вы писали:

WF>Я, кажется, делал выделение/освобождение в разных .dll, только при этом ставил RuntimeLibrary в Multithreaded DLL/Multithreaded Debug DLL для всех своих .dll. Вроде работало , только не знаю, насколько это законно.

Это более-менее законно. Менеджер кучи там будет один.

WF>P.S. А вообще, это, имхо, плохой стиль — в одной dll-ке выделять, а вдругой освобождать память…

А ты перепиши свой шаблон:

template<TYPE> int new2dArr (int h, int w, TYPE**& ppArr)
{
// ppArr = new int*[h];
   ppArr = (TYPE**) new_intptrs(h);

   for (int i = 0; i < h; i++)
//    ppArr[i] = new int[w];
      ppArr[i] = new_ints(w);
}

int** __declspec(dllexport) new_intptrs(int h);
int*  __declspec(dllexport) new_ints(int w);

void __declspec(dllexport) delete2darr (int h, void**& ppBuf);

Кстати, а при чем здесь шаблонность, ведь ты однозначно работаешь с int[][]?

(=^.^=) Neko … << RSDN@Home 1.0 beta 6a >>

http://files.rsdn.org/4783/catsmiley.gif Перекуём баги на фичи!

Подождите ...

Wait...

  • Переместить
  • Удалить
  • Выделить ветку

Пока на собственное сообщение не было ответов, его можно удалить.

Возможно, вам также будет интересно:

  • C sources install esd ошибка
  • C emg samsung ошибка камера
  • C crosser коды ошибок
  • C cin обработка ошибок
  • C 4522 ошибка konica

  • Понравилась статья? Поделить с друзьями:
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии