Использование malloc
Во-первых, ваш код в порядке, но это не значит, что он не содержит проблем.Во-первых, давайте посмотрим, как вы используете malloc
, например,
int** answer = (int**) malloc(sizeof(int*) * rows1);
Нет необходимости разыгрывать возврат malloc
, это не нужно.Смотрите: Я разыгрываю результат malloc? .Далее, и это больше стиля, чем что-либо еще, '*'s
, показывающий уровни косвенности, идет с переменной, а не с типом.Почему?
int* a, b, c;
Это, конечно, не объявляет 3-указатели на int.Он объявляет один указатель и два целых числа, например
int *a, b, c;
При установке размера шрифта для выделения, если вы всегда используете сам указатель с разыменованным указателем, вы никогда не получите неправильный размер шрифта, например
int **answer = malloc (rows1 * sizeof *answer);
Если вы выделите его, вы должны его подтвердить, и вам решать free
это
Для каждого выделения вы должны проверить, что указатель возвращенна malloc, calloc, realloc
не NULL
.Функции распределения не работают, когда у вас заканчивается память.Всегда проверяйте.
В любом написанном вами коде, который динамически распределяет память, у вас есть 2 обязанности относительно любого выделенного блока памяти: (1) всегда сохраняйте указатель на начальный адрес для блока памяти, таким образом, (2) он может быть освобожден , когда он больше не нужен.
Крайне важно, чтобы вы использовали программу проверки ошибок памяти, чтобы убедиться, что вы не пытаетесьполучить доступ к памяти или выполнить запись за пределами / за пределами выделенного блока, попытаться прочитать или основать условный переход на неинициализированном значении и, наконец, подтвердить, что вы освобождаете всю выделенную память.
Для Linux valgrind
- нормальный выбор.Для каждой платформы есть похожие проверки памяти.Все они просты в использовании, просто запустите вашу программу через нее.
Всегда подтверждайте, что вы освободили всю выделенную память и что ошибок памяти нет.
Просто объявите функцию дляосвободите ваши массивы указателей и передайте каждому из них функцию free вместе с количеством строк до выхода из вашей программы, например,
void freearr (int **a, int rows)
{
for (int i = 0; i < rows; i++)
free (a[i]);
free (a);
}
и
...
fclose(fp);
freearr (square, rows1);
freearr (square2, rows2);
freearr (answer, rows1);
return 0;
Почему я получаю: ОШИБКА: AddressSanitizer: переполнение динамического буфера на адресе .....?
Это больше результат того, что ваш компилятор сказал вам перепроверить использование границ массива.В частности, здесь, скорее всего, это результат:
int answer = malloc (rows1 * sizeof *asnwer);
for (int i = 0; i < rows1; i++)
answer[i] = malloc (columns2 * sizeof *answer[i]);
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < columns2; j++) {
for (int k = 0; k < rows2; k++) {
ans += square[i][k] * square2[k][j];
}
answer[i][j] = ans;
Примечание: как answer
измеряется с использованием границ rows1
и columns2
, тогда как square
выделяется с использованиемrows1, columns1
и square2
с rows2, columns2
.Ваш компилятор может помочь вам определить потенциальное переполнение кучи, отслеживая переменные, используемые для определения размера выделения.В этом некоторые компиляторы лучше других.
Если компилятор не может определить, какие ограничения вы используете для итерации по вашему массиву, он может выдать предупреждение о потенциальном переполнении буфера.(все, что должно волновать, это значение используемых пределов, но, как я сказал, некоторые компиляторы лучше, чем другие ...)
После выделения с ограничениями, изложенными выше, вы затем переходите к итерациимассивы указателей с различными ограничениями, которые были прочитаны в отдельные и не связанные переменные.Использование rows1, columns2
для итерации по square, square2 & answer
.Подумайте об этом, хотя вы знаете columns1 == columns2
, тогда компилятор не имеет на это гарантии.То же самое для rows2 == rows1
.
Ваш компилятор не гарантирует, что использование rows1
с square2
не запишет за пределы его выделенного размера.Также нет гарантии, что использование columns2
не нарушит границы square
.Ваш тест columns1 != rows2
не дает никаких гарантий для rows1 == columns2
или rows1 == rows2
и т. Д. *
Итак, все используемые ограничения белого цвета в порядке - ваш компилятор не может гарантировать это и предупреждает.Однако, поскольку вы утомительно выбрали свой код, чтобы знать, что ваши ограничения хороши, все, что требуется, - это доля секунды, чтобы подтвердить его, например,
$ valgrind ./bin/read2darrq dat/arr_2-3x3.txt
==29210== Memcheck, a memory error detector
==29210== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==29210== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==29210== Command: ./bin/read2darrq dat/arr_2-3x3.txt
==29210==
90 96 102
216 231 246
342 366 390
==29210==
==29210== HEAP SUMMARY:
==29210== in use at exit: 0 bytes in 0 blocks
==29210== total heap usage: 13 allocs, 13 frees, 732 bytes allocated
==29210==
==29210== All heap blocks were freed -- no leaks are possible
==29210==
==29210== For counts of detected and suppressed errors, rerun with: -v
==29210== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)