Хорошо, есть большая путаница, объясняющая, в каком именно порядке должны быть необходимые free()
вызовы, поэтому я попытаюсь прояснить, чего люди пытаются добиться и почему.
Начнем с основ, чтобы освободить память, которая была выделена с помощью malloc()
, вы просто вызываете free()
точно с указателем, который вам дал malloc()
. Итак, для этого кода:
int **a = malloc(m * sizeof(int *));
вам нужно соответствие:
free(a);
и для этой строки:
a[i]=malloc(n * sizeof(int));
вам нужно соответствие:
free(a[i]);
внутри аналогичного цикла.
Что усложняется, так это порядок, в котором это должно происходить. Если вы вызываете malloc()
несколько раз, чтобы получить несколько разных фрагментов памяти, в общем случае не имеет значения, в каком порядке вы вызываете free()
, когда вы с ними покончили. Однако порядок здесь важен по очень конкретной причине: вы используете один фрагмент памяти malloc
ed для хранения указателей на другие фрагменты памяти malloc
ed. Поскольку вы не должны не пытаться читать или записывать память после того, как вы вернули ее с помощью free()
, это означает, что вам придется освобождать фрагменты с их указателями, хранящимися в a[i]
прежде чем вы освободите сам фрагмент a
. Отдельные фрагменты с указателями, хранящиеся в a[i]
, не зависят друг от друга, и поэтому могут быть free
d в любом порядке.
Итак, сложив все это вместе, мы получаем следующее:
for (i = 0; i < m; i++) {
free(a[i]);
}
free(a);
И последний совет: при вызове malloc()
рассмотрите возможность их изменения:
int **a = malloc(m * sizeof(int *));
a[i]=malloc(n * sizeof(int));
to:
int **a = malloc(m * sizeof(*a));
a[i]=malloc(n * sizeof(*(a[i])));
Что это делает? Компилятор знает, что a
— это int **
, поэтому он может определить, что sizeof(*a)
совпадает с sizeof(int *)
. Однако, если позже вы передумаете и захотите char
s, short
s или long
s или что-то еще в своем массиве вместо int
s, или вы адаптируете этот код для последующего использования в чем-то другом, вам придется изменить только одну оставшуюся ссылку на int
в первую процитированную строку выше, и все остальное автоматически встанет на свои места. Это исключает вероятность незамеченных ошибок в будущем.
Удачи!
14.11.2009
sizeof(*a)
14.11.2009sizeof(*a[i])
эквивалентно вашемуsizeof(*(a[i]))
, поскольку запись массива[]
имеет более высокий приоритет, чем*
? 14.11.2009