I have a program to dynamically increase the capacity of a hashtable when the size of any
of its buckets goes beyond a maximum value. However i am being hit with a "* glibc
detected * realloc(): " error when i try to run my code.
Could anyone help me out with it? Sorry for positing so much code here,but i really need
the help.
/* structure for the hashtable containing an array of nodes */
typedef struct Hashtable hashtable;
struct Hashtable {
struct node **list;
};
/* the function which resizes the hashtable and re-arranges the values according to
new capacity */
void reSize(hashtable *h)
{
int i;
node **newlist=realloc(h->list,2*capacity*sizeof(node*));
h->list=newlist;
int temp=capacity,index;
capacity=capacity * 2;
for(i=temp;i<capacity;i++)
h->list[i]=calloc(1,sizeof(node));
}
/* mystructure init */
struct hashtable *mystruct_init()
{
int i;
hashtable *hashtable =calloc(1, sizeof(*hashtable));
// loop through and allocate memory for each element in list
hashtable->list= calloc(1,sizeof(node *));
for (i = 0; i < 16; i++) {
hashtable->list[i] = calloc(1, sizeof(node));
}
return hashtable;
}
/* in my main function */
hashtable *h1=(hashtable *) mystruct_init();
hashtable *h2=(hashtable *) mystruct_init();
I am getting this "* glibc detected * ./compareDocs: realloc(): " error when i try
to run it. Could someone point out as to where i am going wrong in my code?? I've spend
a whole night trying to debug this thing, so any help would be really nice. Sorry for
posting so many lines of code..
What happens is that you allocate an array of length capacity. You then double capacity on the line that reads capacity=capacity * 2. And then you write of the end of the array in the for loop because the array is only half as long as you think it is.
node **newlist=realloc(h->list,capacity*sizeof(node*));//array of length capacity
h->list=newlist;
....
capacity=capacity * 2;//oops, capacity is now twice as big as the array
for(i=temp;i<capacity;i++)
h->list[i]=calloc(1,sizeof(node));//and now we are writing off the end
}
There are quite likely other errors in your code. I can't see how the capacity variable is handled. Is it a global? Where is it initialised?
Also, the code you added in your edit is clearly wrong.
hashtable->list= calloc(1,sizeof(node *));
for (i = 0; i < 16; i++) {
hashtable->list[i] = calloc(1, sizeof(node));
}
Here you appear to set the initial capacity of the list to 1, but then assign 16 values. Clearly the calloc should be passed 16 rather than 1.
In your mystruct_init() function you've allocated only one node * for your your list:
hashtable->list= calloc(1,sizeof(node *));
And then went on to dereference elements past the end of the allocated memory:
for (i = 0; i < 16; i++) {
hashtable->list[i] = calloc(1, sizeof(node));
Also, in your reSize() function you use the variable capacity but that does not appear to be defined anywhere. Is this your real code? And if it is, what is the value of capacity?
Edit: You should probably make the code in your init function look like this:
struct hashtable *mystruct_init()
{
int i;
hashtable *hashtable =calloc(1, sizeof(*hashtable));
// loop through and allocate memory for each element in list
hashtable->list= calloc(capacity, sizeof(node *));
for (i = 0; i < capacity; i++) {
hashtable->list[i] = calloc(1, sizeof(node));
}
return hashtable;
}
Notice that I've used capacity in the call to calloc() and as the controlling value in the following for loop.
Related
I am trying to get into C and as a training example, I decided to write a simple dynamically sized list. But I am facing a weird problem, where the code only works up to an initial list size of 4. Starting at List size 5, I get an error.
typedef struct {
int* data;
int alloc_size;
int length;
} List;
List create(int init_size) {
List out;
out.data = (int*) malloc(init_size * sizeof(int));
out.alloc_size = init_size;
out.length = 0;
return out;
}
void list_push(List* list, int elem) {
if (list->length == list->alloc_size) {
list->data = (int*) realloc(list->data, 2 * list->alloc_size);
list->alloc_size *= 2;
}
*(list->data + list->length) = elem;
list->length++;
}
int list_pop(List* list) {
list->length--;
return *(list->data + list->length);
}
int main() {
List list = create(5);
for (int i = 0; i < 100; i++) {
list_push(&list, i);
}
while (list.length > 0) {
printf("%d\n", list_pop(&list));
}
return 0;
}
Up to create(4), everything works as expected. But if the list is created with create(5) (i.e. an initial size of 5), I get the following error: malloc: Incorrect checksum for freed object 0x7f7ff5c01778: probably modified after being freed. Corrupt value: 0x700000006. I can't really wrap my head around what would cause this to only work up to specific initial sizes, as the list size is dynamically reallocated anyway.
There are a couple of problems with this line
list->data = (int*) realloc(list->data, 2 * list->alloc_size);
The most evident is that 2 * list->alloc_size should be multiplied by the size in bytes of each element (sizeof(int) or sizeof(*(list->data)) in this case).
The most subtle is that the return value of realloc (and of the previous malloc) is not checked, but unconditionally assigned to list->data. The problem is that, on failure, it returns NULL, while the passed pointer (list->data) is not invalidated and should be freed to avoid leaks.
change to reallocation statement
list->data = (int*) realloc(list->data,sizeof(int) * 2 * list->alloc_size);
Second time you are trying to re-allocate lesser bytes than you already allocated, that's the reason for this
I have been building this hash table function that is given an array it gets a word from and a pointer to an array that it fills with my linked list struct. It compiles correctly but I get a segmentation fault at - *hashTable[hashVal] = *newNode; .
void hashTableCreate(char *array, list *hashTable[]) {
while(arrayPos < getArrayLength(array)) {
char *temp = getWord(array);
int hashVal = hashingFunc(temp);
if((*hashTable[hashVal]).word == temp ) {
(*hashTable[hashVal]).count = (*hashTable[hashVal]).count+1;
}
else {
list *newNode = malloc(sizeof(list));
strcpy(newNode->word,temp);
newNode->count = 1;
*hashTable[hashVal] = *newNode;
}
}
}
It's called like this:
void timeStructures(char *newArray) {
list *hashTable[3000];
hashTableCreate(newArray, hashTable);
}
I know this is to do with the way I am using my pointers but I can't figure it out. Any help would be appreciated.
There are several problems on this code:
You seem you are using extra asterisks when assigning newNode to hashTable.
You can use ++ operator to increment count, and use -> to access a member of a pointer to struct.
getWord is unknown to me, but seems impossible it can return a pointer to a string contained inside an element of hashTable, which means the next if will always be false (newNode's word is a copied string, not a pointer to array's word), as it compares memory addresses instead of strings.
You never free temp neither hashTable elements, which seems another misconception of what you are doing here.
As noted by #kaylum , you should initialize hashTable so you avoid comparing against unassigned array elements, neither modifying count on them.
hashTable has to be passed as a pointer to hashTableCreate, or this will work on a copied version of it:
Try this:
void hashTableCreate(char *array, list *(*hashTable[])) {
while(arrayPos < getArrayLength(array)) {
char *temp = getWord(array);
int hashVal = hashingFunc(temp);
if((*hashTable)[hashVal] != NULL &&
strcmp((*hashTable)[hashVal]->word, temp) == 0 ) {
(*hashTable)[hashVal]->count++;
}
else {
list *newNode = malloc(sizeof(list));
strcpy(newNode->word,temp);
newNode->count = 1;
(*hashTable)[hashVal] = newNode;
}
free(temp);
}
}
void timeStructures(char *newArray) {
list *hashTable[3000];
int i;
// Initialize hashTable pointers to NULL
for(i = 0; i < 3000; i++) {
hashTable[i] = NULL;
}
hashTableCreate(newArray, &hashTable);
// Free hashTable elements, malloc'ed at hashTableCreate
for(i = 0; i < 3000; i++) {
if(hashTable[i] != NULL) {
free(hashTable[i]);
}
}
}
Note 1: you never check if hashVal is higher than 3000, which might be fine if you know what you are doing, aka, you know hashingFunc will never return 3000 or higher. If you do not, you'll need to care about growing hashTable appropriately.
Note 2: executing getArrayLength on each loop might be a performance problem for large lists. You probably prefer to create a variable to contain its value and execute it only once.
Note 3: It might be some easier if you declare hashTable as a plain list of elements, not a list of pointers to elements, like list hashTable[3000];, but I don't know exactly what you're looking for. Also, it will always waste 3000 list elements of memory, so might be a performance problem.
We are told our input file would be a simple list of numbers:
1 3 4
2 3
3 4
4 1 2
Where the first number is the source node, and the proceeding numbers are it's adjacent nodes.
I am trying to figure out how to best store this.
I wanted to firstly initialize a "graph", an array that contains all these nodes.
Then upon reading the file, line by line, I would store the root node into the graph array, and then update the node's outlist (adjacent nodes) with the following numbers until we reach the end of the line, repeating this for each line until EOF.
However I'm struggling on how to initialize the graph, do I just assume a certain size and realloc() once the size is hit? Do I read the file first and count the number of lines to find out the size, then re-read the file to store the nodes? Is there any other way?
Here is the code for my data structures:
int initialize (Graph *mygraph, int MaxSize) {
mygraph->MaxSize = MaxSize;
mygraph->table = (Node *)malloc(sizeof(Node) * MaxSize);
return 0;
}
int insert_node (Graph *mygraph, int n, char *name) {
mygraph->table[n].name = strdup(name);
mygraph->table[n].outdegree = 0;
return 0;
}
int insert_link (Graph *mygraph, int source, int target) {
List *newList = (List *)malloc(sizeof(List));
newList->index = target;
newList->next = mygraph->table[source].outlist;
mygraph->table[source].outlist = newList;
return 0;
}
So upon reading the file,
I initialize the graph.
I read the first number, store it as a new graph node.
I read the next numbers until hitting "\n", and store these as graph links to the above root node.
I do this for each line until hitting EOF.
As you can see I have no idea what the "MaxSize" until the whole file is read.
Thanks!
I'm rather new to C so sorry if I've done anything silly.
You could have some initial guess for MaxSize (e.g. 8) and grow when needed your data (perhaps by graph->MaxSize += graph->MaxSize/2) using realloc, or just by malloc-ing a bigger new chunk, copying the older chunk inside, then free-ing that older chunk). Don't forget to check the successful result of any malloc or calloc or realloc call, they could (rarely) fail.
Notice that I have no idea of how your Graph and Node type is declared (just guessing).
I am assuming and guessing you have declared something like
typedef struct node_st Node;
typedef struct graph_st Graph;
struct node_st {
char*name; // strdup-ed
unsigned outdegree;
};
struct graph_st {
unsigned MaxSize;
Node* table; //calloc-ed, of allocated size MaxSize
};
So for example your insert_node function might be
void insert_node (Graph *mygraph, int n, char *name) {
assert (mygraph != NULL);
assert (n >= 0);
assert (name != NULL && *name != (char)0);
unsigned maxsize = mygraph->MaxSize;
if (maxsize <= n) {
unsigned newmaxsize = n + maxsize/2 + 1;
Node* newtable = calloc (newmaxsize, sizeof(Node));
if (!newtable)
perror("growing table in graph"), exit(EXIT_FAILURE);
for (unsigned i=0; i<maxsize; i++)
newtable[i] = mygraph->table[i];
free (mygraph->table);
mygraph->table = newtable;
mygraph->MaxSize = newmaxsize;
};
mygraph->table[n].name = strdup(name);
mygraph->table[n].outdegree = 0;
}
You probably don't need insert_node to return a value (otherwise you won't always return 0). So I made it a void returning function (i.e. a "procedure" or "routine").
I have a queue of set length implemented as a dynamic c array implemented like this:
typedef struct {
float* queue;
int size;
int pointer;
} QueueStruct;
void createQueue(QueueStruct* queueInstance, int size){
queueInstance->queue = malloc(sizeof(float)*size);
queueInstance->size = size;
queueInstance->pointer = 0;
}
void addElementToQueue(QueueStruct* queueInstance,float element){
queueInstance->queue[pointer] = element;
if (queueInstance->pointer == queueInstance.size - 1){
queueInstance->pointer = 0;
} else {
++queueInstance->pointer;
}
}
void freeQueue(QueueStruct* queueInstance){
free(queueInstance->queue);
}
And I want to implement this function:
float* returnQueue(QueueStruct queueInstance){
//I want this function to malloc a new float* and then put the queue in it in the
// correct order, from start to finish, as pointed too by the pointer.
//Im not sure how to do this.
}
Any help would be appreciated.
Edit: Corrected a silly programming mistake - this is a simplified version of what is actually in my program.
Let's see if I got that right.
float* returnQueue(QueueStruct *queueInstance){
int j = 0;
float *ret = malloc(sizeof(float)*queueInstance->size); //Allocates the memory you want.
//Copies the elements from pointer to End into the new buffer (assumes, that the array has been filled at least once, add a marker to make sure)
if(queueInstance->FilledOnce) { //Marker variable, explanation as above.
for(int i = queueInstance->pointer; i < queueInstance->size; ++i, ++j)
ret[j] = queueInstance->queue[i];
}
//Copies the newest elements (from beginning to pointer) into the buffer.
for(int i = 0; i < queueInstance->pointer; ++i, ++j)
ret[j] = queueInstance->queue[i];
return ret; //Returns the code in question.
}
To make this code work, you'd have to add 'FilledOnce' to your struct, and amend your 'Add' Code as follows:
void addElementToQueue(QueueStruct* queueInstance, float element){
queueInstance->queue[queueInstance->pointer] = element;
if (queueInstance->pointer == queueInstance.size - 1){
queueInstance->pointer = 0;
queueInstance->FilledOnce = 1;
} else {
++queueInstance->pointer;
}
}
I also advise you, to reset your variables, once you're done with it.
void freeQueue(QueueStruct* queueInstance){
free(queueInstance->queue); //Frees the queue
queueInstance->queue = NULL; //Nulls the reference
queueInstance->FilledOnce = 0;
queueInstance->pointer = 0;
queueInstance->size = 0;
}
This way, if you reuse the struct, you won't run into the problem of trying to access non-allocated memory. Just be sure to check for those variables.
I hope this helps.
I think you should allocate memory for your struct also.
You have made pointer of struct but forgot to allocate memory for that struct
use QueueStruct queuestruct= malloc(sizeof(Queuestruct))
then when you pass this to any of the function above then you can easily allocate
memory for queue poiter in which you can store element for your queue array
This implementation is insufficient. A pointer variable give us location of a tail of queue, but what points to it's head?
I know how to build Dynamically allocated arrays, but not how to grow them.
for example I have the following interface..
void insertVertex( vertex p1, vertex out[], int *size);
This method takes a vertex and stores it into the out array. After storing the vertex I increase the count of length for future calls.
p1 - is the vertex I'm going to add.
out[] - is the array I need to store it in (which is always full)
length - the current length
Vertex is defined as..
typedef struct Vertex{
int x;
int y;
} Vertex;
This is what I'm using in Java..
Vertex tempOut = new Vertex[size +1];
//Code to deep copy each object over
tempOut[size] = p1;
out = tempOut;
This is what I believed I could use in c..
out = realloc(out, (*size + 1) * sizeof(Vertex));
out[(*size)] = p1;
However, I keep on receiving an error message that the object was not allocated dynamically.
I found a solution that will resolve this.. Instead of using Vertex* I was going to switch to Vertex** and store pointers vs. vertex. However, after switching everything over I found out that I over looked the fact that the unit test will be providing me a Vertex out[] that everything has to be stored in.
I have also tried the following with no luck.
Vertex* temp = (Vertex *)malloc((*size + 1) * sizeof(Vertex));
for(int i = 0; i < (*size); i++)
{
temp[i] = out[i];
}
out = temp;
However, no matter what I do when I test after both of these the array returned has not changed.
Update - Requested information
out - is defined as an array of Vertex (Vertex out[])
It is originally built with the number of vertex in my polygon. For example.
out = (Vertex *)malloc(vertexInPolygon * sizeof(Vertex))
Where vertexInPolygon is an integer of the number of vertex in the polygon.
length was a typo that should have been size.
Size is an integer pointer
int *size = 0;
Each time a vertex is in the clipping plane we add it to the array of vertex and increase the size by one.
Update
To better explain myself I came up with a short program to show what I'm trying to do.
#include <stdio.h>
#include <stdlib.h>
typedef struct Vertex {
int x, y;
} Vertex;
void addPointerToArray(Vertex v1, Vertex out[], int *size);
void addPointerToArray(Vertex v1, Vertex out[], int *size)
{
int newSize = *size;
newSize++;
out = realloc(out, newSize * sizeof(Vertex));
out[(*size)] = v1;
// Update Size
*size = newSize;
}
int main (int argc, const char * argv[])
{
// This would normally be provided by the polygon
int *size = malloc(sizeof(int)); *size = 3;
// Build and add initial vertex
Vertex *out = (Vertex *)malloc((*size) * sizeof(Vertex));
Vertex v1; v1.x = 1; v1.y =1;
Vertex v2; v2.x = 2; v2.y =2;
Vertex v3; v3.x = 3; v3.y =3;
out[0] = v1;
out[1] = v2;
out[2] = v3;
// Add vertex
// This should add the vertex to the last position of out
// Should also increase the size by 1;
Vertex vertexToAdd; vertexToAdd.x = 9; vertexToAdd.y = 9;
addPointerToArray(vertexToAdd, out, size);
for(int i =0; i < (*size); i++)
{
printf("Vertx: (%i, %i) Location: %i\n", out[i].x, out[i].y, i);
}
}
One long-term problem is that you are not returning the updated array pointer from the addPointerToArray() function:
void addPointerToArray(Vertex v1, Vertex out[], int *size)
{
int newSize = *size;
newSize++;
out = realloc(out, newSize * sizeof(Vertex));
out[(*size)] = v1;
// Update Size
*size = newSize;
}
When you reallocate space, it can move to a new location, so the return value from realloc() need not be the same as the input pointer. This might work while there is no other memory allocation going on while you add to the array because realloc() will extend an existing allocation while there is room to do so, but it will fail horribly once you start allocating other data while reading the vertices. There are a couple of ways to fix this:
Vertex *addPointerToArray(Vertex v1, Vertex out[], int *size)
{
int newSize = *size;
newSize++;
out = realloc(out, newSize * sizeof(Vertex));
out[(*size)] = v1;
// Update Size
*size = newSize;
return out;
}
and invocation:
out = addPointerToArray(vertexToAdd, out, size);
Alternatively, you can pass in a pointer to the array:
void addPointerToArray(Vertex v1, Vertex **out, int *size)
{
int newSize = *size;
newSize++;
*out = realloc(*out, newSize * sizeof(Vertex));
(*out)[(*size)] = v1;
// Update Size
*size = newSize;
}
and invocation:
out = addPointerToArray(vertexToAdd, &out, size);
Neither of these rewrites addresses the subtle memory leak. The trouble is, if you overwrite the value you pass into realloc() with the return value but realloc() fails, you lose the pointer to the (still) allocated array - leaking memory. When you use realloc(), use an idiom like:
Vertex *new_space = realloc(out, newSize * sizeof(Vertex));
if (new_space != 0)
out = new_space;
else
...deal with error...but out has not been destroyed!...
Note that using realloc() to add one new item at a time leads to (can lead to) quadratic behaviour. You would be better off allocating a big chunk of memory - for example, doubling the space allocated:
int newSize = *size * 2;
If you are worried about over-allocation, at the end of the reading loop, you can use realloc() to shrink the allocated space to the exact size of the array. However, there is then a bit more book-keeping to do; you need to values: the number of vertices allocated to the array, and the number of vertices actually in use.
Finally, for now at least, note that you should really be ruthlessly consistent and use addPointerToArray() to add the first three entries to the array. I'd probably use something similar to this (untested) code:
struct VertexList
{
size_t num_alloc;
size_t num_inuse;
Vertex *list;
};
void initVertexList(VertexList *array)
{
// C99: *array = (VertexList){ 0, 0, 0 };
// Verbose C99: *array = (VertexList){ .num_inuse = 0, .num_alloc = 0, .list = 0 };
array->num_inuse = 0;
array->num_alloc = 0;
array->list = 0;
}
void addPointerToArray(Vertex v1, VertexList *array)
{
if (array->num_inuse >= array->num_alloc)
{
assert(array->num_inuse == array->num_alloc);
size_t new_size = (array->num_alloc + 2) * 2;
Vertex *new_list = realloc(array->list, new_size * sizeof(Vertex));
if (new_list == 0)
...deal with out of memory condition...
array->num_alloc = new_size;
array->list = new_list;
}
array->list[array->num_inuse++] = v1;
}
This uses the counter-intuitive property of realloc() that it will do a malloc() if the pointer passed in is null. You can instead do a check on array->list == 0 and use malloc() then and realloc() otherwise.
You might notice that this structure simplifies the calling code too; you no longer have to deal with the separate int *size; in the main program (and its memory allocation); the size is effectively bundled into the VertexList structure as num_inuse. The main program might now start:
int main(void)
{
VertexList array;
initVertexList(&array);
addPointerToArray((Vertex){ 1, 1 }, &array); // C99 compound literal
addPointerToArray((Vertex){ 2, 2 }, &array);
addPointerToArray((Vertex){ 3, 3 }, &array);
addPointerToArray((Vertex){ 9, 9 }, &array);
for (int i = 0; i < array->num_inuse; i++)
printf("Vertex %d: (%d, %d)\n", i, array->list[i].x, array->list[i].y, i);
return 0;
}
(It is coincidental that this sequence will only invoke the memory allocation once because the new size (old_size + 2) * 2 allocates 4 elements to the array the first time. It is easy to exercise the reallocation by adding a new point, or by refining the formula to (old_size + 1) * 2, or ...
If you plan to recover from memory allocation failure (rather than just exiting if it happens), then you should modify addPointerToArray() to return a status (successful, not successful).
Also, the function name should probably be addPointToArray() or addVertexToArray() or even addVertexToList().
I have a few suggestions for your consideration:
1. Don't use the same input & output parameter while using realloc as it can return NULL in case memory allocation fails & the memory pointed previously is leaked. realloc may return new block of memory (Thanks to #Jonathan Leffler for pointing out, I had missed this out). You could change your code to something on these lines:
Vertex * new_out = realloc(out, newSize * sizeof(Vertex));
if( NULL != new_out )
{
out = new_out;
out[(*size)] = v1;
}
else
{
//Error handling & freeing memory
}
2. Add NULL checks for malloc calls & handle errors when memory fails.
3. Calls to free are missing.
4. Change the return type of addPointerToArray() from void to bool to indicate if the addition is successful. In case of realloc failure you can return failure say, false else you can return success say, true.
Other observations related to excessive copies etc, are already pointed out by #MatthewD.
And few good observations by #Jonathan Leffler (:
Hope this helps!
Your sample program works fine for me. I'm using gcc 4.1.1 on Linux.
However, if your actual program is anything like your sample program, it is rather inefficient!
For example, your program copies memory a lot: structure copies - initialising out, passing vertices to addPointerToArray(), memory copies via realloc().
Pass structures via a pointer rather than by copy.
If you need to increase the size of your list type a lot, you might be better off using a linked list, a tree, or some other structure (depending on what sort of access you require later).
If you simply have to have a vector type, a standard method of implementing dynamically-sized vectors is to allocate a block of memory (say, room for 16 vertices) and double its size everytime you run out of space. This will limit the number of required reallocs.
Try these changes , it should work.
void addPointerToArray(Vertex v1, Vertex (*out)[], int *size)
{
int newSize = *size;
newSize++;
*out = realloc(out, newSize * sizeof(Vertex));
*out[(*size)] = v1;
// Update Size
*size = newSize;
}
and call the function like
addPointerToArray(vertexToAdd, &out, size);
There is a simple way to fix these type of issue (you might already know this). When you pass a argument to a function, think what exactly goes on to the stack and then combine the fact that what ever changes you make to variables present on stack would vanish when come out the function. This thinking should solve most of the issues related to passing arguments.
Coming to the optimization part, picking the right data structure is critical to the success of any project. Like somebody pointed out above, link list is a better data structure for you than the array.