I found a function that frees memory of a matrix:
void free_matrix(int ***matrix, int rows, int cols) {
int row;
if (matrix != NULL && *matrix != NULL) {
for (row = 0; row < rows; row++) {
free((*matrix)[row]);
(*matrix)[row] = NULL;
}
free(*matrix);
*matrix = NULL;
}
}
I call the method like this:
int **my_vector = create_matrix(5, 5);
free_matrix(&my_vector, 5, 5);
I don't quite understand why the author decided to use ***matrix and not **matrix since in my other method where I create the matrix, he is exactly doing that:
void fill_matrix(int **matrix, int rows, int cols) {
int row = 0;
int col = 0;
for (row = 0; row < rows; row++) {
for (col = 0; col < cols; col++) {
matrix[row][col] = ((row + 1) * 10) + col;
}
}
}
int **create_matrix(int rows, int cols) {
int row;
int **matrix = malloc(rows * sizeof(int *));
for (row = 0; row < rows; row++) {
matrix[row] = malloc(cols * sizeof(int));
}
return matrix;
}
There must a reason why suddenly the author decided to use int ***matrix instead of int **matrix.
The author passes the address of the matrix pointer to allow the free_matrix matrix to reset the pointer to NULL in the caller's scope. It is a precaution to prevent accesses to the matrix data after it has been freed, but if the caller made a copy of the matrix pointer, it can still invoke undefined behavior by accessing it via the copy.
As suggested by Olaf, matrices should be implemented as 2D arrays, for much simpler allocation and deallocation:
/* allocating a pointer to a 2D array matrix[rows][cols] filled to 0 */
int (*matrix)[cols] = calloc(sizeof(*matrix), rows);
/* free the matrix */
free(matrix); matrix = NULL;
But, if the sizes are not constant, the syntax required to pass these matrices as function arguments or worse to return them is not so obvious and requires a C99 compliant compiler.
To clarify the dubious advantage of the *** approach, lets look at the more common 2 star solution:
void free_matrix(int **matrix, int rows, int cols) {
int row;
if (matrix != NULL) {
for (row = 0; row < rows; row++) {
free(matrix[row]);
}
free(matrix);
}
}
int main(void) {
int **my_vector = create_matrix(5, 5);
fill_matrix(my_vector, 5, 5);
free_matrix(my_vector, 5, 5);
if (my_vector) {
/* trying to access the freed data will invoke undefined behavior */
}
return 0;
}
In the code above, my_vector is not reset to NULL by free_matrix, so the programmer might try to access it and invoke undefined behavior (crash or anything else), whereas in the posted code, the three star free_matrix would reset my_vector to NULL which can be easily tested.
Related
I have created two matrices in C with the following code:
static allocation method
int data[NMAX][NMAX]; // define NMAX 10 is in header
dynamic allocation method
int** data = (int**) malloc(sizeof(int*) * N);
for (int i = 0; i < N; i++) {
data[i] = (int*) malloc(sizeof(int) * M);
}
now i want to insert data into them with ONE function like so:
int inputMatrix(int **data, int N, int M) { ... }
How can i make the same function declaration work for both array types?
Currently it outputs
expected 'int **' but argument is of type 'int ** (*)[10]'
I have tried creating the static array like this:
int* data[NMAX];
for (int i = 0; i < N; i++) {
data[i] = (int[NMAX]) {};
}
but this code produces a matrix with every line being the same after I input numbers into it
The function inputMatrix will take an array whose elements are pointers to int, so you can create an array that holds pointers to each rows of statically allocated array and pass that to the function.
Construction of the pointer array can be done like this:
int data[NMAX][NMAX];
int *pdata[NMAX]; // array of pointers
for (int i = 0; i < N; i++) {
pdata[i] = data[i]; // the array data[i] is converted to pointers to their first elements here
}
##EDI##
You array pointers
int arr[10][5];
int main(void)
{
srand(time(NULL));
fillArray(5, 10, arr);
printArray(5, 10, arr);
}
See the implementations below https://godbolt.org/z/M6GhrEojn
Do not use arrays of pointers. Use array pointers instead. You remove one level of indirection and you can allocate and free it using one function call. As the whole array is a contignous chunk of memory it is much easier for processor yo use the cache.
void *allocateArray(size_t rows, size_t cols)
{
int (*a)[cols] = malloc(rows * sizeof(*a));
return a;
}
and example usage:
void fillArray(size_t cols, size_t rows, int (*arr)[cols])
{
for(size_t row = 0; row < rows; row++)
for(size_t col = 0; col < cols; col++)
arr[row][col] = rand();
}
void printArray(size_t cols, size_t rows, int (*arr)[cols])
{
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
printf("[%02zu][%02zu]%d,\t", row, col, arr[row][col]);
printf("\n");
}
}
int main(void)
{
size_t cols, rows;
scanf("%zu,%zu", &rows, &cols);
printf("rows:%zu, cols:%zu", rows, cols);
int (*array)[cols] = allocateArray(rows, cols);
srand(time(NULL));
printf("%p\n", array);
if(array)
{
fillArray(rows, cols, array);
printArray(rows, cols, array);
}
free(array);
}
I have an error while trying to release memory of dynamic array.
void Ex()
{
int **Matrix = dyn_matrix_allocation(rows, cols);
.
.
.
free_My_Dyn_Mem(Matrix, rows);
}
void free_My_Dyn_Mem(int **to_Release, int size)
{
int i;
for (i = 0; i < size; i++)
free(to_Release[i]);
//free(to_Release); - If I do this, the program crash.
}
void **dyn_matrix_allocation(int rows, int cols)
{
void **matrix = (void**)calloc (sizeof(int*), cols);
assert(matrix); /*calloc worked*/
int i;
for (i = 0; i < rows; i++)
{
matrix[i] = (int*)calloc(sizeof(int), rows);
assert(matrix[i]); /*calloc worked*/
}
return matrix;
}
after releasing the array itself, I'm trying to release the pointer of pointers (**matrix) then I get an error. debugger shows nothing special. any ideas why?
You made a couple of errors in allocating your dynamic matrix due to unclear definition of your 2D addressing.
First error in allocation, here you choose to create your matrix column dependent allocating an array of cols pointers ti int:
void **matrix = (void**)calloc (sizeof(int*), cols);
Now you should allocate an array of rows integers per each column, but you assign rows arrays of integers:
for (i = 0; i < rows; i++) //Should be for (i = 0; i < cols; i++)
{
matrix[i] = (int*)calloc(sizeof(int), rows);
assert(matrix[i]); /*calloc worked*/
}
Up to now some compilers, or lint or even good debuggers should have told you that you where outside bounds.
But the exception triggers when you free the memory still using the wrong addressing.
void Ex()
{
int **Matrix = dyn_matrix_allocation(rows, cols);
.
.
.
free_My_Dyn_Mem(Matrix, rows); //But you allocated cols pointers...
}
You should pass the array of integer pointers that has a size of cols members, not rows.
Now you release what you allocated out of bounds:
for (i = 0; i < size; i++)
free(to_Release[i]);
The debugger should have complained a lot!
Then you release a now corrupted memory...
free(to_Release);
Your code should be:
#include <stdlib.h>
#include <assert.h>
void free_My_Dyn_Mem(int **to_Release, int size)
{
int i;
for (i = 0; i < size; i++)
free(to_Release[i]);
free(to_Release); //- If I do this, the program crash.
}
int **dyn_matrix_allocation(int rows, int cols)
{
int **matrix = calloc(sizeof(int *), cols);
assert(matrix); /*calloc worked */
int i;
//for (i = 0; i < rows; i++)
for (i = 0; i < cols; i++)
{
matrix[i] = calloc(sizeof(int), rows);
assert(matrix[i]); /*calloc worked */
}
return matrix;
}
void Ex(void)
{
int rows = 100;
int cols = 20;
int **Matrix = dyn_matrix_allocation(rows, cols);
//.
//.
//.
//free_My_Dyn_Mem(Matrix, rows);
free_My_Dyn_Mem(Matrix, cols);
}
Remember that you chosen a columns ordered matrix.
P.S. I forget to add that asserts are normally used for development checks and they can be removed defining the symbol NDEBUG. When you need a permanent control, like an error on allocation return, you should use standard if (condition) ErrorHandling(...);.
I'm trying to generate a matrix of some arbitrary dimensions. I can do it just fine by calling scanf in main and then assigning matrix elements on a row by row basis, but trying to do it in a single function, outside of main, (and only if scanf() is called outside of main) gives me a segfault error:
int **genmat(int nrow, int ncol){
int i,j;
int **mat = (int**) malloc(sizeof(int)*ncol*nrow);
char rowbuff[16];
for(i=0; i < nrow; i++){
INPUT: scanf("%[^\n]%*c",rowbuff);
if(strlen(rowbuff) != ncol){
printf("Error: Input must be string of length %d\n", ncol);
goto INPUT;
}
else{
for(j=0; j < ncol; j++){
if(rowbuff[j] == '1'){
mat[i][j] = 1;
}
else{
mat[i][j] = 0;
}
}
}
}
return(mat);
}
The following works just fine:
int *genrow(int ncol, char *rowbuff){
int i;
int *row = malloc(sizeof(int)*ncol);
for(i=0;i<ncol;i++){
row[i] = rowbuff[i]%2;
}
return(row);
}
with the following in my main function to call genrow() for each row of the matrix:
for(i=0; i < row; i++){
INPUT: scanf("%[^\n]%*c",rowbuff);
if(strlen(rowbuff) != col){
printf("Error: Input must be string of length %d\n", col);
goto INPUT;
}
else{
int *newrow = genrow(col, rowbuff);
for(j=0; j < col; j++){
matrix[i][j] = newrow[j];
}
free(newrow);
newrow = NULL;
}
}
Why is the behavior different in these two contexts?
Dynamically allocated 2D arrays are unfortunately burdensome and ugly in C. To properly allocate one, it is very important that you do so with a single call to malloc, just as you tried to do. Otherwise it won't be a 2D array, but instead some segmented, slow look-up table.
However, the result of that malloc call will be a pointer to a 2D array, not a pointer-to-pointer. In fact, pointer-pointers have nothing to do with 2D arrays whatsoever - this is a widespread but incorrect belief.
What you should have done is this:
int (*mat)[nrow][ncol] = malloc( sizeof(int[nrow][ncol] );
This is an array pointer to a 2D array. This syntax is already a bit burdensome, but to make things worse, it is not easy to pass this array pointer back to main, because it is a local pointer variable. So you would need to use a pointer to an array pointer... and there's no pretty way to do that. It goes like this:
void genmat (size_t nrow, size_t ncol, int (**mat)[nrow][ncol] )
{
*mat = malloc( sizeof(int[nrow][ncol]) );
To ease usage a bit, you can create a temporary pointer to rows, which doesn't require multiple levels of indirection and is therefore much easier to work with:
int (*matrix)[ncol] = *mat[0]; // in the pointed-at 2D array, point at first row
for(size_t r=0; r<nrow; r++) // whatever you want to do with this matrix:
{
for(size_t c=0; c<ncol; c++)
{
matrix[r][c] = 1; // much more convenient syntax than (**mat)[r][c]
}
}
From main, you'll have to call the code like this:
size_t row = 3;
size_t col = 4;
int (*mat)[row][col];
genmat(row, col, &mat);
Example:
#include <stdio.h>
#include <stdlib.h>
void genmat (size_t nrow, size_t ncol, int (**mat)[nrow][ncol] )
{
*mat = malloc( sizeof(int[nrow][ncol]) );
int (*matrix)[ncol] = *mat[0];
for(size_t r=0; r<nrow; r++)
{
for(size_t c=0; c<ncol; c++)
{
matrix[r][c] = 1;
}
}
}
void printmat (size_t nrow, size_t ncol, int mat[nrow][ncol])
{
for(size_t r=0; r<nrow; r++)
{
for(size_t c=0; c<ncol; c++)
{
printf("%d ", mat[r][c]);
}
printf("\n");
}
}
int main (void)
{
size_t row = 3;
size_t col = 4;
int (*mat)[row][col];
genmat(row, col, &mat);
printmat(row, col, *mat);
free(mat);
return 0;
}
Please note that real code needs to address the case where malloc returns NULL.
I assume the problems is withint **mat = (int**) malloc(sizeof(int)*ncol*nrow);
You are trying to allocate the a 2D array right? But this isn't the correct method to allocate the memory. You can't allocate the whole chunk of memory one short.
What you should be doing here is, allocate the memory for all the rows(basically pointer to store the column address) and then for columns
int **mat= (int **)malloc(nrow * sizeof(int *));
for (i=0; i<nrow; i++)
mat[i] = (int *)malloc(ncol * sizeof(int));
Refer this link for more info http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/
I'm new to C and I'm trying to define a matrix using a struct and some methods that will change the int** field of the struct. The matrix is supposed to be dynamically allocated and also resizable in how many rows it can have. When I run the program below and print out the values of the matrix in main, the matrix just have random values, not the ones inserted in genMatrix() and addRow(). What am I doing wrong? Very grateful for any help.
I define the struct like this:
typedef struct matrix {
int** matrix;
int rows;
int cols;
int capacity;
} matrix;
And then have the following methods that should change the field of the struct:
matrix* genMatrix() {
matrix* matrix = malloc(sizeof(matrix));
initMatrix(matrix, 100, 3, 200);
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
int row[] = {i+j, i*j, i-j};
addRow(matrix, row);
}
}
return matrix;
}
void initMatrix(matrix* matrix, int rows, int cols, int capacity) {
matrix->matrix = malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
matrix->matrix[i] = malloc(cols * sizeof(int));
}
matrix->cols = cols;
matrix->rows = rows;
matrix->capacity = capacity;
}
void addRow(matrix* matrix, int* row) {
if (matrix->rows == matrix->capacity) {
matrix->capacity *= 2;
matrix->matrix = realloc(matrix->matrix, matrix->capacity * sizeof(int*));
}
matrix->matrix[matrix->rows++] = row;
}
And in main I call the function genMatrix and then print the result out, but get random values like 32691, -1240670624 etc.
int main() {
matrix* matrix = genMatrix();
}
WHen you try to add a row here:
int row[] = {i+j, i*j, i-j};
addRow(matrix, row);
the data you are adding is a temporary local variable. On the next loop iteration it will get overwritten and then when the loop exits it will go out of scope.
You need to allocate some memory for the new row data, e.g. using malloc:
int * row = malloc(3 * sizeof(int));
row[0] = i+j;
row[1] = i*j;
row[2] = i-j;
addRow(matrix, row);
Don't forget to free all these row allocations later when you're done with the matrix.
You are storing row, a local variable. This pointer ceases to be valid once its scope ends:
for (int j = 0; j < 10; j++) {
int row[] = {i+j, i*j, i-j};
addRow(matrix, row);
}
You must dynamically allocate memory for the row data, too.
row is a local variable.As soon as loop goes for new iteration data gets overwritten and after loop exits data goes out of scope .
So use
int * row = malloc(NumOfRows * sizeof(int));
and then row members.
I am new to C and during my learning I want to return a two dimensional array from a function, so that I can use it in my main program. Can anyone explain me the same with example. Thanks in advance.
It depends how it is implemented. You can either work with just a one-dimensional array where you know the length of each (row) and the next row begins immediately after the previous one. OR, you can have an array of pointers to arrays. The extra cost though is you need to de-reference two pointers to get to one element of data.
// 2D array of data, with just one array
char* get_2d_ex1(int rows, int cols) {
int r, c, idx;
char* p = malloc(rows*cols);
for (r=0; r<rows; r++) {
for (c=0; c<cols; c++) {
idx = r*cols + c; // this is key
p[idx] = c; // put the col# in its place, for example.
}
}
return p;
}
Declare your function as returning a pointer to a pointer. If we use int as an example:
int **samplefunction() {
int** retval = new int*[100];
for (int i = 1; i < 100; i++) {
retval[i] = new int[100];
}
// do stuff here to retval[i][j]
return retval;
}
Here's an example of how you might create, manipulate and free a "2d array":
#include <stdlib.h>
#define ROWS 5
#define COLS 10
int **create_2d_array(size_t rows, size_t cols)
{
size_t i;
int **array = (int**)malloc(rows * sizeof(int*));
for (i = 0; i < rows; i++)
array[i] = (int*)malloc(cols * sizeof(int));
return array;
}
void free_2d_array(int **array, size_t rows, size_t cols)
{
size_t i;
for (i = 0; i < rows; i++)
free(array[i]);
free(array);
}
int main(void)
{
int **array2d = create_2d_array(ROWS, COLS);
/* ... */
array2d[3][4] = 5;
/* ... */
free_2d_array(array2d, ROWS, COLS);
return 0;
}
To create a "2d array"/matrix, all you have to do is create a dynamic array of pointers (in this case int*) of the size of the rows/width:
int **array = (int**)malloc(rows * sizeof(int*));
Then you set each of those pointers to point to a dynamic array of int of the size of the columns/height:
array[i] = (int*)malloc(cols * sizeof(int));
Note that the casts on malloc aren't required, it's just a habit I have.