I am trying to create a vector in C, following is the struct declaration:
#define VECT_INITIAL_CAPACITY 4
typedef struct vect vect_t;
struct vect {
char **data; // data is an array of strings
unsigned int size;
unsigned int capacity;
};
I have a function that constructs a new empty vector, here is what I did:
vect_t *vect_new() {
vect_t *v = (vect_t*) malloc(sizeof(vect_t));
if (v == NULL) {
return NULL;
}
// Allocate memory for data
v->data = (char**) malloc(VECT_INITIAL_CAPACITY * sizeof(char*));
if (v->data == NULL) {
return NULL;
}
for (int i = 0; i < VECT_INITIAL_CAPACITY; i++) {
v->data[i] = NULL;
}
// Initialize fields
v->size = 0;
v->capacity = VECT_INITIAL_CAPACITY;
return v;
}
Valgrind tells me that the line v->data = (char**) malloc(VECT_INITIAL_CAPACITY * sizeof(char*)); caused memory leak. But I'm not sure how to fix this. Can anyone point out what caused the memory leaks?
Edit: Added my cleanup code below:
/** Free all the memories of the vector. */
void vect_delete(vect_t *v) {
// Delete data first
for (int i = 0; i < v->size; i++) {
free(v->data[i]);
}
// Delete the vector
free(v);
}
/** Delete the vector, freeing all memory it occupies. */
void vect_delete(vect_t *v)
{
if(v)
{
// Delete data first
if(v -> data)
for (size_t i = 0; i < v->capacity; i++) //not v->size
{
free(v->data[i]);
}
free(v -> data); //missing
// Delete the vector
free(v);
}
}
Some remarks:
Use the correct type for sizes and indexes (size_t) not int or unsigned
Use objects instead of types in sizeofs. vect_t *v = malloc(sizeof(*v));
Do not cast the results of void * functions like malloc. If the code does not compile, then you use the wrong compiler (C++ one) to compile C code.
In addition to #0___________ good answer,
if (v->data == NULL) { return NULL; } also leaks.
Use if (v->data == NULL) { free(v); return NULL; }.
Related
How can I free memory allocated in this struct
struct image_t {
char type[3];
int **ptr;
int width;
int height;
};
In the first function I made these allocations:
struct image_t *struktura = (struct image_t *)malloc(sizeof(struct image_t));
int **ptr = (int**)malloc(struktura->height * sizeof(int*));
for (i = 0; i < struktura->height; i++) {
*(ptr + i) = (int *)malloc(struktura->width * sizeof(int));
if (*(ptr + i) == NULL) {
break;
}
}
In the second function I must free allocated memory so I tried to free memory something like this but it does not work
void destroy_image(struct image_t **m) {
if (m != NULL) {
if (*m != NULL) {
if ((*m)->ptr != NULL) {
for (int i = 0; i < (*m)->height; i++) {
free(*((*m)->ptr + i));
}
free((*m)->ptr);
free(*m);
}
}
}
}
I can't change declaration of the destroy function so there must be double pointer on struct.
In order for your destroy function to work properly, all pointers in the pointer array must be either valid or null. Memory returned by malloc() is uninitialized so breaking out of the loop in the allocation function leaves the rest of the pointer array uninitialized, hence should not be passed to free().
Also note the you should test for allocation failure of the structure pointer and the pointer array. Furthermore the width and height members of the newly allocated structure are unintialized: you should use function arguments to initialize them.
The destroy_image function should probably set *m to NULL after deallocation and must free(*m); even if (*m)->ptr is a null pointer.
Here are solutions for this issue:
allocate the array with calloc() (a good idea in all cases) or
set height to the number of successfully allocated pointers.
explicitly set the remaining pointers in the array to NULL
free the allocated block upon allocation failure and return NULL.
Here is a modified version:
#include <stdlib.h>
struct image_t {
char type[3];
int **ptr;
int width;
int height;
};
struct image_t *allocate_image(int width, int height) {
struct image_t *struktura = calloc(1, sizeof(*struktura));
if (struktura == NULL)
return NULL;
// should initialize struktura->type too
struktura->width = width;
struktura->height = height
struktura->ptr = calloc(height, sizeof(*struktura->ptr));
if (struktura->ptr == NULL) {
free(struktura);
return NULL;
}
for (int i = 0; i < height; i++) {
struktura->ptr[i] = calloc(sizeof(*struktura->ptr[i]), width);
if (struktura->ptr[i] == NULL) {
// Iterate downwards on index values of allocated rows
// (i --> 0) is parsed as (i-- > 0)
// this test works on signed and unsigned index types, unlike (--i >= 0)
while (i --> 0) {
free(struktura->ptr[i]);
}
free(struktura->ptr);
free(struktura);
return NULL;
}
}
return struktura;
}
void destroy_image(struct image_t **m) {
if (m != NULL) {
struct image_t *p = *m;
if (p != NULL) {
if (p->ptr != NULL) {
for (int i = 0; i < p->height; i++) {
free(p->ptr[i]);
}
free(p->ptr);
}
free(p);
*m = NULL;
}
}
}
To start with...
Don't cast the value returned by malloc
Don't use *(ptr + i) Use the equivalent but much more readable version, i.e. ptr[i]
Doing that changes your allocation to:
struct image_t *struktura = malloc(sizeof(struct image_t));
int **ptr = malloc(struktura->height * sizeof(int*));
for (i = 0; i < struktura->height; i++) {
ptr[i] = malloc(struktura->width * sizeof(int));
if (ptr[i] == NULL) {
break;
}
}
Here is the first problem... you never assign ptr to anything. In the end of the code block you need to add:
struktura->ptr = ptr;
Another problem is that both struktura->height and struktura->width are uninitialized when used. They must be assigned a value before use.
For freeing the allocated memory: Your current code is too complex. A statement like free(*((*m)->ptr + i)); contains 3 pointer dereferences!!. That's hard to read. I'll recommend that you use a few local variables to simplify the code.
void destroy_image(struct image_t **m) {
if (m == NULL) return;
if (*m == NULL) return;
struct image_t *t = *m;
int **ptr = t->ptr;
if (ptr != NULL)
{
for (int i = 0; i < t->height; i++)
{
free(ptr[i]);
}
free(ptr);
}
free(t);
*m = NULL; // The only reason to pass a double pointer to this
// function is to be able to change *m. I guess
// the prototype authoe wants the function to set
// *m to NULL
}
By using these local variables the code is much easier to read than stuff like free(*((*m)->ptr + i));
And for the break in the allocation code...
It's kind of strange (a bug?) that you you don't check for NULL after the first two malloc and then do it inside the loop. Further it's kind of strange to use break as it will leave the rest of the pointers uninitialized.
Anyway - If you really want that break in the allocation code, you also need to take that into account when freeing memory. Something like:
void destroy_image(struct image_t **m) {
if (m == NULL) return;
if (*m == NULL) return;
struct image_t *t = *m;
int **ptr = t->ptr;
if (ptr != NULL)
{
for (int i = 0; i < t->height && ptr[i] != NULL; i++)
{
free(ptr[i]);
}
free(ptr);
}
free(t);
*m = NULL;
}
This is needlessly complicated and inefficient. Have a look at Correctly allocating multi-dimensional arrays.
You can change the struct like this:
struct image_t {
char type[3];
int* ptr; // placeholder pointer
int width;
int height;
};
Then malloc like this:
struct image_t* s = malloc(sizeof *s);
s->width = width;
s->height = height;
s->ptr = malloc( sizeof(int[width][height]) );
(Remember to check the result of each malloc and stop the program if it returns NULL.)
Then use it like this:
int (*arr)[s->height] = (void*) s->ptr; // convert to a temporary 2D array pointer
...
arr[i][j] = whatever; // this enables 2D array access syntax
And free it like this:
free(s->ptr);
free(s);
I am trying to write a C Struct for a resizing array and am getting the error:
a.out(34254,0x7fffa17b7340) malloc: *** error for object
0x7fdd39c02908: incorrect checksum for freed object - object was
probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug
[1] 34254 abort ./a.out
This is the code I currently have:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <math.h>
typedef struct List {
int length;
int *vals; // This should be generic somehow
int curr_inserted;
int max_allowed;
} List;
List *initialize(int val) {
List *curr;
curr = malloc(5 * sizeof(int));
if (curr == NULL) {
printf("Memory Allocation Error\n");
exit(1);
} else {
curr->length = 1;
curr->vals = malloc(10 * sizeof(int));
curr->vals[0] = val;
curr->curr_inserted = 1;
curr->max_allowed = 10;
}
return curr;
}
void add(List *x, int val) {
if (x->curr_inserted == x->max_allowed) {
int* bigger_arr = realloc(x->vals, (2 * x->max_allowed));
x->vals = bigger_arr;
x->max_allowed *= 2;
}
x->vals[x->curr_inserted] = val;
x->length++;
x->curr_inserted++;
}
And I am initialzing and checking the values like this:
int main() {
List *x = initialize(10);
for (int i = 0; i < 100; i++) {
add(x,i);
}
for (int i =0; i < x->length; i++) {
printf("val %d is %d\n",i,x->vals[i]);
}
free(x);
return 0;
}
I believe the error is in the add method where I attempt to resize, but I can not quite figure out how to approach this error.
int* bigger_arr = realloc(x->vals, (2 * x->max_allowed));
will be
int* bigger_arr = realloc(x->vals, (2 * x->max_allowed*sizeof(int)));
But the way you realloc is wrong, given that realloc may fail also. You should check what it returns before you assign it.
Also curr = malloc(5 * sizeof(int)); will be
curr = malloc(sizeof(List)); because for strutures you can't calculate the allocated memory it would need by adding size of individual member elements. There is always a possibility of having padding in which case it would fail.
I wrote the following struct for a vector:
typedef struct Vector_ Vector;
struct Vector_
{
int dim;
double* vector;
};
And I wrote a function to initialise a new instance of that struct:
Vector* newVector(int length){
int i = 0;
Vector* vec = malloc(sizeof(Vector));
assert(vec != NULL);
assert(length > 0);
vec->dim = length;
vec->vector = malloc((length+1)*sizeof(double));
assert(vec->vector != NULL);
for(i=0;i<=length+1;i++) vec->vector[i] = 0;
return vec;
}
This all works, but then I wrote a function to reallocate memory and change the length of the vector like this:
Vector* setVectorLength(Vector* vec, int length)
{
assert(vec->dim > 0);
int i = 0;
if(length > vec->dim)
{
vec->vector = realloc(vec->vector,(length+1)*sizeof(double));
assert(vec->vector != NULL);
for(i = vec->dim+1;i<=length;i++)
{
vec->vector[i] = 0;
}
}
else
{
vec->vector = realloc(vec->vector,length+1 * sizeof(double));
}
vec->dim = length;
return vec;
}
And I call it like this:
int main()
{
Vector* newvec = newVector(5);
setVectorLength(newvec,8);
}
For some reason, the line in the setVectorLength function where I reallocate the memory of the vector array causes the program to abort. If I comment out that section, everything works. Interestingly, I am able to write entries to the array even without reallocating it to a sufficiently high length, so for example, if I only initialise the vector struct and give it the length 5, then I can write values into the 7th or 8th spot of the vec->vector array, even though I never allocated that much memory to it. Any hints?
In line 77 v->size is 0 while in line 186 v-size is 2. I dont understand why this is so because line 186 is at the very end of the function definition of void _setCapacityDynArr(struct DynArr *v, int newCap)(in line 140) and line 77 is right after the call to the function. Somehow between the end of the function and the next line after the function call the value has changed. I thought because v is a pointer it should retain the value. If someone could please tell me why the value is changing it would be greatly appreciated. I've run out of ideas and have no idea what to do.
http://pastebin.com/tWR6w8rG
/*
* File: main.c
* Author: user1
*
* Created on April 7, 2015, 3:57 PM
*/
#include <stdio.h>
#include <stdlib.h>
/*
* File: main.c
* Author: user1
*
* Created on April 7, 2015, 3:57 PM
*/
/*
*
*/
# ifndef TYPE
# define TYPE int
# endif
struct DynArr
{
TYPE *data;
int size;
int capacity;
};
/* pointer to the data array */
/* Number of elements in the array */
/* capacity ofthe array */
void initDynArr(struct DynArr *v, int capacity)
{
v->data = malloc(sizeof(TYPE) * capacity);
//assert(v->data != 0);
v->size = 0;
v->capacity = capacity;
}
void freeDynArr(struct DynArr *v)
{
if(v->data != 0)
{
free(v->data); /* free the space on the heap */
v->data = 0;
/* make it point to null */
}
v->size = 0;
v->capacity = 0;
}
int sizeDynArr( struct DynArr *v)
{
return v->size;
}
/*
void addDynArr(struct DynArr *v, TYPE val)
{
// Check to see if a resize is necessary
if(v->size == v->capacity)
_setCapacityDynArr(v, 2 * v->capacity);
v->data[v->size] = val;
v->size++;
}
*/
void addDynArr(struct DynArr *v, TYPE val)
{
// Check to see if a resize is necessary
if(v->size >= v->capacity)
{
_setCapacityDynArr(v, 2 * v->capacity);
printf(">>>%d",v->size); //<<<<<<<<<<<<<<<<<<<<v->size = 0
v->data[v->size] = val;
v->size++;
printf("setcapacity: size is: %d capacity is: %d value is %d value in array is: %d\n", v->size, v->capacity, val, v->data[v->size-1]);
}
else
{
v->data[v->size] = val;
v->size++;
printf("not setcapacity: size is: %d capacity is: %d value is %d value in array is: %d\n", v->size, v->capacity, val, v->data[v->size-1]);
}
//printf("%d\n", v->capacity);
}
void removeDynArray(struct DynArr *b, TYPE v)
{
for(int i = 0; i < b->size; i++)
{
if(b->data[i] == v)
{
while(i < (b->size))
{
b->data[i] = b->data[i+1];
i++;
}
break;
}
}
b->size--;
}
void print(struct DynArr *v)
{
for(int i = 0; i < v->size; i++)
{
printf("%d\n", v->data[i]);
}
}
//do this
void _setCapacityDynArr(struct DynArr *v, int newCap)
{
struct DynArr* temp;
temp = v;
///print(temp);
//struct DynArr v;
v = malloc(sizeof(struct DynArr));
v->data = malloc(sizeof(TYPE) * newCap);
v->capacity = newCap;
v->size = 0; //temp size is also being set
for (int i = 0 ; i < temp->size; i++)
{
v->data[i] = temp->data[i];
v->size++;
}
free(temp->data);
temp->size = 0;
temp->capacity = 0;
temp = 0;
printf(">!>>%d",v->size); //////////<<<<<<<<<<<<<<<<<<<<<<<<v->size = 2
}
int main(int argc, char** argv)
{
struct DynArr a;
initDynArr(&a, 2);
addDynArr(&a, 5);
addDynArr(&a, 7);
addDynArr(&a, 8);
//printf("%d\n", a.size);
//print(&a);
// printf ("%d\n",a.data[2]);
return (EXIT_SUCCESS);
}
Your _setCapacityDynArr function is written in a rather nonsensical fashion. All functions in this "API" receive a pointer v (or, sometimes, b) to an existing struct DynArr object, which they work with. They can manipulate the fields of *v object. They can allocate/deallocate/reallocate the actual array v->data. But they never allocate/deallocate the *v object itself. Object *v is passed from the outside and managed by the outside code.
But your _setCapacityDynArr function attempts to do something completely and drastically different. It begins with
temp = v;
v = malloc(sizeof(struct DynArr));
...
free(temp);
That is already incorrect. This is completely unacceptable. You are not allowed to allocate/deallocate *v object itself.
In any case, changing the value of v inside the function make no sense simply because v is passed to _setCapacityDynArr by value. The outside code will not see these changes anyway.
This latter detail is what makes your code to output allegedly "changing" value of v->size - you are simply outputing two completely different v->size values and one of them actually belongs to deallocated memory. In line 77 you are printing v->size value stored in "dead" memory already deallocated by free(temp) call inside _setCapacityDynArr.
Don't try to acclocate/deallocate *v object inside your _setCapacityDynArr. Where did you get that idea? Just reallocate v->data and change the other firelds accordingly. But don't attempt to change the value of v itself.
I'm a beginner in C and programming. I would like to ask some questions on dynamic array and pointer in C.
I am trying to create a dynamic array and increase its capacity, but I can't get my code working. I believe something is wrong in my setCapacityDynArr function.
Can someone give me some help?
Thanks!
struct DynArr {
TYPE *data; /* pointer to the data array */
int size; /* Number of elements in the array */
int capacity; /* capacity ofthe array */
};
void initDynArr(struct DynArr *v, int capacity) {
v->data = malloc(sizeof(TYPE) * capacity);
assert(v->data != 0);
v->size = 0;
v->capacity = capacity;
}
void freeDynArr(struct DynArr *v) {
if (v->data != 0) {
free(v->data); /* free the space on the heap */
v->data = 0; /* make it point to null */
}
v->size = 0;
v->capacity = 0;
}
int sizeDynArr(struct DynArr *v) {
return v->size;
}
void addDynArr(struct DynArr *v, TYPE val) {
/* Check to see if a resize is necessary */
if (v->size >= v->capacity) {
_setCapacityDynArr(v, 2 * v->capacity);
}
v->data[v->size] = val;
v->size++;
}
void _setCapacityDynArr(struct DynArr *v, int newCap) {
//create a new array
struct DynArr *new_v;
assert(newCap > 0);
new_v = malloc(newCap * sizeof(struct DynArr));
assert(new_v != 0);
initDynArr(new_v, newCap);
//copy old values into the new array
for (int i = 0; i < new_v->capacity; i++) {
new_v->data[i] = v->data[i];
}
//free the old memory
freeDynArr(v);
//pointer is changed to reference the new array
v = new_v;
}
int main(int argc, const char * argv[]) {
//Initialize an array
struct DynArr myArray;
initDynArr(&myArray, 5);
printf("size = 0, return: %d\n", myArray.size);
printf("capacity = 5, return: %d\n", myArray.capacity);
//Add value to the array
addDynArr(&myArray, 10);
addDynArr(&myArray, 11);
addDynArr(&myArray, 12);
addDynArr(&myArray, 13);
addDynArr(&myArray, 14);
addDynArr(&myArray, 15);
for (int i = 0; i < myArray.size; i++) {
printf("myArray value - return: %d\n", myArray.data[i]);
}
return 0;
}
//pointer is changed to reference the new array
v = new_v;
This is your problem, a classic mistake in C. In fact the function changes its own copy of the pointer, the caller never sees the change. The problem is amply described by this C FAQ.
I suggest a different approach. There's no reason to make a new v: you simply want more storage associated with it. So instead of actually changing v, you'll probably want to just call realloc on the storage: v->DATA.
You might get away with something like:
tmp = realloc(v->data, newCap * sizeof *v->data);
if (!tmp)
error;
v->data = tmp;
And this way you don't need to copy the elements either: realloc takes care of that.
//pointer is changed to reference the new array
v = new_v;
Your original pointer outside the function is not changed, since you passed the value of the pointer not the address of it here:
void _setCapacityDynArr(struct DynArr *v, int newCap)
{
Yes it's an error in _setCapacityDynArr. It's an error because you declare an DynArr structure on the stack, then you try to free it and assign a new pointer to it. That will not work, as items allocated on the stack can't be freed.
What you want to do is to reallocate only the actual data, not the whole structure. For this you should use the realloc function.
There are other problems with the function as well, like you assigning to the pointer. This pointer is a local variable so when the function returns all changes to it will be lost.