matrix* make_matrix(size_t width, size_t height, size_t k, options opt){
matrix *m= malloc(sizeof(matrix));
if(m==NULL) return NULL;
m->width = width;
m->height = height;
m->k = k;
/*
Since m->data is a int **, it points to int *,
so I have to allocate a number of int *-sized objects to store in it.
*/
//m->data = malloc(sizeof(int *)*height);
m->data = calloc(height, sizeof(int*));
if(m->data == NULL){
free(m);
return NULL;
}
for(size_t i=0; i < height; i++){
//m->data[i] = malloc(sizeof(int)*width);
m->data[i] = calloc(width, sizeof(int));
if(m->data[i] == NULL){
for(size_t j = 0; j < i; j++) free(m->data[j]);
free(m->data);
free(m);
return 0;
}
/*
for(size_t j = 0; j < width; j++){
m->data[i][j] = 0;
}*/
}
return m;
}
I am generating an 2d array and I used malloc instead of calloc. And it turned out that this is going to be a sparse matrix where most of the elements will be zero. So I decided to use calloc. My question is that do I stil need to keep the if statement
if(m->data[i] == NULL){
for(size_t j = 0; j < i; j++) free(m->data[j]);
free(m->data);
free(m);
return 0;
}
I wrote this because malloc doesn't take care of the stack over flow issue so in case of it fails then I have to free those blocks in reverse order. Do I still keep this code with calloc?
Yes. calloc can (and will) fail just as hard as malloc.
This is not a case of "stack overflow", as you are allocating objects on the heap.
The if is required for both malloc and calloc. What it does is that if you fail half-way through your allocation, it will delete the parts you already have allocated. The order is not important.
Related
I am desperately trying to free a 2d int array and can't manage to do so.
I guess there's something wrong when i intialize the array?
Could you please help me out?
int rows = 2;
int cols = 3;
int *mfields = (int *) malloc(sizeof(int) * rows * cols);
int **matrix = (int **) malloc(sizeof(int *) * rows);
for (int i = 0; i < rows; i++) {
matrix[i] = mfields + i * cols;
for(int j=0; j<rows;j++) {
matrix[i][j] = (i+1)*(j+1);
}
}
for (int i = 0; i < rows; i++) {
free((matrix[i]));
}
free(matrix);
Thanks in advance,
Christian
Two chunks of memory are allocated:
int *mfields = (int *) malloc(sizeof(int) * rows * cols);
int **matrix = (int **) malloc(sizeof(int *) * rows);
and therefore two chunks of memory should be freed:
free(matrix);
free(mfields);
Freeing multiple chunks of memory, as this loop does:
for (int i = 0; i < rows; i++) {
free((matrix[i]));
is incorrect, as it passes addresses to free that were never returned from malloc.
Generally, it is not good to implement matrices as pointers-to-pointers. This prevents the processor from doing load prediction and impairs performance. If the C implementation(s) that will be used with the code support variable length arrays, then it is preferable to simply allocate one chunk of memory:
int (*matrix)[cols] = malloc(rows * sizeof *matrix);
If variable length array support is not available, then a program should allocate one chunk of memory and use manual calculations to address array elements. While this is may be more work for the programmer, it is better for performance:
int *matrix = malloc(rows * cols * sizeof *matrix);
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
matrix[i*cols + j] = (i+1) * (j+1);
#define max 40
...
void transpose(int matrix[][max], int* row, int* col)
{
int data[*row][max]; //expression must have a constant value at *row.
for (int i = 0; i < *row; i++)
{
for (int j = 0; j < *col; j++)
{
data[i][j] = matrix[i][j];
}
}
int _col = *row; //this *row works fine.
*row = *col; //also this *row works fine.
*col = _col;
for (int i = 0; i < *row; i++) //this *row is fine too.
{
for (int j = 0; j < *col; j++)
{
matrix[i][j] = data[j][i];
}
}
}
int main()
{
...
if (...)
{
int row = 0, col = 0;
int matrix[30][max];
if (FunctionReadFile(Parameters[0], matrix, &row, &col))
{
...
transpose(matrix, &row, &col);
...
}
...
}
...
return 0;
}
I tried put 'const' before int but it still show this error at [*row], why does this error occured and how to fix it? Does declaring an dynamic array is the only to fix this problem, any possible solution easier?
Your compiler does not support VLA:s, so you should use dynamic allocation:
void transpose(int matrix[][max], int* row, int* col)
{
// Parenthesis matters. This is a pointer to array of size max. Without
// the parenthesis, it would be an array of pointers to int.
int (*data)[max] = malloc(max * sizeof (*data));
for (int i = 0; i < *row; i++)
{
for (int j = 0; j < *col; j++)
{
data[i][j] = matrix[i][j];
}
}
free(data);
}
Do note that I did not check if the allocation failed. You can do that with a simple check. If the pointer is NULL, then the allocation failed. Also, remember to free the memory when you're done with it as shown.
You can use _alloca() or _malloca() in MSVC for stack allocation.
Return Value
The _alloca routine returns a void pointer to the allocated space,
which is guaranteed to be suitably aligned for storage of any type of
object. If size is 0, _alloca allocates a zero-length item and
returns a valid pointer to that item.
A stack overflow exception is generated if the space cannot be
allocated. The stack overflow exception is not a C++ exception; it is
a structured exception. Instead of using C++ exception handling, you
must use Structured Exception Handling (SEH).
Remarks
_alloca allocates size bytes from the program stack. The allocated
space is automatically freed when the calling function exits (not when
the allocation merely passes out of scope). Therefore, do not pass the
pointer value returned by _alloca as an argument to free.
There are restrictions to explicitly calling _alloca in an exception
handler (EH). EH routines that run on x86-class processors operate in
their own memory frame: They perform their tasks in memory space that
is not based on the current location of the stack pointer of the
enclosing function. ...
For example:
void transpose(int matrix[][max], int* row, int* col)
{
int ( *data )[ max ] = _alloca( max * sizeof( *data ) );
for (int i = 0; i < *row; i++)
{
for (int j = 0; j < *col; j++)
{
data[i][j] = matrix[i][j];
}
}
...
Or, with _malloca(), which requires you to call _freea():
void transpose(int matrix[][max], int* row, int* col)
{
int ( *data )[ max ] = _malloca( max * sizeof( *data ) );
for (int i = 0; i < *row; i++)
{
for (int j = 0; j < *col; j++)
{
data[i][j] = matrix[i][j];
}
}
...
_freea( data );
...
I need to allocate contiguous space for a 3D array. (EDIT:) I GUESS I SHOULD HAVE MADE THIS CLEAR IN THE FIRST PLACE but in the actual production code, I will not know the dimensions of the array until run time. I provided them as constants in my toy code below just to keep things simple. I know the potential problems of insisting on contiguous space, but I just have to have it. I have seen how to do this for a 2D array, but apparently I don't understand how to extend the pattern to 3D. When I call the function to free up the memory, free_3d_arr, I get an error:
lowest lvl
mid lvl
a.out(2248,0x7fff72d37000) malloc: *** error for object 0x7fab1a403310: pointer being freed was not allocated
Would appreciate it if anyone could tell me what the fix is. Code is here:
#include <stdio.h>
#include <stdlib.h>
int ***calloc_3d_arr(int sizes[3]){
int ***a;
int i,j;
a = calloc(sizes[0],sizeof(int**));
a[0] = calloc(sizes[0]*sizes[1],sizeof(int*));
a[0][0] = calloc(sizes[0]*sizes[1]*sizes[2],sizeof(int));
for (j=0; j<sizes[0]; j++) {
a[j] = (int**)(a[0][0]+sizes[1]*sizes[2]*j);
for (i=0; i<sizes[1]; i++) {
a[j][i] = (int*)(a[j]) + sizes[2]*i;
}
}
return a;
}
void free_3d_arr(int ***arr) {
printf("lowest lvl\n");
free(arr[0][0]);
printf("mid lvl\n");
free(arr[0]); // <--- This is a problem line, apparently.
printf("highest lvl\n");
free(arr);
}
int main() {
int ***a;
int sz[] = {5,4,3};
int i,j,k;
a = calloc_3d_arr(sz);
// do stuff with a
free_3d_arr(a);
}
Since you are using C, I would suggest that you use real multidimensional arrays:
int (*a)[sz[1]][sz[2]] = calloc(sz[0], sizeof(*a));
This allocates contiguous storage for your 3D array. Note that the sizes can be dynamic since C99. You access this array exactly as you would with your pointer arrays:
for(int i = 0; i < sz[0]; i++) {
for(int j = 0; j < sz[1]; j++) {
for(int k = 0; k < sz[2]; k++) {
a[i][j][k] = 42;
}
}
}
However, there are no pointer arrays under the hood, the indexing is done by the magic of pointer arithmetic and array-pointer-decay. And since a single calloc() was used to allocate the thing, a single free() suffices to get rid of it:
free(a); //that's it.
You can do something like this:
int ***allocateLinearMemory(int x, int y, int z)
{
int *p = (int*) malloc(x * y * z * sizeof(int));
int ***q = (int***) malloc(x * sizeof(int**));
for (int i = 0; i < x; i++)
{
q[i] = (int**) malloc(y * sizeof(int*));
for (int j = 0; j < y; j++)
{
int idx = x*j + x*y*i;
q[i][j] = &p[idx];
}
}
return q;
}
void deallocateLinearMemory(int x, int ***q)
{
free(q[0][0]);
for(int i = 0; i < x; i++)
{
free(q[i]);
}
free(q);
}
I use it and works fine.
I followed few examples on this forum, but it seems like my program still keeps crashing at some point.
All i want to do is just use a void function for memory allocation.
void alloc(int ***matrix, int n)
{
int i = 0;
for( ; i < n; i++)
{
(*matrix)[i] = (int*)malloc(n * sizeof(int));
}
i = 0;
for( ; i < n; i++)
{
int j = 0;
for( ; j < n; j++)
{
(*matrix)[i][j] = i * j;
}
}
}
//-------------------------------------------------------------------
int main()
{
int n;
int **matrix_pp;
printf("Enter n: ");
scanf("%d", &n);
alloc(&matrix_pp, n);
free(matrix_pp);
return 0;
}
You try to use (*matrix)[i] before it's been allocated. Add:
(*matrix) = malloc(n * sizeof(**matrix));
before your for loop.
Note two things here:
1) Don't cast the result of malloc,
2) use sizeof(*pointer) instead of explicitly writing out the type; this way, if you decide to change the type later, it will still work.
Further, you will need to free all of the allocations you have in a loop as a loop as well; otherwise, you have a memory leak.
In debugging my program with Valgrind, I have discovered a memory leak despite what I thought were effective calls to free. First, the code that is allocating the memory and storing it:
row = malloc(sizeof(Row));
row->columns = malloc(sizeof(char*) * headcnt);
row->numcol = 0;
...
row->numcol = colcnt;
rows = realloc(rows, (rowcnt+1) * sizeof(Row));
rows[rowcnt++] = *row;
The code responsible for attempting to free the memory:
void cleanUp(){
int i = 0;
int j = 0;
for (i = 0; i < rowcnt; i++){
for (j = 0; j < rows[i].numcols; j++){
free(rows[i].columns[j]);
}
free(&rows[i]);
}
free(rows);
exit(0);
}
The declaration of Row:
typedef struct {
char** columns;
unsigned short int numcol;
} Row;
Row* rows = NULL;
Worse still, this program sometimes causes a glibc error at free(&rows[i]) that complains of a double free. I am new to C, and would appreciate any pointers (ahem) someone might have.
Doing rows[rowcnt++] = *row; effectively makes a copy of the memory you allocated. Your array rows should be an array of pointers. Also like Oli Chalesworth pointed out, you free for columns should be a single free for all the columns.
rows = malloc(count * sizeof(Row*)); // This is probably done somewhere
row->columns = malloc(sizeof(char*) * headcnt);
row->numcol = 0;
...
row->numcol = colcnt;
rows = realloc(rows, (rowcnt+1) * sizeof(Row*));
rows[rowcnt++] = row;
Now if your cleanup
void cleanUp(){
int i = 0;
int j = 0;
for (i = 0; i < rowcnt; i++){
free(rows[i]->columns);
}
free(rows);
exit(0);
}
Every call to malloc (or realloc) must be matched with a corresponding call to free. If you dynamically allocate an array thus:
int *p = malloc(sizeof(int) * NUM);
You free it like this:
free(p);
Not like this:
for (int i = 0; i < NUM; i++)
{
free(p[i]);
}
It appears that you are doing this incorrectly. I suspect that your cleanup code ought to be:
void cleanUp(){
int i = 0;
int j = 0;
for (i = 0; i < rowcnt; i++){
for (j = 0; j < rows[i].numcols; j++){
free(rows[i].columns[j]); // Free whatever rows[i].columns[j] points to
}
free(rows[i].columns); // Matches row->columns = malloc(sizeof(char*) * headcnt);
}
free(rows); // Matches rows = realloc(rows, (rowcnt+1) * sizeof(Row));
exit(0);
}
Also, there is no way to match the row = malloc(sizeof(Row));. I suspect that your allocation code ought to be:
row->numcol = colcnt;
rows = realloc(rows, (rowcnt+1) * sizeof(Row));
rows[rowcnt].columns = malloc(sizeof(char*) * headcnt);
rows[rowcnt].numcol = 0;
rowcnt++;
Maybe I'm being dense, but isn't this totally unnecessary? All of your memory will be released as soon as the program exits, anyway.