Функция для динамического выделения матрицы
Я хочу создать функцию для выделения (с malloc
/calloc
) матрицы, объявленной как двойной указатель. Я понял, как работает матрица двойных указателей и как распределить ее с помощью malloc
, но когда я передаю свою матрицу (объявленную в main()
и инициализированную до NULL
), моя программа сработает. Я полагаю, что ошибка связана с моей функцией allocMatrix()
, потому что, если я выделяю матрицу в main
, все работает плавно. Спасибо: -)
Main:
#include <stdio.h>
#include <stdlib.h>
#include "Data.h"
#define ROW 5
#define COL 5
int main(void) {
int i,j, ret;
int nRow, nCol;
int **mat=NULL; // double pointer matrix
nRow = 0;
nCol = 0;
//Insert n of row and columns
printf("Insert n of rows and columns:\n");
scanf("%d %d", &nRow, &nCol);
//Functions to allocate matrix
ret=allocMatrix(mat, nRow, nCol);
printf("Return value: %d\n",ret);
/*
this code works perfect!
mat= malloc(nRow * sizeof(int));
i=0;
while( i < nRow)
{
mat[i]=malloc(nCol * sizeof(int));
i++;
}
*/
//Get Values from stdin
i=0;
while( i < nRow)
{
j=0;
while (j < nCol)
{
printf("Insert value pos[%d,%d]:\n", i, j);
scanf("%d", &mat[i][j]);
j++;
}
i++;
}
//Print values
i=0;
while (i < nRow)
{
j=0;
while( j < nCol)
{
printf("Value pos[%d,%d] is: %d \n", i, j, mat[i][j]);
j++;
}
i++;
}
system("pause");
return EXIT_SUCCESS;
}
allocateMatrix
:
int allocMatrix(int **matrix, int nRow, int nCol)
{
int i;
int ext_status;
//Classic allocation method for matrix
matrix= malloc( nRow * sizeof(int));
if ( matrix != NULL)
{
i=0;
while (i < nRow)
{
matrix[i]= malloc(nCol * sizeof(int));
if( matrix[i] != NULL)
ext_status= 1;
else
ext_status= 0;
i++;
}
}
else
ext_status= 0;
return ext_status;
}
Ответы
Ответ 1
Никогда не используйте указатель на указатель для выделения многомерных массивов. Это широко распространенная, но плохая и неправильная практика. Это не даст вам истинный 2D-массив, и это приведет к более медленному коду из-за фрагментации кучи. Это также делает код сложнее писать, читать и поддерживать, что, в свою очередь, увеличивает потенциал утечек памяти.
Вместо этого правильно распределите 2D-массив в смежных ячейках памяти, например:
int x;
int y;
// store some values in x and y here
int(*matrix)[y] = malloc (sizeof(int[x][y]));
if(matrix == NULL)
{
// error handling here
}
matrix[i][j] = something; // do something with the matrix
free(matrix);
Если вы настаиваете на сохранении этого кода в функции, это будет:
void* allocMatrix (int nRow, int nCol)
{
return malloc (sizeof(int[nRow][nCol]));
}
int(*matrix)[y] = allocMatrix(x, y);
Изменить: объяснение указателей кода и массива.
В строке int(*matrix)[y] = malloc (sizeof(int[x][y]));
, sizeof(int[x][y])
довольно прямолинейный, это просто размер 2D-массива int с размерами x * y. Он использует концепцию массивов переменной длины из стандарта C99, которая позволяет определять размеры массива во время выполнения.
Указатель массива является некоторым особым типом в C, он может указывать на целые массивы, а не только на первый элемент массива, как это делает обычный указатель. Указатель массива, в отличие от обычного указателя, знает размер массива.
Указатель массива записывается как type(*name)[size]
, поэтому, например, указатель на массив из 5 ints будет записан как int(*arr_ptr)[5] = &the_array;
.
При обращении к указанному содержимому указатель массива ведет себя точно так же, как любой указатель, вы получаете доступ к его содержимому с помощью *
. Поэтому *arr_ptr
указывает массив, на который указывает, а (*arr_ptr)[0]
- первый элемент этого массива.
Для многомерных массивов применяются те же правила. Учитывая массив int arr[x][y]
, указатель массива на этот тип будет int(*arr_ptr)[x][y] = &arr;
. Доступ к содержимому *arr_ptr
даст вам двумерный массив, который эквивалентен массиву массивов. (*arr_ptr)[0]
, следовательно, даст первый массив в массиве массивов. Обычное правило для любого имени массива при использовании в выражении состоит в том, что оно "распадается" на указатель на первый элемент. Здесь применяется то же самое, поэтому (*arr_ptr)[0]
также будет таким же, как указатель на первый элемент в первом массиве. И (*arr_ptr)[0][0]
предоставит первый элемент первого массива.
Теперь этот синтаксис (*arr_ptr)[0][0]
выглядит немного трудным для чтения; для получения первого элемента 2D-массива мы используем при написании только arr[0][0]
. Поэтому при объявлении указателя массива есть удобный трюк. Вместо объявления полного и правильного указателя массива: int(*matrix)[x][y]
, указатель массива на двумерный массив размеров x * y, мы вместо этого объявляем его как int(*matrix)[y]
, который является указателем массива на 1D-массив с размером y. Он будет указывать на первый элемент в 2D-массиве, который представляет собой 1D-массив размера y. Мы знаем, что 2D-массив содержит x таких элементов.
И из-за этого трюка мы теперь сможем использовать указатель массива с тем же синтаксисом, что и при доступе к 2D-массиву, а именно matrix[i][j]
, а не к трудночитаемому (*matrix)[i][j]
.
Ответ 2
Проблема заключается в том, что вы передаете mat
самостоятельно функции распределения, которая не может удерживать выделенную память от функции при возврате, поскольку C
использует значение pass-by-value для передачи аргумента функции.
Вам нужно передать указатель на mat
и соответственно присвоить.
Ответ 3
Вы передаете матрицу в allocMatrix
по значению, когда она должна быть по ссылке.
Определите свою функцию как int allocMatrix(int ***matrix, int nRow, int nCol)
и замените matrix
на *matrix
(btw осторожно с синтаксисом индексации, он должен быть (*matrix)[i]
, а не *matrix[i]
).
Это означает, что вы вызовете эту функцию как allocMatrix(&mat, nRow, nCol)
.
Ответ 4
где написано double
, вы можете изменить для вашего типа матрицы
void allocMatrix(double ***matrix, int row, int col){
int i = 0;
*matrix = (double **)malloc(sizeof(double *) * row);
for(i = 0; i < col; i++){
*(*matrix + i) = (double *)malloc(sizeof(double) * col);
}
}
void deallocMatrix(double **matrix, int row){
int i = 0;
for(i = 0; i < row; i++){
free(matrix[i]);
}
free(matrix);
}
когда в основном вы можете использовать их, как это
int main(){
int i = 0, j = 0, k = 0, row = 3, col = 4;
double **myMatrix = NULL;
allocMatrix(&myMatrix, row, col);
for(i = 0; i < row; i++){
for(j = 0; j < col; j++){
myMatrix[i][j] = k++;
printf("%.0lf\t", myMatrix[i][j]);
}
printf("\n");
}
deallocMatrix(myMatrix, row);
return 0;
}
Выход
1 2 3 4
5 6 7 8
9 10 11 12
что может избежать утечек памяти, но, как сказал Lundin, лучше не использовать 2d-массивы
Никогда не используйте указатель на указатель для выделения многомерных массивов. Это широко распространенная, но плохая и неправильная практика. Это не даст вам истинный 2D-массив, и это приведет к более медленному коду из-за фрагментации кучи. Это также делает код сложнее писать, читать и поддерживать, что, в свою очередь, увеличивает потенциал утечки памяти. Вместо этого правильно распределите 2D-массив в смежных ячейках памяти
[]