Что вызывает сбой моей программы при выполнении «free (ppMapData [i])»?

Я попытался сделать динамический 2D-массив charследующим образом:

char** ppMapData = (char**)malloc(sizeof(char*)*iMapHeight);
for (int i=0; i< iMapHeight; i++)
{
    ppMapData[i] = (char*)malloc(sizeof(char)*iMapWidth);
    //do something
}

// do something

for (int i=0; i<iMapHeight; i++)
    free(ppMapData[i]);
free(ppMapData);

Это выглядит хорошо для меня; однако, когда дело доходит до выполнения, моя программа вылетает в строке, которая вызывает free(ppMapData[i]). Есть идеи, в чем тут проблема. Большое спасибо.

11.12.2008 21:51:58
Каково значение i, когда ваша программа падает? Это соответствует?
Frosty 12.12.2008 13:42:19
11 ОТВЕТОВ

На первый взгляд, освобождение выглядит хорошо. Следующее, что вы должны проверить, это убедиться, что вы не превысили ни один из этих массивов после конца. Это может вызвать проблемы с системами выделения памяти.

Если вы используете Visual Studio, вы можете вызвать _CrtCheckMemory, чтобы убедиться, что вы ничего не теряете. Этот вызов работает только в сборке DEBUG.

8
11.12.2008 21:55:28

Вы проверяли значения NULL после malloc?

4
11.12.2008 21:55:49
Не вызовет этой проблемы (на любом используемом мной компиляторе) - это действительно для освобождения NULL, и если первое выделение было NULL, оно вылетит намного раньше (когда результат второго выделения был назначен NULL [0] ). Ofc может быть что-то странное, например, если 0 является записываемым адресом на оборудовании.
Steve Jessop 11.12.2008 23:38:24

Вы отметили свой вопрос «C ++». Почему бы не использовать соответствующие конструкции C ++ вместо этого? Например, vector<vector<char> >или даже (могу ли я предложить) vector<string>?

РЕДАКТИРОВАТЬ Ну хорошо, это vector<string>, вероятно, не то, что вы хотите. Тем не менее, я настоятельно рекомендую решение на C ++.

2
11.12.2008 21:56:12

Я не вижу проблемы на первый взгляд, но это не значит, что ее там нет. Пожалуйста, убедитесь, что вы не делаете двойное освобождение, освобождая память где-то в разделе «сделать что-то».

2
11.12.2008 21:56:59

Если это двумерный массив с фиксированным размером в обоих измерениях, я всегда предпочитаю:

char* array = (char*)malloc(iMapHeight*iMapWidth);

И доступ к нему с помощью:

char val = array[height*iMapWidth + width];

Оберните это в макрос, если вы предпочитаете:

#define GET_VAL(h, w) array[h*iMapWidth + w]

Умножение будет быстрее, чем разыменование двух указателей, чтобы найти значение.

2
11.12.2008 22:30:06

Несколько возможных ответов:

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

  2. Вы уверены, что не изменяете значения в ppMapData? Попытка освободить указатель, который никогда не был выделен, вообще плохая вещь.

  3. Каково значение i, когда ваша программа потерпела крах? Это соответствует? зная, что это будет полезно и, возможно, поучительно

Некоторые стилистические комментарии:

  • Проверьте возвращаемое значение malloc (оно будет NULL, если не получится).

  • Не приводите возвращаемое значение malloc (если вы действительно пишете C, а не C ++).

2
12.12.2008 13:41:43
Просто чтобы быть точным, важная информация malloc как до, так и после выделенного блока.
Eyal 12.12.2008 19:18:28

Является ли iMapHeight / iMapWidth постоянным? Если нет, они могут быть изменены между ними, вызывая проблемы. Также, как предлагают другие, проверьте на null возвращаемые malloc.

-1
17.12.2008 21:20:19

Предполагая, // сделать что-то больше, чем просто комментарий, вынуть

// сделай что-нибудь

код и посмотреть, если он все еще падает. Добавляйте вещи обратно по одному, пока они снова не рухнут

0
17.12.2008 21:52:23

Из кода в вопросе не похоже, что вы проверяете, успешно ли malloc. Убедитесь, что malloc не возвращает NULL в качестве первого шага. Возможно, это не ваша проблема, поскольку

//do something

вероятно, использует новую выделенную память, но если это не так, malloc может потерпеть неудачу без вашего ведома, если вы не разыменовываете со свободной. (Я знаю, что маллок вряд ли потерпит неудачу, если вы не разрабатываете для среды с низким объемом памяти, но это все еще стоит проверить)

Во-вторых, какова iценность, когда он падает, это почти то же самое?

Наконец, вы можете достать нам дамп ядра, проблему будет легче выявить :)

0
17.12.2008 22:13:14

По-прежнему происходит сбой, если вы удаляете код "сделать что-то"? Если это не так, это, вероятно, означает, что вы нарушаете память в коде «что-то делать», и именно в этом заключается ваша ошибка, а не в коде выше.

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

0
17.12.2008 22:18:09

В качестве альтернативы Joemucchiello,

char **ppMapData = malloc(iMapHeight * sizeof(char*) +
                          iMapHeight * iMapWidth * sizeof(char)));

for (int i = 0; i < iMapHeight; i++) {
    ppMapData[i] = (char *)(ppMapData + iMapHeight) + i * iMapWidth;
    /* do something */
}

/* do something */

free(ppMapData);

Это делает одно большое выделение, содержащее как массив-указателей, так и массив-массив-символов.

Однако, как утверждают многие другие, код, который вы разместили, работает нормально. В // do somethingсегменте " " должно быть что-то, что вы не опубликовали, что вызывает эту ошибку.

Например, если вы уже освободили ppMapData[i], вы не можете освободить его снова. Некоторые люди избегают этого, устанавливая ppMapData[i] = NULLсразу же после любого free(ppMapData[i]): это работает, потому что a free(NULL)является законным и ничего не делает. Я предпочитаю не делать этого, а исправлять любой дизайн, который привел бы вас к двойной ситуации.

0
17.12.2008 22:24:40