Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Achez
0 / 0 / 2
Регистрация: 22.11.2015
Сообщений: 4
#1

Почему меняется содержимое строки? - C++

26.06.2017, 12:57. Просмотров 126. Ответов 2
Метки нет (Все метки)

Я новичок в С++ и пытаюсь написать простейшую игру: игрок ходит по полю и встречает монстров. Но я забуксовал на самых ранних стадиях, постоянно возникают ошибки. В частности, в моём классе ANIMAL (я знаю, что капсом надо писать константы, а не классы, но мне так почему-то легче) есть строка name и с ней возникают самые разные проблемы: я получал сообщение stack corrupted (не помню дословно) в области name, я переделал строку в динамическую и получил исключение при delete[] name. Сейчас я окончательно запутался, программа вся в заплатках, все функции переписаны неоднократно. Но перейду к конкретике. Во-первых, копирование объекта ANIMAL удаётся, но при добавлении объекта в динамическую структуру и чтении из неё повреждается строка name, в неё попадает мусор. Я трассировал программу и обнаружил, что строка меняется при return 0; в функции Fauna::AddObject. Это нелепица какая-то, как возвращение значения влияет на постороннюю переменную? Во-вторых, я получаю assertion failed при выходе из main.

Пока писал это сообщение, опять изменил код (зря я это сделал) и получил совершенно другие ошибки. Во-первых, "программа вызвала срабатывание точки останова" в следующем системном коде:
C++
1
2
3
4
5
6
7
8
9
10
11
12
extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer(
        const void * pUserData
        )
{
        if (!pUserData)
            return FALSE;
 
        if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE))
            return FALSE;
 
        return HeapValidate( _crtheap, 0, pHdr(pUserData) );
}
Конкретно по завершающей фигурной скобке.
Во-вторых, это уже что-то невероятное, при простом копировании ANIMAL a=b; портится name. Что-то у меня не так с копированием name, хотя что можно перепутать в строке strcpy(name, new_name);? Разве что порядок операторов, но это вроде правильно. Теперь собственно код.

Кликните здесь для просмотра всего текста
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
// field.h
class PLAYER
{
    int posx, posy, health, exp, money, str, dex, con, m_int, wis, men;
};
 
//class OBJECT
//{
//protected:
//  int posx, posy;
//public:
//  virtual OBJECT& operator=(OBJECT& master);
//};
 
class ANIMAL // : public OBJECT
{
    // move to class OBJECT
    int posx, posy;
    int exp, health, str, dex, con, m_int, wis, men;
    char* name;
public:
    int SetStats(int new_posx, int new_posy, int new_exp, int new_health, int new_str, int new_dex, int new_con, int new_int, int new_wis, int new_men);
    int SetName(char* new_name);
    void GetStats(int* new_posx, int* new_posy, int* new_exp, int* new_health, int* new_str, int* new_dex, int* new_con, int* new_int, int* new_wis, int* new_men);
    void GetName(char* copyName);
    ANIMAL& operator=(ANIMAL& master);
    ANIMAL();
    ~ANIMAL();
};
 
class Fauna
{
//  OBJECT** m_objects;
    ANIMAL** m_objects;
    int size;
    int max_size;
public:
//  int AddObject(OBJECT newObject);
    int AddObject(ANIMAL newObject);
    Fauna();
    ~Fauna();
//  int GetObject(int pos, OBJECT* copyObject);
    int GetObject(int pos, ANIMAL* copyObject);
    int RemoveObject(int pos);
    int GetSize();
};
 
void Initialize();
void ViewStats(ANIMAL theAnimal);

Кликните здесь для просмотра всего текста
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "field.h"
 
using namespace std;
 
Fauna theFauna;
 
ANIMAL::ANIMAL()
{
    name = new char[50];
}
 
ANIMAL::~ANIMAL()
{
    delete[] name;
}
 
int ANIMAL::SetStats(int new_posx, int new_posy, int new_exp, int new_health, int new_str, int new_dex, int new_con, int new_int, int new_wis, int new_men)
{
    posx = new_posx;
    posy = new_posy;
    exp = new_exp;
    health = new_health;
    str = new_str;
    dex = new_dex;
    con = new_con;
    m_int = new_int;
    wis = new_wis;
    men = new_men;
    return 0;
}
 
void ANIMAL::GetStats(int* new_posx, int* new_posy, int* new_exp, int* new_health, int* new_str, int* new_dex, int* new_con, int* new_int, int* new_wis, int* new_men)
{
    *new_posx = posx;
    *new_posy = posy;
    *new_exp = exp;
    *new_health = health;
    *new_str = str;
    *new_dex = dex;
    *new_con = con;
    *new_int = m_int;
    *new_wis = wis;
    *new_men = men;
}
 
void ANIMAL::GetName(char* copyName)
{
    strcpy(copyName, name);
}
 
int ANIMAL::SetName(char* new_name)
{
    if (strlen(new_name) <= 50)
    {
        strcpy(name, new_name);
        return 0;
    }
    else
    {
        return 1;
    }
}
 
void Initialize()
{
 
}
 
void ViewStats(ANIMAL theAnimal)
{
    char* tempName1 = new char[50];
    theAnimal.GetName(tempName1);
    cout << "Name: " << tempName1<<endl;
    int x, y, exp, hp, str, dex, con, m_int, wis, men;
    theAnimal.GetStats(&x, &y, &exp, &hp, &str, &dex, &con, &m_int, &wis, &men);
    cout << "X pos: " << x << ", Y pos: " << y << endl;
    cout << "Experience: " << exp << ", Health: " << hp << endl;
    cout << "STR: " << str << ", DEX: " << dex << ", CON: " << con << endl;
    cout << "INT: " << m_int << ", WIS: " << wis << ", MEN: " << men << endl;
    delete[] tempName1;
}
 
ANIMAL& ANIMAL::operator=(ANIMAL& master)
{
    posx = master.posx;
    posy = master.posy;
    exp = master.exp;
    health = master.health;
    str = master.str;
    dex = master.dex;
    con = master.con;
    m_int = master.m_int;
    wis = master.wis;
    men = master.men;
    strcpy(name, master.name);
    return *this;
}
 
//int Fauna::AddObject(OBJECT newObject)
//{
//  if (size >= max_size)
//  {
//      OBJECT** newObjects = new OBJECT*[max_size + 100];
//      for (int i = 0; i < max_size; i++)
//      {
//          newObjects[i] = m_objects[i];
//      }
//      max_size = max_size + 100;
//      delete m_objects;
//      m_objects = newObjects;
//  }
//  m_objects[size] = new OBJECT(newObject);
//  size++;
//  return 0;
//}
 
int Fauna::AddObject(ANIMAL newObject)
{
    if (size >= max_size)
    {
        ANIMAL** newObjects = new ANIMAL*[max_size + 100];
        for (int i = 0; i < max_size; i++)
        {
            newObjects[i] = m_objects[i];
        }
        max_size = max_size + 100;
        delete m_objects;
        m_objects = newObjects;
    }
    m_objects[size] = new ANIMAL(newObject);
    size++;
    return 0;
}
//
//Fauna::Fauna()
//{
//  size = 0;
//  max_size = 100;
//  m_objects = new OBJECT*[max_size];
//  for (int i = 0; i < max_size; i++)
//      m_objects[i] = nullptr;
//}
 
Fauna::Fauna()
{
    size = 0;
    max_size = 100;
    m_objects = new ANIMAL*[max_size];
    for (int i = 0; i < max_size; i++)
        m_objects[i] = nullptr;
}
 
Fauna::~Fauna()
{
    while (size)
    {
        delete[] m_objects[size - 1];
        size--;
    }
    delete[] m_objects;
}
 
//int Fauna::GetObject(int pos, OBJECT* copyObject)
//{
//  if (pos < size && pos >= 0)
//  {
//      *copyObject = *(m_objects[pos]);
//      return 0;
//  }
//  else if (pos >= 0)
//      return 1;
//  else
//      return 2;
//}
 
int Fauna::GetObject(int pos, ANIMAL* copyObject)
{
    if (pos < size && pos >= 0)
    {
        *copyObject = *(m_objects[pos]);
        return 0;
    }
    else if (pos >= 0)
        return 1;
    else
        return 2;
}
 
int Fauna::RemoveObject(int pos)
{
    if (pos < size && pos >= 0)
    {
        delete m_objects[pos];
        m_objects[pos] = nullptr;
        size--;
        return 0;
    }
    else if (pos >= 0)
    {
        return 1;
    }
    else
    {
        return 2;
    }
}
 
int Fauna::GetSize()
{
    return size;
}
 
int main()
{
    ANIMAL tempAnimal, tempAnimal2, tempAnimal3;
    int error;
    tempAnimal.SetStats(0, 0, 100, 100, 5, 5, 5, 3, 3, 3);
    tempAnimal.SetName("Rat");
    ViewStats(tempAnimal);
    tempAnimal2 = tempAnimal;
    ViewStats(tempAnimal2);
    /*theFauna.AddObject(tempAnimal);
    error = theFauna.GetObject(0, &tempAnimal2);
    if (!error)
    {
        ViewStats(tempAnimal2);
    }
    else
    {
        cout << "error accessing object";
    }*/
    // error=theFauna.RemoveObject(0);
    if (error)
        cout << "error removing object";
    system("pause");
    return 0;
}


Добавлено через 40 минут
Удалил из main всё, кроме этого:
C++
1
2
3
4
5
    ANIMAL tempAnimal, tempAnimal2, tempAnimal3;
    int error;
    tempAnimal.SetStats(0, 0, 100, 100, 5, 5, 5, 3, 3, 3);
    tempAnimal.SetName("Rat");
    ViewStats(tempAnimal);
В результате при выходе из main debug assertion failed в системном коде:
Кликните здесь для просмотра всего текста
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 operator delete(
        void *pUserData
        )
{
        _CrtMemBlockHeader * pHead;
 
        RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
 
        if (pUserData == NULL)
            return;
 
        _mlock(_HEAP_LOCK);  /* block other threads */
        __TRY
 
            /* get a pointer to memory block header */
            pHead = pHdr(pUserData);
 
             /* verify block type */
            _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)); // <-- вот в этом месте
 
            _free_dbg( pUserData, pHead->nBlockUse );
 
        __FINALLY
            _munlock(_HEAP_LOCK);  /* release other threads */
        __END_TRY_FINALLY
 
        return;
}
Если удаляю delete[] name; из ANIMAL::~ANIMAL() - ошибка исчезает.
Если удаляю ViewStats(tempAnimal); из main - ошибка исчезает.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
26.06.2017, 12:57
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Почему меняется содержимое строки? (C++):

Методы принимают в качестве аргумента простой указатель, как тогда меняется содержимое строки?
Уже &quot;достали&quot; указатели, недавно разбирал односвязный список и там для того,...

Почему меняется размер строки?
Перегруженный оператор который должен возвращать пересечение двух строк. Но...

При повторном обращении к объекту меняется его содержимое
Добрый день! У меня такая странная проблема: есть две одинаковые строчки кода...

Почему символ не меняется
подскажите пожалуйста, написал метод класа для изменения регистра символа, но...

Почему не меняется true/false?
Добрый день! Написал простенькую программу с перегрузкой типов. 24 часовая...

Почему не меняется цвет текста?
Не пойму почему не меняется цвет текста? void FuncThread(HWND hWnd) {...

2
gray_fox
What a waste!
1552 / 1257 / 165
Регистрация: 21.04.2012
Сообщений: 2,634
Завершенные тесты: 3
26.06.2017, 13:48 #2
Цитата Сообщение от Achez Посмотреть сообщение
Во-вторых, это уже что-то невероятное, при простом копировании ANIMAL a=b; портится name.
У вас нет пользовательского конструктора копирования (сами не написали) в классе Animal, а значит генерируется конструктор по умолчанию (компилятором). Конструктор копирования по умолчанию делает простое почленное копирование, соответственно после создание копии экземпляра Animal поле name и в оригинале, и в копии, будут указывать на один и тот же участок памяти. Потом при уничтожении и оригинала, и копии, эта память будет дважды освобождена (delete[] в деструкторе) - вот вам и "порча памяти".
1
Achez
0 / 0 / 2
Регистрация: 22.11.2015
Сообщений: 4
26.06.2017, 14:18  [ТС] #3
Спасибо. Вот, что значит не тренироваться, такую простую вещь забыл.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.06.2017, 14:18
Привет! Вот еще темы с решениями:

Класс,почему не меняется переменная
не могу понять почиму не работает &quot;a1=y;&quot;Помогите пожалуста. //Complex.h...

Почему значение статической переменной не меняется?
У м еня есть класс, в котором есть статическая переменная - ID работника. В...

Почему меняется значение константной переменной?
Доброго времени суток! Возникла такая проблема. Вовремя выполнения функции...

Почему не меняется imin после первой итерации?
void solution() { bool flag; for (int i =m-2; i&gt;=0; i--) { flag...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru