Вы не можете выделить достаточно памяти для каждой строки после выделения для ваших указателей.(у вас проблема с магическим числом )
Перед тем, как решить проблему выделения, давайте рассмотрим общую проблему использования магических чисел в вашем коде.Например, в:
KAB = (double **) malloc(3 * sizeof(double **));//makes array of pointers
for(i = 0; i < 15; i++)
3 & 15
являются магическими числами (то есть, если что-то меняется, и вам нужно отрегулировать пределы выделения или цикла, вам остается выбирать код, чтобы найтикаждое распределение и корректировать каждый предел цикла, каждый размер декларации и т. д.
1014 * Не используйте
магические числа , например
#define ROW 3 /* if you need a constant, #define one (or more) */
#define COL 15
#define NVAL 5
...
for (int ms = 0; ms < ROW; ms++) { /* for each row */
kab[ms] = calloc (COL, sizeof *kab[ms]); /* allocate storage */
В вашем случае выиметь неправильное магическое число в распределении строк, например,
for(i = 0; i < 15; i++)
{
KAB[i] =(double *) malloc(3 *sizeof(double*));
}
Вы выделяете только 3-указатели , но затем пытаетесь выделить и назначить хранилище для 3double*
до 15-указателей . Начиная с KAB[3]
, вы вызываете Неопределенное поведение (поскольку вы уже использовали 3 выделенных указателя), и определенная операция вашего кода завершена.
Использование констант вместо магических чисел помогает избежать этой проблемы. Кроме того, у вас есть одно удобное место для внесения изменений в верхней части исходного файла, если что-либо требует изменения.
Распределение указателей иХранилище для значений
Когда вы выделяете, используя указатель-указатель-на-тип в качестве базового типа, вы должны
- выделитьуказатель для хранения адреса памяти для каждой строки;и
- выделяет хранилище для каждой строки для хранения значений
(вы также должны проверять каждое выделение, malloc, calloc & realloc
может и потерпеть неудачу при исчерпании памяти)
Далее, поскольку вы циклически обнуляете свои значения строк kab
до нуля, просто используйте calloc
для выделения, он одновременно выделяет и устанавливает память в ноль.
(не используйте UPPPER
имена переменных регистра (зарезервированные для констант и макросов) и не используйте camelCase
или MixedCase
переменную - (оставьте их для Java или C ++))
Таким образом, ваше распределение для указателей и строк может выглядеть примерно так:
...
int main (void) {
double **kab = NULL;
/* calloc allocates and initializes memory all zero */
kab = calloc (ROW, sizeof *kab); /* use dereference pointer to
* determine typesize */
if (!kab) { /* validate every allocation by checking the return */
perror ("calloc-kab"); /* handle error */
exit (EXIT_FAILURE);
}
for (int ms = 0; ms < ROW; ms++) { /* for each row */
kab[ms] = calloc (COL, sizeof *kab[ms]); /* allocate storage */
if (!kab[ms]) { /* validate allocation */
perror ("calloc-kab[ms]"); /* handle error */
exit (EXIT_FAILURE);
}
...
(Нет необходимости приводить к возвращению malloc
, это не нужно. См .: DoЯ приведу результат malloc? )
Теперь у вас есть и указатели, и хранилище для ваших значений строк, присвоенных нулю (благодаря использованию calloc
), и вы можете свободно обращаться и заполнятьваши значения, используя двумерную индексную нотацию.
Собрав все части вместе, вы можете сделать что-то похожее на следующее:
#include <stdlib.h>
#include <stdio.h>
#define ROW 3 /* if you need a constant, #define one (or more) */
#define COL 15
#define NVAL 5
int main (void) {
double **kab = NULL;
/* calloc allocates and initializes memory all zero */
kab = calloc (ROW, sizeof *kab); /* use dereference pointer to
* determine typesize */
if (!kab) { /* validate every allocation by checking the return */
perror ("calloc-kab"); /* handle error */
exit (EXIT_FAILURE);
}
for (int ms = 0; ms < ROW; ms++) { /* for each row */
kab[ms] = calloc (COL, sizeof *kab[ms]); /* allocate storage */
if (!kab[ms]) { /* validate allocation */
perror ("calloc-kab[ms]"); /* handle error */
exit (EXIT_FAILURE);
}
for (int i = 0; i < COL; i++ ) { /* for each column */
double value = 0;
for (int n = 0; n < NVAL; n++) /* loop NVAL times */
value += ms * 1.0 + 1; /* build value */
kab[ms][i] = value; /* assign value to kab[ms][i] */
}
}
for (int ms = 0; ms < ROW; ms++) { /* for each row */
for (int i = 0; i < COL; i++) /* for each col */
printf (" %4.1lf", kab[ms][i]); /* output value */
putchar ('\n'); /* tidy up */
free (kab[ms]); /* free row */
}
free (kab); /* free pointers */
return 0;
}
Пример использования / Вывод
Как создать value
для хранения в каждом столбце, немного неинтересно, но для целей примера это хорошо.
$./bin/arraydyn2d
5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0
10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0
15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0
Использование памяти / проверка ошибок
В любом написанном вами коде, который динамически распределяет память, у вас есть 2 отклика относительно любого выделенного блока памяти: (1) всегда сохраняет указатель на начальный адрес для блока памяти, поэтому (2) он может быть освобожден , когда онбольше не требуется.
Крайне важно, чтобы вы использовали программу проверки ошибок памяти, чтобы убедиться, что вы не пытаетесь получить доступ к памяти или писать за пределами / за пределами выделенного блока, пытаться прочитать или создать условное выражениеперейти к неинициализированному значению и, наконец, подтвердить, что вы освобождаете всю выделенную память.
Для Linux valgrind
- нормальный выбор.Для каждой платформы есть похожие проверки памяти.Все они просты в использовании, просто запустите вашу программу через нее.
$ valgrind ./bin/arraydyn2d
==15774== Memcheck, a memory error detector
==15774== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==15774== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==15774== Command: ./bin/arraydyn2d
==15774==
5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0
10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0
15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0
==15774==
==15774== HEAP SUMMARY:
==15774== in use at exit: 0 bytes in 0 blocks
==15774== total heap usage: 4 allocs, 4 frees, 384 bytes allocated
==15774==
==15774== All heap blocks were freed -- no leaks are possible
==15774==
==15774== For counts of detected and suppressed errors, rerun with: -v
==15774== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Всегда подтверждайте, что вы освободили всю выделенную память и нет ошибок памяти.
Посмотрите вещии дайте мне знать, если у вас есть дополнительные вопросы.