MayaNash, в твоем сообщении об ошибке есть полезная информация:
«Normal block» — это блок памяти, выделенный new, malloc или calloc.
«application wrote to memory after end of heap buffer» — это значит, что
приложение при записи вылезло за пределы буфера.
Ловить такую ошибку можно по-разному.
Во-первых, для начала можно врубить на максимум все возможности отладочной CRT
(debug CRT) и понаставить проверок через каждые 5 строчек кода, статья по теме есть на RSDN:
Обнаружение и локализация утечек памяти
http://rsdn.org/article/vcpp/leaks.xml
Во-вторых, можно временно заменить new/malloc/calloc на VirtualAlloc, сделав «забор»:
первая страница (страницы) памяти под буфер выделяются с атрибутами PAGE_READWRITE
(чтение + запись), а защита самой последней страницы меняется (через VirtualProtect)
на PAGE_NOACCESS (нет доступа). Причем адрес буфера делается таким, чтобы конец
буфера упирался сразу же в страницу с PAGE_NOACCESS. В этом случае при попытке
что-то записать или прочитать за пределами буфера сразу вылетит исключение
STATUS_ACCESS_VIOLATION, ну а далее можно подключать отладчик и смотреть,
где вылезли за границу.
Есть специальные аллокаторы, которые делают всю эту работу (и еще много чего),
конкретные не посоветую, ибо сам пользуюсь такими вещами редко.
Динамический массив в языке C++ имеет два значения: массив переменного размера(т.е. способным к добавлению и удалению в нём элементов) и массив, который мы разместили в куче(heap
). В данном случае вы используете второй вид динамического массива, который сам по себе не меняет своих размеров.
Когда мы хотим считать и записать элементы массива, то у нас стоит выбор какой использовать: статический или динамический(1 или 2). Если количество элементов фиксировано(т.е. мы изначально знаем), то под это отлично подойдёт обычный статический массив, а если же количество элементов вводится с клавиатуры, то мы используем динамический, т.к. по стандарту в языке C++ количество элементов в статическом массиве должно быть известно в момент компиляции, никак не исполнения.
В вашем случае, как я понял, количество элементов фиксировано и равно 10. Тогда и вовсе динамический массив никак не обязателен.
Распишу решение в 3-х видах: с использованием статического и динамического 1-го и 2-го вида.
Статический(неспособный к растягиванию массив, выделенный в stack
):
int main()
{
constexpr int ARR_SIZE = 10;
arr[ARR_SIZE];
for(int i = 0; i < ARR_SIZE; ++i)
std::cin >> arr[i];
//обрабатываем элементы массива
...
return 0;
}
Динамический(неспособный к растягиванию массив в heap
):
#include <iostream>
#include <vector>
int main()
{
int numbersInArray;
std::cout << "Enter number of elements: ";
std::cin >> numbersInArray;
double *arr = new double[numbersInArray];
for(int i = 0; i < numbersInArray; ++i)
cin >> arr[i];
//обрабатываем элементы массива
...
return 0;
}
Динамический(cпособный к растягиванию массив, внутри сам выделен в heap
):
#include <iostream>
#include <vector>
int main()
{
std::vector < double > arr;
int numbersInArray;
std::cout << "Enter number of elements: ";
std::cin >> numbersInArray;
for(int i = 0; i < numbersInArray; ++i)
{
double temp_variable;
cin >> temp_variable;
arr.push_back(temp_variable);
}
//обрабатываем элементы массива
...
return 0;
}
- Remove From My Forums
-
Question
-
Hi,
I wouldn’t be asking this but this problem sometimes occurs directly after the line..
int main(int argc, char **argv[])
{
PWCHAR var = (PWCHAR) malloc ((sizeof(«some\string») * sizeof(WCHAR)) + sizeof(WCHAR));«HEAP CORRUPTION DETECTED after normal block (#60) at 0x00000000xxxxxxxx.»
«CRT detected the application wrote to memory after the end of the heap buffer.»The problem never always occurs the same line and sometimes — usually — when I run through the code step by step (F10) lines are executed but the arrow jumps past lines unless I set a specific breakpoint on the line.
Previously another error that has occurred has been a write to invalid memory. (Error — 0x00000005, ACCESS_DENIED)
The code seems fine when compiled as 32bit (no problems have ever occurred.) but the problems certainly occur when compiled as 64bit.
I would like to know if it is possible that code that has been compiled has somehow been corrupted and is causing this error. I ask this only because I have had the HEAP CORRUPTION error occurred directly after the first run statement.
Thankyou, I really need the help.
Answers
-
Heap corruptions are caused by writing too much to a memory buffer, and that is never a compiler error.
Heap corruptions only manifest the next time you try to do something with the heap itself, like allocate more memory or free a block of memory, so it wouldn’t occur after you overwrite the end of the buffer.
As for the debugger jumping past lines, is your configuration set to release? When it optimises code, it may remove lines completely. The debugger will just not go onto those lines. If you want the best possible debug experience, make sure it is set to the
debug configuration.For a simple way of causing a heap corruption, try the following code. It will always trigger on the free line.
int wmain() { wchar_t *mystr = (wchar_t*)malloc(24); wcscpy(mystr, L"a longer string"); free(mystr); //will break here mystr = nullptr; return 0; }
This causes a heap corruption because obviously the buffer can only store 12 characters (including the null terminator) and you copy more than that to the buffer. The obvious way to fix this is to increase the size of the buffer.
If you want more help though, provide code. Either your actual code or a small sample that reproduces the same issue.
This is a signature
Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts
is to aid in the learning process.Do you want Visual Studio 11 Express to be freely installable on Windows 7 and able to write regular C++ applications? Please vote for
this.
-
Marked as answer by
Friday, May 11, 2012 5:38 AM
-
Unmarked as answer by
Helen Zhao
Friday, May 11, 2012 5:39 AM -
Marked as answer by
Helen Zhao
Thursday, May 17, 2012 3:25 AM
-
Marked as answer by
-
HEAP CORRUPTION DETECTED is usually caused by using bad pointers or indexes in some previously executed code. I.e., not by the line of code that produces the message. Your malloc call just gives the heap checker an opportunity to check for heap damage
caused by previous operations.If you have constructors of global objects they run before main(). So that would be a good place to look for trouble.
-
Marked as answer by
Helen Zhao
Friday, May 11, 2012 5:38 AM -
Unmarked as answer by
Helen Zhao
Friday, May 11, 2012 5:39 AM -
Marked as answer by
Helen Zhao
Thursday, May 17, 2012 3:25 AM
-
Marked as answer by
-
Hi,
I wouldn’t be asking this but this problem sometimes occurs directly after the line..
int main(int argc, char **argv[])
It is probably not related to your problem but this is not a legal definition for main. Your second parameter can be char **argv or char *argv[] but not what you have posted.
{
PWCHAR var = (PWCHAR) malloc ((sizeof(«some\string») * sizeof(WCHAR)) + sizeof(WCHAR));«HEAP CORRUPTION DETECTED after normal block (#60) at 0x00000000xxxxxxxx.»
«CRT detected the application wrote to memory after the end of the heap buffer.»<snip>
Previously another error that has occurred has been a write to invalid memory. (Error — 0x00000005, ACCESS_DENIED)
This inidcates you already have used a bad pointer.
You need to show your actual code since it is obviouls the call to malloc is not that early.
-
Marked as answer by
Helen Zhao
Friday, May 11, 2012 5:38 AM -
Unmarked as answer by
Helen Zhao
Friday, May 11, 2012 5:39 AM -
Marked as answer by
Helen Zhao
Thursday, May 17, 2012 3:25 AM
-
Marked as answer by
-
You’re not helping yourself by mixing narrow string literals in your sizeof() expressions with wide string literals in your wcscpy() calls. However, it doesn’t seem to be the underlying problem — unless your WCHAR
is not a two byte type like wchar_t.You can safely replace
PWCHAR var = (PWCHAR) malloc ((sizeof("some\string") * sizeof(WCHAR)) + sizeof(WCHAR)); wcscpy(var, L"some\string");
with the equivalent
PWCHAR var = (PWCHAR) _wcsdup(L"some\string");
Of course, you should always check for a NULL pointer from malloc() and _wcsdup().
Answering policy: see profile.
-
Marked as answer by
Helen Zhao
Friday, May 11, 2012 5:38 AM -
Unmarked as answer by
Helen Zhao
Friday, May 11, 2012 5:39 AM -
Marked as answer by
Helen Zhao
Thursday, May 17, 2012 3:25 AM
-
Marked as answer by
-
I suggest you to use the _vsnwprintf
function, where you specify the maximum number of characters to write. Also check if you use the “( )” parentheses correctly in
malloc, and your msg is always compatible with arguments.-
Marked as answer by
Helen Zhao
Friday, May 11, 2012 5:39 AM -
Unmarked as answer by
Helen Zhao
Friday, May 11, 2012 5:39 AM -
Marked as answer by
Helen Zhao
Thursday, May 17, 2012 3:25 AM
-
Marked as answer by
Немного расскажу про дебажную кучу, речь пойдет о Visual Studio 2008. В остальных версиях дебажная куча выглядит примерно так же. Про другие компиляторы не знаю.
Основная мысль — дебажная куча отличается от релизной, чтобы облегчить отладку. И, если в дебаге произойдет порча памяти, то ее можно отловить. Visual Studio выдает в таком случае окно с сообщением и пишет в Output что-то вроде
Heap corruption at address.
HEAP[MyProg.exe]: Heap block at 0AC6A400 modified at 0AC6A6EC
past requested size of 2e4
Итак, в чем состоят отличия и каким образом отлавливаются ошибки. Давайте я пример приведу, с примером удобнее.
class CBase
{
public:
int BaseI;
int BaseJ;
};class CDerived : public CBase
{
public:
int DerivedI;
};
int main()
{
CBase *pBase = new CBase;//(1)
pBase->BaseI = 3;
pBase->BaseJ = 4;//(2)
delete pBase;//(3)
return 0;
}
Как будет выглядеть память в точке (1). (Чтобы вывести окно с памятью, выберите Debug->Windows->Memory->Memory1).
0x00984ED8 cd cd cd cd cd cd cd cd fd fd fd fd 00 00 00 00
У меня экземпляр класса CBase расположился по адресу 0x00984ED8. Оба int’а, а это восемь байт, заполнены значением 0xCD, Clean Memory. Это значение по умолчанию.
Дальше четыре байта 0XFD, Fence Memory, она же «no mans land». Это такой заборчик, которым обрамляется свежевыделенная память. Перед адресом 0x00984ED8 стоят точно такие же четыре байта.
Точка (2).
0x00984ED8 03 00 00 00 04 00 00 00 fd fd fd fd 00 00 00 00
Мы записали значения 3 и 4 и они идут одно за другим. Младший байт идет первым, потому что я работают с little endian платформой.
Точка (3)
0x00984ED8 dd dd dd dd dd dd dd dd dd dd dd dd 00 00 00 00
Память после удаления заполняется значениями 0xDD, Dead Memory. После вызова функции HeapFree() будет заполнена значениями 0xFEEEFEEE.
Давайте теперь сымитируем багу и посмотрим как Visual Studio ее поймает. Это реальная бага, я ее упростила до синтетического примера. На самом деле кода было больше и он был размазан по нескольким функциям.
CBase *pBase = new CBase;//(1) pBase->BaseI = 3;
pBase->BaseJ = 4;//(2)
CDerived* pDerived = static_cast<CDerived*>(pBase);
pDerived->DerivedI = 7;//(3)
delete pBase;
Итак, мы стали приводить по иерархии с помощью static_cast’а, вместо dynamic_cast’а. Что в итоге получили. В точках (1) и (2) программа выглядит все также. В точке (3) мы полезли в чужую память и затерли забор.
03 00 00 00 04 00 00 00 07 00 00 00 00 00 00 00
После попытки вызвать delete pBase мы получим сообщение об ошибке, потому что забора нет, а это означает, что мы лазили в чужую память.
HEAP CORRUPTION DETECTED: after Normal block (#68) at 0x008D4ED8.
CRT detected that the application wrote to memory after end of heap buffer.
Еще различия между дебажной и релизной кучами приводят к тому, что программа начинает себя вести по-разному в дебаге и в релизе. Простой пример — дебажная «падает», релизная нет. Очень может быть, что «падение» — это не падение вовсе, а как раз сообщение о порче памяти. Почитайте повнимательнее, что там в окне написано.
Также народ жалуется, что дебажная версия работает сильно меденнее релизной. Причиной этого в том числе может быть дебажная куча. В интернетах пишут, что можно ее в дебаге отключить то ли с помощью переменной окружения _NO_DEBUG_HEAP, то ли NO_DEBUG_HEAP, в единицу ее надо выставить. Я пробовала ее отключить, куча осталась дебажной.
Ссылки по теме:
Win32 Debug CRT Heap Internals
Inside CRT: Debug Heap Management
Memory Management and the Debug Heap (MSDN)
Приведение типов в C++
Эта программа о времени пузырьковой сортировки, вставки и сортировки.
Я запустил свою программу и получил ошибку отладки,
HEAP CORRUPTION DETECTED:after Normal block(#152)at 0x006613C0 CRT Detected
чтобы приложение записывало в память после завершения буфера кучи.
Затем я удаляю последние 3 строки кода (delete [] a; delete [] b; delete [] c) в void part_1(int n)
чтобы это работало. И мой профессор сказал мне: «Ваша программа должна иметь другие ошибки, эти ошибки вызывают
ошибки в операторах удаления. «и я не должен удалять последние 3 строки кода. Я не могу найти его. Пожалуйста, помогите.
// Part-1 : --------------------------- sorting algorithms
void bubbleSort(double *x, int n)
{
// Implement the sorting function using the bubble sort algorithm.
double temp;
for (int j = 0;j < n;j++) {
for (int i = 0;i < n;i++) {
if (x[i] > x[i + 1]) {
temp = x[i];
x[i + 1] = x[i];
x[i + 1] = temp;
}
}
}
}void insertionSort(double *x, int n)
{
// Implement the sorting function using the insertion sort algorithm.
for (int i = 1;i < n;i++) {
double temp = x[i];
int j = 0;
for (j = i - 1;j >= 0 && x[j]>temp;j--) {
x[j + 1] = x[j];
}
x[j + 1] = temp;
}
}int compare_1(const void *a, const void *b) {
double *X = (double *)a;
double *Y = (double *)b;
if (*X > *Y) {
return 1;
}
else if (*X < *Y)
return -1;
return 0;
}
void part_1(int n)
{
srand((unsigned)time(NULL)); // set the seed of the random number generator
double *a = new double[n]; // create 3 arrays with identical contents
double *b = new double[n];
double *c = new double[n];
for (int i = 0; i < n; i++)
a[i] = b[i] = c[i] = rand() / 10000.0;
clock_t begin, end;
double elapsedTime;
cout << "Bubble sort: sorting an array of size " << n << endl;
begin = clock();
bubbleSort(a, n);
end = clock();
elapsedTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout << "Elapsed time = " << elapsedTime << " seconds" << endl << endl;
for (int i = 0; i < n - 1; i++)
if (a[i] > a[i + 1])
{
cout << "Bubble sort : Incorrect resultsnn";
break;
}
cout << "Insertion sort: sorting an array of size " << n << endl;
begin = clock();
insertionSort(b, n);
end = clock();
elapsedTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout << "Elapsed time = " << elapsedTime << " seconds" << endl << endl;
for (int i = 0; i < n - 1; i++)
if (b[i] > b[i + 1])
{
cout << "Insertion sort : Incorrect resultsnn";
break;
}
cout << "Write your statements to sort array c[] using qsort()n";
cout << "qsort: sorting an array of size " << n << endl;
begin = clock();
// #### write your statements to sort array c[] using qsort().
// Define your own compare function.
qsort(c, n, sizeof(double), compare_1);
end = clock();
elapsedTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout << "Elapsed time = " << elapsedTime << " seconds" << endl << endl;
for (int i = 0; i < n - 1; i++)
if (c[i] > c[i + 1])
{
cout << "qsort : Incorrect resultsnn";
break;
}
delete[] a;
delete[] b;
delete[] c;
}
int main()
{
part_1(50000);
system("pause");
return 0;
}
-1
Решение
Эта ошибка возникает из-за повреждения памяти. Повреждение памяти произошло из-за того, что вы записали за предел массива.
Например: если есть массив из 5 целых чисел, например
int array[5];
Вы не должны делать такие вещи, как
int n=4;
array[n+1] = 10; //array out of bound memory write operation
C / C ++ не проверяет массив вне связанной операции. Это разрешает такую операцию без ошибки компиляции. В результате, когда вы запускаете программу, может произойти все что угодно. Поэтому ответственность за проверку таких ошибок лежит на программисте.
Один такой экземпляр найден в вашем коде.
void bubbleSort(double *x, int n)
{
// Implement the sorting function using the bubble sort algorithm.
double temp;
for (int j = 0;j < n;j++) {
for (int i = 0;i < n;i++) {
if (x[i] > x[i + 1]) {
temp = x[i];
x[i + 1] = x[i]; // out of bound write when i=n-1.
x[i + 1] = temp;
}
}
}
}
0
Другие решения
В bubbleSort
Ваш индекс массива выходит за пределы диапазона. Измените функцию, как показано ниже, и вы увидите, что происходит:
void bubbleSort(double *x, int n)
{
// Implement the sorting function using the bubble sort algorithm.
double temp;
for (int j = 0; j < n; j++) {
for (int i = 0; i < n; i++) {
if (i + 1 >= n)
{ // index is out of range
cout << "Bummern";
exit(1);
}
if (x[i] > x[i + 1]) {
temp = x[i];
x[i + 1] = x[i];
x[i + 1] = temp;
}
}
}
}
Там, скорее всего, аналогичные проблемы в других ваших функций сортировки.
0