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; }.
I'm actually learning C programming and my school actually doesn't allow us to use calloc / realloc without reprogramming them. That's why I'm asking for help.
Here is my problem :
I want to use void * to make my code reusable but I encounter the problem "dereferencing void * pointer" when I try to run through my array. I'm unable to pick up the type of the final pointer.
Here is my functions :
#include <stdlib.h>
void *my_calloc(size_t size, size_t n) //n = number of bytes your type : sizeof(<whatever>)
{
void *ptr = NULL;
if (size < 1 || n < 1)
return (NULL);
ptr = malloc(n * (size + 1));
if (ptr == NULL)
return (NULL);
for (int i = 0; i != (n * (size + 1)); i++) {
*ptr = NULL; //Here is my problem
ptr++;
}
return (ptr);
}
void *my_realloc(void *src, size_t size, size_t n)
{
void *dst = NULL;
int dst_len = 0;
if (src == NULL || size < 0 || n < 1)
return (NULL);
dst_len = my_strlen(src) + size;
if (dst_len == my_strlen(src))
return (src);
dst = my_calloc(dst_len, n);
if (dst == NULL)
return (NULL);
for (int i = 0; src[i] != NULL;i++)
dst[i] = src[i]; //Here is the same problem...
free(src);
return (dst);
}
I just find a problem while I was writing my post, my my_strlen function can only take a char *... so I would need a function my_strlen looking like :
int my_strlen(void *str)
{
int len = 0;
while (str[len] != NULL) { //same problem again...
len++;
}
return (len);
}
A typical function where i call calloc / malloc would be :
int main(void)
{
char *foo = NULL;
int size = 0;
int size_to_add = 0;
size = <any size>;
//free(foo); //only if foo has been malloc before
foo = my_calloc(size, typeof(*foo));
//something
size_to_add = <any size>;
foo = my_realloc(foo, size_to_add, sizeof(*foo))
//something
free(foo);
return (0);
}
Thank you for trying to help me.
my_calloc() has various troubles:
Attemptted pointer math on a void *
This is undefined behavior (UB).
Instead make ptr a character pointer.
// void *ptr = NULL;
unsigned char *ptr = NULL;
...
ptr++;
Attempt to de-reference a void *
This is also UB.
Instead make ptr a character pointer.
// void *ptr = NULL;
unsigned char *ptr = NULL;
...
// *ptr = NULL;
*ptr = '\0';
my_calloc() allocates more memory than calloc()
To do the same as calloc(), do not add one.
// ptr = malloc(n * (size + 1));
ptr = malloc(n * size);
No overflow protection
my_calloc() does not detect overflow with n * (size + 1). A test is
// Note: it is known n > 0 at this point
if (SIZE_MAX/n > size+1) return NULL;
// or if OP drop the + 1 idea,
if (SIZE_MAX/n > size) return NULL;
my_realloc() has various troubles:
Different signature
I'd expect the goal of "school actually doesn't allow us to use calloc / realloc without reprogramming them" was meant to create a realloc() substitute of which my_realloc() is not. If a different function is desired, consider a new name
void *my_realloc(void *src, size_t size, size_t n)
// does not match
void *realloc(void *ptr, size_t size);
Failure to handle a shrinking allocation
The copying of data does not take into account that the new allocation may be smaller than the prior one. This leads to UB.
Unneeded code
size < 0 is always false
Memory leak
The below code does not free src before returning. Further, it does not allocate anything when n>0. This differs from calloc(pit, 0) and calloc(NULL, 42).
// missing free, no allocation
if (src == NULL || size < 0 || n < 1) {
return (NULL);
}
Assumed string
my_strlen(src) assume src points to a valid string. calloc() does not assume that.
void is an incomplete type, so you can't dereference a void *. What you can do however is cast it to a char * or unsigned char * to access individual bytes.
So my_calloc can do this:
((char *)ptr)[i] = 0;
And my_realloc can do this:
((char *)dst)[i] = ((char *)src)[i];
I have a function which builds an array of strings (char*) .
After I finished using the array I want to free its memory but then I get a CrtIsValidHeapPointer Error.
Code:
int main(int argc, char * argv[])
{
char** arr = NULL;
creating_array(&arr); // Building the array
//free each string memory
for (size_t i = 0; i < 4; i++)
{
free(arr[i]);
}
// until here everything works fine :)
//free the array memory
free(arr); // Error CrtIsValidHeapPointer
return 0;
}
void creating_array(char*** pArr)
{
char** arr = (char**)malloc(4);
arr[0] = (char*)malloc(5 * sizeof(char));
strcpy(arr[0], "aaaa");
arr[1] = (char*)malloc(5 * sizeof(char));
strcpy(arr[1], "bbbb");
arr[2] = (char*)malloc(5 * sizeof(char));
strcpy(arr[2], "cccc");
arr[3] = (char*)malloc(5 * sizeof(char));
strcpy(arr[3], "dddd");
*pArr = arr;
}
Why does it happen?
Please try, in creating_array
char **arr ;
arr=(char **) calloc( 4 , sizeof(char *));
Here is the working code. It compiles and runs now.
Generally after freeing a pointer, people set it to NULL to avoid confusion (so that any time a pointer is not null it points to valid memory). That avoids bugs. Also it is legal to free(NULL), so you don't get into very severe and hard-to- debug problems that happen if you double-free an address.
One important point, is that in this case, the parenthesis in this case (*pArr)[2] are important, to override the operator precedence in C. If you try *pArr[2] it assumes you mean to de-reference the pointer stored at element [2]. (*pArr)[2] means return element at element to from the the location at the address pointed to by pArr. The reason C assumes the other case and that you need parens in this case is that the other use is much much more common, so it is convenient.
Note: ALWAYS check return values for malloc() and function calls and have a strategy to catch and log errors. Otherwise as you start writing bigger programs you will find them extremely difficult, troublesome or nearly impossible to debug.
Another thing is to create named constants instead of literals, because then it is clear what the number is and how it is used, and if that number is needed in more than one place it can be changed in one place. It makes the program easier to read and understand.
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#define STRING_COUNT 4
char **create_array(char ***pArr);
int
main()
{
char **arr = NULL;
if (create_array(&arr) == NULL) {
fprintf(stderr, "out of memory - exiting\n");
return -1;
}
for (size_t i = 0; i < STRING_COUNT; i++) {
printf("%s\n", arr[i]);
}
for (size_t i = 0; i < STRING_COUNT; i++) {
free(arr[i]);
arr[i] = NULL;
}
free(arr);
return 0;
}
char **
create_array(char ***pArr)
{
if ((*pArr = malloc(STRING_COUNT * sizeof (char **))) == NULL) {
return NULL;
}
if (((*pArr)[0] = strdup("aaaa")) == NULL) {
return NULL;
}
if (((*pArr)[1] = strdup("bbbb")) == NULL) {
free((*pArr)[0]);
*pArr[0] = NULL;
return NULL;
}
if (((*pArr)[2] = strdup("bbbb")) == NULL) {
free((*pArr)[0]);
*pArr[0] = NULL;
free((*pArr)[1]);
*pArr[1] = NULL;
return NULL;
}
if (((*pArr)[3]= strdup("bbbb")) == NULL) {
free((*pArr)[0]);
*pArr[0] = NULL;
free((*pArr)[2]);
*pArr[1] = NULL;
free((*pArr)[2]);
*pArr[2] = NULL;
return NULL;
}
return *pArr;
}
So I am trying to print out a char* array after being returned from a function but I keep getting a segfault.
char* return(node *n){
node* p = list->head;
int count = 0;
int size = 0;
while(p != NULL){
size += strlen(p->name);
count++;
p = p->nxt;
}
size = size + 1; // for the '\0'
char * arr[count][size];
p = list->head;
count = 0;
while(p != NULL){
strcpy(arr[count], p->name);
count++;
p = p->next;
}
return arr;
}
I then go to try and print it out in my main method on a certain node. and I get a segmentation fault.
char* test = return(node1);
for(i = 0; i < 5; i++){
printf("%s", test[i]);
}
Your arr is local to the (unfortunately named) function. When the function exits, the space is deallocated. If you use that pointer afterwards, you are indexing into unknown, and most likely somewhere you're not supposed to (which results in a segfault).
When you want to allocate space in a function and return a pointer, you should use malloc (or equivalent), and remember to free the space afterwards. An alternate way is to have the pointer be a parameter to the function, and leave the reponsibility for allocation (and deallocation) to the caller (like fgets does).
Approach 1 (allocation inside the function):
char *foo() {
char *arr = malloc(100);
return arr;
}
/* somewhere else */
char *arr = foo();
/* use arr */
free(arr);
Approach 2 (allocation outside the function):
void foo(char *arr, size_t size) {
/* do stuff to arr */
}
/* somewhere else */
char *arr = char[100];
foo(arr, 100);
EDIT: Was wrong. Ignore what was here.
I understand more about pointers and stuff but I have no idea what I am doing wrong here.
if i Have
char *(*data)[]
That would just be interpreted as "a pointer to an array of char pointers", right?
Then I have a struct like this, typedef'd to be myStruct, redundant as it may be, but that's aside the point:
typedef struct myStruct myStruct;
struct myStruct{
int size;
char *name;
myStruct *(*array)[];
}
Having looked around the site for similar posts, I got something like this:
//let's say allocating 5 spaces for this case
myStruct *a = malloc(sizeof(myStruct)+ sizeof(struct myStruct *)*5);
I am sure that the number I allocated the struct with is the size of the array.
I can't quite get my head wrapped around this, how does it work if it's a struct?
The plan here is to have this struct, and it contains an array of 5 myStruct's. Do I have to allocate them separately as well? like this?
a->array[0] = malloc( .... )
I tried and it keeps giving me an error saying Invalid use of array with unspecified bounds.
What am I doing wrong or how Can i fix this?
Thank you
From your comment, it sounds like you want a pointer to an array of pointers to structures, rather than a pointer to an array of structures, since "pointer to an array of char *" also has two levels of indirection.
Here's the difference:
A pointer to a structure:
A pointer to an array of structures:
A pointer to an array of pointers to structures:
Assuming you want #3, you can do it like so (in "traditional" C):
typedef struct myStruct myStruct;
struct myStruct
{
int size;
char *name;
myStruct **array;
};
myStruct *allocate_node(char *name, int size)
{
myStruct *p_node;
if (size < 0)
size = 0;
p_node = calloc(1, sizeof(myStruct));
p_node->name = name;
p_node->size = size;
p_node->array = calloc(1, size * sizeof(myStruct *));
return p_node;
}
void expand_node_child_array(myStruct *p_node, int size_to_add)
{
if (size_to_add < 1 || p_node == NULL)
return;
if (p_node->array == NULL)
{
p_node->size = size_to_add;
p_node->array = calloc(1, size_to_add * sizeof(myStruct *));
}
else
{
p_node->array = realloc(p_node->array, (p_node->size + size_to_add) * sizeof(myStruct *));
memset(p_node->array + p_node->size * sizeof(myStruct *), 0, size_to_add * sizeof(myStruct *));
p_node->size += size_to_add;
}
}
myStruct *get_child_node(myStruct *p_node, int index)
{
if (index < 0 || index >= p_node->size)
return 0;
return p_node->array[index];
}
int set_child_node(myStruct *p_node, int index, myStruct *p_child)
{
if (index < 0 || index >= p_node->size)
return FALSE;
p_node->array[index] = p_child;
return TRUE;
}
void free_node(myStruct **pp_node)
{
// Free p_node and the array but DO NOT free the children
if (pp_node == NULL || *pp_node == NULL)
return;
if ((*pp_node)->array != NULL)
free((*pp_node)->array);
free((*pp_node));
*pp_node = NULL;
}
void free_node_and_children(myStruct **pp_node)
{
int iChild;
if (pp_node == NULL || *pp_node == NULL)
return;
for (iChild = 0; iChild < (*pp_node)->size; iChild++)
{
myStruct *p_child = get_child_node((*pp_node), iChild);
if (p_child != NULL)
free_node_and_children(&p_child);
set_child_node((*pp_node), iChild, NULL);
}
free_node(pp_node);
}
Update
A flexible array, under the C99 standard syntax, is a variable-length array that appears at the tail of a structure and whose actual length is set at run time. It looks like this in memory:
Assuming your compiler supports this syntax (not all do), you declare it like this:
struct myStruct
{
Type array_of_type[]; /* AT THE END OF THE STRUCT ONLY */
};
And the code for "myStruct" becomes:
typedef struct myStruct myStruct;
struct myStruct
{
int size;
char *name;
myStruct *array[];
};
myStruct *allocate_node(char *name, int size)
{
myStruct *p_node;
if (size < 0)
size = 0;
p_node = calloc(1, sizeof(myStruct) + size * sizeof(myStruct *));
p_node->name = name;
p_node->size = size;
return p_node;
}
myStruct *get_child_node(myStruct *p_node, int index)
{
if (index < 0 || index >= p_node->size)
return NULL;
return p_node->array[index];
}
int set_child_node(myStruct *p_node, int index, myStruct *p_child)
{
if (index < 0 || index >= p_node->size)
return FALSE;
p_node->array[index] = p_child;
return TRUE;
}
void free_node(myStruct **pp_node)
{
if (pp_node == NULL || *pp_node == NULL)
return;
free((*pp_node));
*pp_node = NULL;
}
void free_node_and_children(myStruct **pp_node)
{
int iChild;
if (pp_node == NULL || *pp_node == NULL)
return;
for (iChild = 0; iChild < (*pp_node)->size; iChild++)
{
myStruct *p_child = get_child_node((*pp_node), iChild);
if (p_child != NULL)
free_node_and_children(&p_child);
set_child_node((*pp_node), iChild, NULL);
}
free_node(pp_node);
}
If you compiler does not, see here for some workarounds.
With flexible arrays, expanding the array would require re-allocating the node itself and fixing all references to it, something not required in the "pointer to array of pointers" design.
The syntax you are using:
myStruct *(*array)[];
should be read as "a pointer to array(s) of unknown size of pointers to structures", rather than
myStruct **array;
which is "a pointer to pointer(s) to structures", or (e.g.):
myStruct *(*array)[4];
which is "a pointer to array(s) of length 4 of pointers.
Your syntax actually produces memory map #3, however accessing the individual elements is a bit more awkward because you have to explicitly get a pointer to the zeroth element of the "array of unknown size", which is (*p_node->array). Thus the functions from #3 are modified as follows:
void expand_node_child_array(myStruct *p_node, int size_to_add)
{
if (size_to_add < 1 || p_node == NULL)
return;
if (p_node->array == NULL)
{
p_node->size = size_to_add;
p_node->array = calloc(1, size_to_add * sizeof(myStruct *));
}
else
{
p_node->array = realloc(p_node->array, (p_node->size + size_to_add) * sizeof(myStruct *));
memset((*p_node->array) + p_node->size * sizeof(myStruct *), 0, size_to_add * sizeof(myStruct *));
p_node->size += size_to_add;
}
}
myStruct *get_child_node(myStruct *p_node, int index)
{
if (index < 0 || index >= p_node->size)
return NULL;
return (*p_node->array)[index];
}
int set_child_node(myStruct *p_node, int index, myStruct *p_child)
{
if (index < 0 || index >= p_node->size)
return FALSE;
(*p_node->array)[index] = p_child;
return TRUE;
}
And finally, the test code for either architecture:
void dump_nodes_recursive(myStruct *p_node, int level)
{
if (p_node == NULL)
{
printf("%*s", 4*level, " ");
printf("NULL\n");
}
else
{
int iChild;
printf("%*s", 4*level, " ");
printf("Node: Name=\"%s\", array size=%d\n", p_node->name, p_node->size);
for (iChild = 0; iChild < p_node->size; iChild++)
{
myStruct *p_child = get_child_node(p_node, iChild);
printf("%*s", 4*level, " ");
printf("Child [%d]:\n", iChild);
dump_nodes_recursive(p_child, level+1);
}
}
}
void dump_nodes(myStruct *p_node)
{
dump_nodes_recursive(p_node, 0);
}
void test_my_struct()
{
myStruct *p_top = allocate_node("top", 4);
myStruct *p_child0 = allocate_node("child0", 1);
myStruct *p_child1 = allocate_node("child1", 5);
myStruct *p_child2 = allocate_node("child2", 0);
myStruct *p_child3 = allocate_node("child3", 0);
myStruct *p_child00 = allocate_node("child00", 0);
set_child_node(p_top, 0, p_child0);
set_child_node(p_top, 1, p_child1);
set_child_node(p_top, 2, p_child2);
set_child_node(p_top, 3, p_child3);
set_child_node(p_child0, 0, p_child00);
dump_nodes(p_top);
free_node_and_children(&p_top);
}
myStruct *(*array)[]; is not a flexible array member, since it's not an array type. It is a pointer which happens to be pointing to an incomplete array type.
The general pattern for flexible array member is:
struct myStruct {
int size;
char *name;
Type array[];
};
where in your case, Type would be defined by typedef MyStruct * Type;. I'm assuming you want an array which will contain 5 pointers. (This is the same effect as having myStruct *array[]; in the struct, of course).
(If you do actually want your struct to contain a single pointer, which points to an array of 5 elements; then flexible array member is not the right technique to use).
Your malloc is correct for this definition I have just given. It allocates a contiguous bloc of memory and you can use array as if it were actually an array of 5 objects, except you can't do sizeof on it to find the size.