Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > malloc() ошибка выделения памяти


Автор: kurlyak 26.2.2012, 18:02
Пишу на WinAPI, VS2005.
Есть у меня три файла- один с функцией WinMain(), другой файл с классом, третий файл с заголовком класса. Порядок вызова такой:
Код

//главный файл проекта
CTRLevelLoader g_TRLevelLoader;

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int iCmdShow )
{
.....
Init();
,,,,,,
}

void Init()
{
.....
g_TRLevelLoader.ReadLevelFile("NameLevel.ph1");
.....
}

//файл заголовка класса:
class CTRLevelLoader
{
public:
//структура для файла для крации не приводится
TR2_Level * Level;
void ReadLevelFile(char *szFileName);
};

//файл реализации класса
void ReadLevelFile(char *szFileName)
{
...........

//тут ошибка выделения памяти, функция TR2alloc возвращает NULL
Level->Rooms[i].Lights = (struct tr2_room_light_struct *)TR2alloc(48 * Level->Rooms[i].NumLights);
...........
}

//функция выделения памяти
void *TR2alloc(int size)
{
   void *ReturnValue;

   if (size == 0)
      return(NULL);

   if ((ReturnValue = malloc(size)) == NULL)
      {
    return(NULL);
      }
   memset(ReturnValue, 0x00, size); // initialise it to NULL (better safe than sorry)
   return(ReturnValue);
}


Теперь вобщим о проблеме, а проблема вся в том, что у меня в функции ReadLevelFile() происходит множество вызовов TR2alloc() когда загружается файл уровня игры и выделяется память под нужные структуры. Так вот когда весь уровень из игры загружен (файл уровня 2 мегабайта) в самом конце функции ReadLevelFile() память перестает выделяться и внезапно функция TR2alloc() перестает выделять память. Прямо курьез какой- то - везде в программе память выделялась, а дошел до конца память перестала выделяться bad_alloc типа ошибка.

Пробывал использовать оператор new - то же самое. Я не очень разбираюсь, но функция malloc() выделяет память из кучи, у меня 2 Гига оперативки. 

кроме того есть аналогичная тестовая функция в другом проекте когда весь код класса из функции ReadLevelFile() заключен в WinMain() - то есть весь тот же код но без использования классов- все сделано в одном файле главном проекта. И этот тестовый код работает. А когда начал делать с классами проект, вызывать функцию из функций других пользовательских - то все, память перестает выделяться.

Что это может быть?
Заранее благодарен.

Автор: feodorv 26.2.2012, 18:22
Цитата(kurlyak @  26.2.2012,  18:02 Найти цитируемый пост)
48 * Level->Rooms[i].NumLights

48 - это правильное число? Может, лучше sizeof(struct tr2_room_light_struct) или что-то подобное?

Цитата(kurlyak @  26.2.2012,  18:02 Найти цитируемый пост)
   if ((ReturnValue = malloc(size)) == NULL)

Вызовите GetLastError() и напечатайте ошибку ;)

Автор: kurlyak 26.2.2012, 19:27
Огромное спасибо feodorv!
Как то не додумал примостить GetLastError() в свой код - давно этой функцией не пользовался. Она вернула ошибку. Я по ошибке нашел в интернете как проверить состояние кучи памяти:

Код

char * MyHeapCheck()
{
// Check heap status
   int heapstatus = _heapchk();
   switch( heapstatus )
   {
   case _HEAPOK:
      return(" OK - heap is fine\n" );
      break;
   case _HEAPEMPTY:
      return(" OK - heap is empty\n" );
      break;
   case _HEAPBADBEGIN:
      return( "ERROR - bad start of heap\n" );
      break;
   case _HEAPBADNODE:
      return( "ERROR - bad node in heap\n" );
      break;
   }
}

void MyFunc()
{
//после каждого выделения памяти malloc()
char * szBuff = MyHeapCheck();
}


И потом нашел что в моей структуре я пользуюсь:

Код

char * FileName = {"LEVEL1.PHD"};
strcpy_s(Level->FileName,256, FileName);


После этого происходил сбой в куче памяти. Я поменял на старую функцию strcpy():

Код

typedef struct tr2_level_struct {
char   *FileName;                        
.....
} TR2_Level;    

char * FileName = {"LEVEL1.PHD"};
TR2_Level * Level;
......
strcpy(Level->FileName, FileName);


И все заработало. Но теперь следующий вопрос. После того как все заработало у меня предупреждения компилятора что я использую старую функцию strcpy() вместо новой strcpy_s(). Так вот - как мне сделать что бы в данном мое случае использовать char * FileName = {"LEVEL1.PHD"}; и новую функцию strcpy_s() в которой надо указать длинну строки. Когда я указываю длинну строки strcpy_s(Level->FileName, 256, FileName) то опять происходит сбой кучи памяти. Может поменят так:

Код

typedef struct tr2_level_struct {
char   FileName[256];                        
.....
} TR2_Level;    

char * FileName = {"LEVEL1.PHD"};
TR2_Level * Level;
......
strcpy_s(Level->FileName,256, FileName);


Так работает код, но у меня вопрос есть ли другие варианты с strcpy_s()?

Заранее благодарен за внимание.

Автор: volatile 26.2.2012, 20:27
Цитата(kurlyak @  26.2.2012,  19:27 Найти цитируемый пост)
После того как все заработало у меня предупреждения компилятора что я использую старую функцию strcpy() вместо новой strcpy_s(). 

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

Отключить такую заботу, можно так: (куда нибудь в главную шапку)
#define _CRT_SECURE_NO_WARNINGS

К тому-же strcpy_s() ище и непереносима.  (во всех смыслах  smile )
(это все конечно моё имхо.)

Автор: feodorv 26.2.2012, 21:56
Цитата(kurlyak @  26.2.2012,  19:27 Найти цитируемый пост)
И все заработало.

Это хорошо)))

Но, может, я чего-то не понимаю, но разве так можно:
Цитата(kurlyak @  26.2.2012,  19:27 Найти цитируемый пост)
typedef struct tr2_level_struct {
char   *FileName;                        
.....
} TR2_Level;    
char * FileName = {"LEVEL1.PHD"};
TR2_Level * Level;
......
strcpy(Level->FileName, FileName);

Если, конечно, после TR2_Level->FileName есть какой-то хвост, в который можно записать этот самый FileName, то всё в порядке. Но если он там действительно есть, то в 
Цитата(kurlyak @  26.2.2012,  19:27 Найти цитируемый пост)
strcpy_s(Level->FileName,256, FileName);

достаточно вместо 256 указать размер этого хвоста, и всё должно работать с strcpy_s. Не стоит в strcpy_s задавать абстрактный размер доступного пространства)))

Автор: kurlyak 28.2.2012, 16:05
Понял, спасибо.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)