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.
Related
I'm trying to free the malloc that is generated with a not fixed number of arrays.
char ** get_moves(){
// some code
char **moves = malloc(sizeof(char *) * k); // 'k', could ranges between 1~9
if (!moves){
return NULL;
}
for(int i = 0; i < k; i++){
moves[i] = malloc(82);
if (!moves[i]) {
free (moves);
return NULL;
}
// more code
return moves;
}
int main(){
//some code
char **res = get_moves(some_input);
//more code
for (int i = 0; i < (sizeof(res)/sizeof(res[0)); i ++){
free(res[i]);
}
free(res);
}
In one of the inputs to get_move, res should have 2 arrays but the sizeof(res)/sizeof(res[0) gives me just 1.
How is the proper way to handle this?
The only way is to keep track of the element count of the array, if you don't want to pass it to every function when passing the array, you can combine both pieces of information in a struct, like here
#include <stdlib.h>
struct ArrayOfStrings
{
int count;
char **data;
};
struct ArrayOfStrings get_moves()
{
struct ArrayOfStrings result;
char **moves;
// some code
result.count = 0;
result.data = malloc(sizeof(char *) * k); // 'k', could ranges between 1~9
if (result.data == NULL)
return result;
result.count = k;
moves = result.data;
for (int i = 0; i < k; i++)
{
moves[i] = malloc(82);
if (moves[i] == NULL)
{
/* also free succesfully allocated ones */
for (int j = i - 1 ; j >= 0 ; --j)
free(moves[j]);
free(moves);
}
result.count = 0;
result.data = NULL;
return result;
}
// more code
return result;
}
int main(){
//some code
struct ArrayOfStrings res = get_moves(some_input);
//more code
for (int i = 0; i < res.count ; i ++)
free(res.data[i]);
free(res.data);
return 0; // you should return from main.
}
sizeof is not for the length of an object's content but for the size of a data type, it is computed at compile time.
So in your case
sizeof(res) / sizeof(res[0]) == sizeof(char **) / sizeof(char *) == 1
since sizeof(char **) == sizeof(char *) it's just the size of a pointer.
sizeof(res)
Returns the sizeof(double-pointer);
So if you intend to get the number of pointers stored then you might not get this by doing what you are doing.
You need to do something like
for(i=0;i<k;i++) /* As I see you are allocating k no of pointer Keep track of it*/
free(res[i]);
free(res);
res is in fact not an array of arrays of char type. Instead it is a pointer to pointer to char type. sizeof(res) will give you the size of char**. You need to keep track of the number of allocations.
Since the maximum number of arrays to allocate is small (9), you can simplify your code by allocating the maximum number. Fill the unused elements with NULL:
#define MAX_K 9
char **moves = malloc(sizeof(char *) * MAX_K);
for(int i = 0; i < k; i++){
...
}
for(int i = k; i < MAX_K; i++){
moves[i] = NULL;
}
To deallocate, just ignore the NULL pointers:
for (int i = 0; i < MAX_K; i ++){
if (res[i])
free(res[i]);
}
free(res);
I want to define a 2D array of very big size. But it is giving me segmentation fault?
#include <stdio.h>
int main () {
int i;
int temp[4000][5000];
for (i = 0; i < 5; i++)
{
printf ("Hello World\n");
}
}
Can anyone please suggest me some other way? Is there some problem with memory initialization? Thanks in advance
You can allocate the whole table in only one array but you won't be able to access array data with indices using two square brackets:
int * temp = malloc(4000*5000*sizeof(int));
to access the element (i,j) where previously you wrote temp[i][j], now you should now compute the index the following way:
temp[i*5000+j];
and do not forget to free the memory allocated for your table afterward:
free(temp);
int temp[4000][5000];
That's a VERY BIG array, way bigger than the normal size of stack, you get a segmentation fault because of stack overflow. Consider using dynamic allocation instead.
You need to use dynamic allocated arrays for such big arrays.
Try:
int* temp[4000];
for(i = 0; i < 4000; ++i) temp[i] = malloc(5000 * sizeof(int));
...
for(i = 0; i < 4000; ++i) free(temp[i]).
Whole program with error checking:
int main () {
int i, j;
int* temp[4000];
for (i = 0; i < 4000; ++i)
{
temp[i] = malloc(5000 * sizeof(int));
if (temp[i] == NULL)
{
for (j = 0; j < i; ++j) free(temp[i]);
exit(1);
}
}
for (i = 0; i < 5; i++)
{
printf ("Hello World\n");
}
for (i = 0; i < 4000; ++i) free(temp[i]);
}
Here you can find function which would use single malloc call to allocate two dimension array.
And simpler version of my own:
int main () {
int i, j;
int* temp[4000];
int* array = malloc(4000 * 5000 * sizeof(int));
if (malloc_tmp == NULL) exit(1);
for (i = 0; i < 4000; ++i)
{
temp[i] = array + (i * 5000);
}
for (i = 0; i < 5; i++)
{
printf ("Hello World\n");
}
free(temp[0]);
}
I am struggling with an algorithm to print numbers between 1 and a dynamic variable n into an int.
int n = // dynamic value
int i = 0;
int output[n];
for(i = 0; i < n; i++) {
output[i] = i;
}
However, as n is dynamic, the code won't compile.
Any help would be much appreciated - thanks in advance.
You need to allocate a buffer, or dynamic-sized array, with malloc:
int n = // whatever
int i = 0;
int* output = NULL;
// Allocate the buffer
output = malloc(n * sizeof(int));
if (!output) {
fprintf(stderr, "Failed to allocate.\n");
exit(1);
}
// Do the work with the array
for(i = 0; i < n; i++) {
output[i] = i;
}
// Finished with the array
free(output);
output is a pointer to the beginning of the buffer you allocated, and you can treat it as an array of n ints.
When you're finished with the array, you need to de-allocate the memory with free.
This should work:
int n = // whatever
int i = 0;
int* output = (int*)malloc(sizeof(int)*n);
for(i = 0; i < n; i++) {
output[i] = i;
}
Don't forget to free(output); when you don't need it anymore.
EDIT: Made it C.
If 'n' is changing during runtime, then you could use malloc like suggested in the comments. Then check if you need more space, then automatically realloc more space should it be needed
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.
I d love to know how I can allocate data through a function, and after the function is returned the data is still allocated. This is both for basic types (int, char**) and user defined types. Below are two snipsets of code. Both have the allocation within the function though after the return the allocation goes.
int* nCheck = NULL;
int nCount = 4;
CallIntAllocation(nCheck, nCount);
nCheck[1] = 3; // Not allocated!
...
CallIntAllocation(int* nCheck, int nCount)
{
nCheck = (int*)malloc(nCount* sizeof(int));
for (int j = 0; j < nCount; j++)
nCheck[j] = 0;
}
The same behaviour for as before though for user defined type:
typedef struct criteriatype
{
char szCriterio[256];
char szCriterioSpecific[256];
} _CriteriaType;
typedef struct criteria
{
int nCount;
char szType[128];
_CriteriaType* CriteriaType;
} _Criteria;
...
_Criteria* Criteria;
AllocateCriteria(nTypes, nCriteria, Criteria);
...
void AllocateCriteria(int nTypes, int nCriteria[], _Criteria* Criteria)
{
int i = 0;
int j = 0;
Criteria = (_Criteria*)malloc(nTypes * sizeof(_Criteria));
for (i = 0; i < nTypes; i ++)
{
// initalise FIRST the whole structure
// OTHERWISE the allocation is gone
memset(&Criteria[i],'\0',sizeof(_Criteria));
// allocate CriteriaType
Criteria[i].CriteriaType = (_CriteriaType*)malloc(nCriteria[i] * sizeof(_CriteriaType));
// initalise them
for (j = 0; j < nCriteria[i]; j ++)
memset(&Criteria[i].CriteriaType[j],'\0',sizeof(_CriteriaType));
}
}
Any ideas? I think I need to pass the pointers as a reference, though how can i do so?
Thanks in advance,
Sunscreen
using return?
Criteria *
newCriteria() {
Criteria *criteria = malloc(..);
...
return criteria;
}
/* the caller */
Criteria *c1 = newCriteria();
Criteria *c2 = newCriteria();
EDIT
the caller is responsible for calling free()
You have 2 possible solutions:
int *CallIntAllocation(int nCount)
{
int *nCheck = (int*)malloc(nCount* sizeof(int));
for (int j = 0; j < nCount; j++)
nCheck[j] = 0;
return nCheck;
}
int* nCheck = NULL;
int nCount = 4;
nCheck = CallIntAllocation(nCount);
or you should pass a pointer to int* if you want to alloc array:
void CallIntAllocation(int **nCheck, int nCount)
{
*nCheck = (int*)malloc(nCount* sizeof(int));
for (int j = 0; j < nCount; j++)
*nCheck[j] = 0;
}
int* nCheck = NULL;
int nCount = 4;
CallIntAllocation(&nCheck, nCount);
To answer your question directly:
int* nCheck = NULL;
int nCount = 4;
CallIntAllocation(&nCheck, nCount);
nCheck[1] = 3; // allocated!
...
void CallIntAllocation(int** pnCheck, int nCount)
{
int* nCheck = NULL;
nCheck = (int*) malloc(nCount * sizeof(*nCheck));
for (int j = 0; j < nCount; j++)
nCheck[j] = 0;
*pnCheck = nCheck;
}
but I would suggest this in stead:
nCheck = CallIntAllocation(nCount);
nCheck[1] = 3; // allocated!
...
int *CallIntAllocation(int nCount)
{
int * nCheck
nCheck = (int*) malloc(nCount * sizeof(*nCheck));
for (int j = 0; j < nCount; j++)
nCheck[j] = 0;
return nCheck;
}
The reason it is not working is that function arguments in C are copied. So, nCheck = NULL in the outside context, you pass it into the CallIntAllocation function and a copy is made. The CallIntAllocation defines it's local copy of nCheck to be the return of the malloc call. But the outer copy is not updated -- it still points at NULL.
The simplest solution is to return the new pointer value and assign it as already suggested by several people.
When you have functions that need to modify data structures, you need to pass around a pointer to them, rather than copies of them, so that the function can modify what the pointer points at. The same principle applies here, although the data structure you want to modify is itself a pointer.
So another solution would be for CallIntAllocation to take a pointer-to-a-pointer which would let you modify where the pointer points, and also dereference it:
CallIntAllocation(int** nCheck, int nCount)
{
*nCheck = (int*)malloc(nCount* sizeof(int));
for (int j = 0; j < nCount; j++)
(*nCheck)[j] = 0;
}
and invocation
CallIntAllocation(&nCheck, nCount);
Clearly in this situation returning a new pointer value is the sensible approach.
Final point: if you have it available, "memset" (C90 but not C89 afaik, part of the single unix specification however) can be used in place of your "for" loop
memset(ncheck, 0, nCount);
(that's for your version of the function, not the one that takes an int ** argument)
You can "return" the pointer to the allocated memory. If NULL is returned, that means the allocation was unsuccessful.