Форум программистов, компьютерный форум CyberForum.ru

Повреждение кучи - C++

Восстановить пароль Регистрация
 
bytephone32
1 / 1 / 0
Регистрация: 08.08.2012
Сообщений: 21
17.10.2012, 04:30     Повреждение кучи #1
Task2.h

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
#ifndef _TASK2_H_
#define _TASK2_H_
 
#include <iostream>
 
using namespace std;
 
namespace TeamResult
{
    static int fieldCnt = 1;
 
    static double planPctMax;
    static double planPctMin;
    
    typedef struct TR
    {
        char day[32];
        double plan;
        double realDo;
    } FIELD;
 
    typedef TR* DATABASE;
 
    DATABASE CreateTable ( void );
 
    void AddField ( DATABASE );
 
    void ShowTable ( DATABASE );
 
    void SortTable ( DATABASE );
 
    void DeleteTable ( DATABASE );
};
 
 
#endif _TASK2_H_


Task1.cpp

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
#include "Task2.h"
 
#include <memory>
 
TeamResult::DATABASE TeamResult::CreateTable ( void )
{
    return ( DATABASE ) malloc ( sizeof ( TR ) );
}
 
void TeamResult::AddField ( DATABASE db )
{
    puts ( "Input day: " );
    scanf ( "%s", &( db + fieldCnt - 1 )->day );
    puts ( "Input plan: " );
    scanf ( "%f", &( db + fieldCnt - 1 )->plan );
    puts ( "Input actual output: " );
    scanf ( "%f", &( db + fieldCnt - 1 )->realDo );
 
    double planPct = (
        ( db + fieldCnt - 1 )->plan ) /
        ( ( db + fieldCnt - 1 )->realDo ) * 100;
 
    if ( fieldCnt == 1)
    {
        planPctMax = planPct;
        planPctMin = planPct;
    }
    else 
    {
        if ( planPctMax < planPct ) 
            planPctMax = planPct;
        if ( planPctMin > planPct )
            planPctMin = planPct;
    }
 
    db = ( DATABASE ) realloc ( db, ( ++fieldCnt ) * sizeof ( FIELD ) );
}
 
void TeamResult::ShowTable ( DATABASE db )
{
    for ( int i = 0; i < fieldCnt - 1 ; ++i)
        cout<<( db + i )->plan<<endl;
}
 
void TeamResult::SortTable ( DATABASE db )
{
    for(int i = 0; i < fieldCnt - 1; ++i)
        for(int j = i + 1; j < fieldCnt - 1; ++j)
            if( ( ( db + i )->plan) > ( ( db + j )->plan) )
            {
                DATABASE tmp = new FIELD;
                memcpy ( tmp, ( db + i ), sizeof ( FIELD ) );
                memcpy ( ( db + i ), (db + j), sizeof ( FIELD ) );
                memcpy ( ( db + j ), tmp, sizeof ( FIELD ) );
                delete tmp;
            }
}
 
void TeamResult::DeleteTable ( DATABASE db )
{
    free ( db );
}


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
#include "Task2.h"
 
using namespace TeamResult;
 
int main()
{
 
    DATABASE db;
 
    db = CreateTable ( );
 
    AddField ( db );
 
    AddField ( db );
 
/////////////////////////////////////////
 
    AddField ( db );
 
    SortTable ( db );
 
    ShowTable ( db );
 
    DeleteTable ( db );
 
    system ( "pause" );
 
    return 0;
}
После второго раза вызова функции "ОС инициализировала точку останова", которая вызвана повреждением кучи.
C++
1
    db = ( DATABASE ) realloc ( db, ( ++fieldCnt ) * sizeof ( FIELD ) );
Как этого можна избежать?

Когда писал функцию заполнял только поле plan и все работало полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.10.2012, 04:30     Повреждение кучи
Посмотрите здесь:

МНК, повреждение кучи C++
C++ Ошибка о повреждение кучи
Повреждение кучи C++
C++ Повреждение кучи
Ошибка при "сборе мусора" . Повреждение кучи C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11845 / 6824 / 771
Регистрация: 27.09.2012
Сообщений: 16,919
Записей в блоге: 2
Завершенные тесты: 1
17.10.2012, 05:00     Повреждение кучи #2
1)
C++
1
db = ( DATABASE ) realloc ( db, ( ++fieldCnt ) * sizeof ( FIELD ) );
Здесь db - это временный объект. В результате после первого вызова у Вас создается новый кусок памяти, а старый(который создавался в CreateTable()) удаляется, но указатель в функции main будет указывать на старый кусок.
сам указатель db(локальный) выделен на стеке и уничтожается после выхода из области видимости.
Чтобы не менять код внутри функции, передавайте этот параметр по ссылке:
void TeamResult::AddField ( DATABASE &db )

2)"%f" - это float, а у Вас double, поэтому используйте "%lf"
C++
1
scanf ( "%f", &( db + fieldCnt - 1 )->plan );
bytephone32
1 / 1 / 0
Регистрация: 08.08.2012
Сообщений: 21
17.10.2012, 05:19  [ТС]     Повреждение кучи #3
Цитата Сообщение от Croessmah Посмотреть сообщение
Здесь db - это временный объект.
Как это временый? Я в функцию я передаю указатель на обьект, т.е. все что я сделаю с ним в функции касаеться и передаваемого параметра к примеру:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void SomeFunc(int* p)
{
    for ( int i = 0; i < 10; ++i)
        *(p+i) = i;
}
 
int main()
{
    int* k = new int[10];
 
    
    for ( int i = 0; i < 10; ++i)
        cout<<*(k+i);
 
    SomeFunc(k);
 
    for ( int i = 0; i < 10; ++i)
        cout<<*(k+i);
 
    system ( "pause" );
 
    return 1;
}

Цитата Сообщение от Croessmah Посмотреть сообщение
"%f" - это float, а у Вас double, поэтому используйте "%lf"
Это разве влияет на работоспособность? Мне бы сначала память нормально выделить, а потом эти функции будут заменены.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11845 / 6824 / 771
Регистрация: 27.09.2012
Сообщений: 16,919
Записей в блоге: 2
Завершенные тесты: 1
17.10.2012, 05:51     Повреждение кучи #4
Если ссылки не нравятся, тогда можно сделать через указатель:
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
void TeamResult::AddField ( DATABASE  * db )
{
    puts ( "Input day: " );
    scanf ( "%s", &( *db + fieldCnt - 1 )->day );
    puts ( "Input plan: " );
    scanf ( "%lf", &( *db + fieldCnt - 1 )->plan );
    puts ( "Input actual output: " );
    scanf ( "%lf", &( *db + fieldCnt - 1 )->realDo );
 
    double planPct = (
        ( *db + fieldCnt - 1 )->plan ) /
        ( ( *db + fieldCnt - 1 )->realDo ) * 100;
 
    if ( fieldCnt == 1)
    {
        planPctMax = planPct;
        planPctMin = planPct;
    }
    else 
    {
        if ( planPctMax < planPct ) 
            planPctMax = planPct;
        if ( planPctMin > planPct )
            planPctMin = planPct;
    }
 
    *db = ( DATABASE ) realloc ( *db, ( ++fieldCnt ) * sizeof ( FIELD ) );
}
Соответственно и объявление функции нужно поменять. И вызывать данную функцию так
AddField ( &db );

Добавлено через 2 минуты
Цитата Сообщение от bytephone32 Посмотреть сообщение
Как это временый? Я в функцию я передаю указатель на обьект, т.е. все что я сделаю с ним в функции касаеться и передаваемого параметра к примеру:
Вы передаете указатель на объект и можете изменять объект, а чтобы изменить указатель, Вам необходимо передать указатель на указатель (либо ссылку на указатель)

что касается scanf'a то влияет и очень сильно. если сделать "%f" для аргумета double, то в него запишется непонятное число, точнее понятное, но не ожидаемое

Добавлено через 12 минут

Не по теме:

Если что-то не понятно из вышесказанного то пишите. Я просто рассказчик замечательный, описываю слона, а получается крокодил =)))



Добавлено через 16 минут
Чтобы было понятнее, небольшой пример:
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
#include <iostream>
 
void Demo1(int * p1, int * p2){
    std::cout<<"\tDemo1 function\n";
    p2=p1;
}
void Demo2(int ** p1, int **p2){
    std::cout<<"\tDemo2 function\n";
    *p2=*p1;
}
 
int main ()
{
    int Num=10;
    int * pNum1=&Num;
    int * pNum2=NULL;
    std::cout.setf(std::ios_base::hex);
        std::cout<<"Main Function Start"<<std::endl;
    std::cout<<"pNum1 = "<<pNum1<<std::endl;
    std::cout<<"pNum2 = "<<pNum2<<std::endl;
        Demo1(pNum1,pNum2);
    std::cout<<"pNum1 = "<<pNum1<<std::endl;
    std::cout<<"pNum2 = "<<pNum2<<std::endl;
        Demo2(&pNum1,&pNum2);
    std::cout<<"pNum1 = "<<pNum1<<std::endl;
    std::cout<<"pNum2 = "<<pNum2<<std::endl;
    system ("pause");
    return 0;
}
bytephone32
1 / 1 / 0
Регистрация: 08.08.2012
Сообщений: 21
18.10.2012, 19:28  [ТС]     Повреждение кучи #5
Croessmah, но в данном случае память будет выделяться последовательно? Каждая структура будет размещаться сразу же за предыдущей структурой?

Может будет безопаснее создать, так:

C++
1
2
typedef TR* FIELD;
typedef TR** DATABASE;
в DATABASE будет хранится адрес на FIELD на структуру. в Самом FIELD уже адрес самой структуры.

Добавлено через 35 минут
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
#include <memory>
 
 
typedef void* FIELD;
typedef void** DATABASE;
 
static int fieldCnt = 0;
 
struct TR
{
    int i;
    int k;
};
 
// Create table of database
DATABASE CreateTable ( void );
 
//Add field
void AddField ( DATABASE& );
 
int main()
{
    DATABASE db;
 
    db = CreateTable ( );
 
    AddField(db);
    AddField(db);
    AddField(db);
    AddField(db);
 
    cout<<((TR*)db + fieldCnt)->i;
 
    //ShowTable ( db );
 
    //DeleteTable ( db );
 
    system("pause");
    return 0;
}
 
DATABASE CreateTable ( void )
{
    return (DATABASE) malloc ( sizeof ( FIELD ) );
}
 
void AddField ( DATABASE& db )
{
    //aloccated memory for our struct in last field;
    *(db + fieldCnt) = (TR*) malloc ( sizeof ( TR ) );
    //input data
    printf ( "Input day: " );
    scanf ( "%d", &((TR*)db + fieldCnt)->i );
    //
        //как тут нам расширить память для указателей для структур???
    *db = ( FIELD ) realloc ( *db, ( ++fieldCnt + 1 ) * sizeof ( FIELD ) );
}
Добавлено через 20 минут
т.е. в db всегда должен хранится адресс на первый байт массива указателей на структуры, и должен равнятся всегда одному значению, которое ему досталось после выполнения функции CreateTable ( );
Yandex
Объявления
18.10.2012, 19:28     Повреждение кучи
Ответ Создать тему
Опции темы

Текущее время: 20:12. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru