I got assigment from the professor to create a list using pointers. I'm having a problem with free() in all of my functions when I try to free memory. I keep getting a message:
"HEAP CORRUPTION DETECTED: after Normal block (#83) at 0x00D58CE0.
CRT detected that the application wrote to memory after end of heap buffer."
I have no idea how to fix it. I've tried different things but nothing worked so far. I'm not sure where to search for it either anymore. I know that my program is not properly secured yet, but it doesn't affect the problem. I'm trying to eliminate it first before going further with it. Also, do you have any advice on detecting memory leaks from the program in visual studio? Here are my functions, full source code is below in the link:
Full Source Code
struct ListElement
{
int value;
struct element *next;
};
typedef struct ListElement List;
typedef List *ListEl;
void ViewListBackwards(ListEl *list_el)
{
ListEl current_element = *list_el;
int size = 0;
int i = 0;
int *reversed_array;
while (current_element->next != NULL)
{
size++;
current_element = current_element->next;
}
current_element = *list_el;
reversed_array = (int*)malloc(size * sizeof(*reversed_array));
for (i = size; i >= 0; i--)
{
reversed_array[i] = current_element->value;
current_element = current_element->next;
}
for (i = 0; i <= size; i++)
{
printf(" %d. %d\n", i + 1, reversed_array[i]);
}
free(reversed_array);
}
void RemoveFromListFront(ListEl *list_el)
{
if (ListEmpty(list_el) == 0)
{
ListEl current_element = *list_el;
*list_el = current_element->next;
free(current_element);
}
else
{
printf("List is empty!\n");
}
}
void RemoveFromListBack(ListEl *list_el)
{
if (ListEmpty(list_el) == 0)
{
ListEl current_element = *list_el;
ListEl last_element = *list_el;
while (current_element->next != NULL)
{
last_element = current_element;
current_element = current_element->next;
}
last_element->next = NULL;
free(current_element);
}
}
In the following code:
reversed_array = (int*)malloc(size * sizeof(*reversed_array));
for (i = size; i >= 0; i--)
{
reversed_array[i] = current_element->value;
current_element = current_element->next;
}
for (i = 0; i <= size; i++)
{
printf(" %d. %d\n", i + 1, reversed_array[i]);
}
you are allocating (what amounts to) an int reversed_array[size] array, but then proceed to write to reversed_array[size], which is sizeof(int) past the end of the allocated memory segment.
You instead want to change your for loops to:
for (i = size - 1; i >= 0; i--)
so that the indices you write to start at reversed_array[size - 1].
EDIT:
As an aside, please, as other people have suggested in the comments, don't cast malloc(). This is unneeded in C, as void * can be assigned to any object pointer type variables, and in addition can hide bugs in your code, such as forgetting to include stdlib.h.
And FWIW, you don't need the parentheses around sizeof(*reversed_array), as parentheses are only needed when applying the sizeof operator to types.
This is mostly just a style suggestion; it is preferred by many (myself included) that you omit the extraneous parentheses and write that expression as sizeof *reversed_array, as that makes it clear that sizeof is a unary operator and not a function.
Related
I took it upon myself to develop a concurrent generic hash table in C.
Relevant contents of hash_table.h:
typedef struct list_node {
void * data;
struct list_node * next;
} list_node_t;
typedef struct hash_table {
int max_size;
int count;
list_node_t * * elements;
pthread_rwlock_t * locks;
pthread_rwlock_t global_table_lock;
hash_table_compare_function compare;
hash_table_hash_function hash;
} hash_table_t;
Relevant contents of hash_table.c:
#define LOCK_RD(lock) pthread_rwlock_rdlock(&lock);
#define LOCK_WR(lock) pthread_rwlock_wrlock(&lock);
#define UNLOCK(lock) pthread_rwlock_unlock(&lock);
bool
hash_table_remove(hash_table_t * table, void * element)
{
int hash_value = table->hash(element);
list_node_t * node, * prev;
LOCK_WR(table->locks[hash_value]);
node = table->elements[hash_value];
prev = NULL;
while (node) {
if (!table->compare(node->data, element)) {
// value is first item in the list
if (node == table->elements[hash_value]) {
table->elements[hash_value] = node->next;
free(node);
UNLOCK(table->locks[hash_value]);
LOCK_WR(table->global_table_lock);
table->count--;
UNLOCK(table->global_table_lock);
return true;
} else {
// link previous node with one after current
prev->next = node->next;
free(node);
UNLOCK(table->locks[hash_value]);
LOCK_WR(table->global_table_lock);
table->count--;
UNLOCK(table->global_table_lock);
return true;
}
}
prev = node;
node = node->next;
}
UNLOCK(table->locks[hash_value]);
return false;
}
I wrote a test case which uses strings, in which this is the relevant code:
#include "hashtable.h"
#define NUM_THREADS 2
#define NUM_STRINGS 154560
#define NUM_LOOKUPS 10000
void *
do_work(void * data)
{
int thread_id = *(int*)data;
// write "threadX.txt" to filename, where X is the given thread id
char filename[64];
strcpy(filename, "thread");
char thread_id_str[4];
sprintf(thread_id_str, "%d", thread_id);
strcat(filename, thread_id_str);
strcat(filename, ".txt");
FILE * file = fopen(filename, "r");
char buffer[128];
int i, num_str_per_thread = NUM_STRINGS / NUM_THREADS;
char * str_array[num_str_per_thread];
for (i = 0; i < num_str_per_thread; i++) {
fgets(buffer, 128, file);
str_array[i] = calloc((strlen(buffer) + 1), sizeof(char));
strcpy(str_array[i], buffer);
}
fclose(file);
for (i = 0; i < num_str_per_thread; i++)
hash_table_insert(table, str_array[i]);
for (i = 0; i < NUM_LOOKUPS; i++)
hash_table_contains(table, str_array[rand() % num_str_per_thread]);
for (i = 0; i < num_str_per_thread / 2; i++)
hash_table_remove(table, str_array[rand() % num_str_per_thread]);
//sleep(2); NOTE: no read errors reported if I leave this sleep() here.
for (i = 0; i < num_str_per_thread; i++)
if (str_array[i])
free(str_array[i]);
return NULL;
}
void
create_workers()
{
pthread_t threads[NUM_THREADS];
int ids[NUM_THREADS];
int i;
for (i = 0; i < NUM_THREADS; i++)
ids[i] = i + 1;
for (i = 0; i < NUM_THREADS; i++)
pthread_create(&threads[i], NULL, do_work, (void*)&ids[i]);
for (i = 0; i < NUM_THREADS; i++)
pthread_join(threads[i], NULL);
}
The test case is supposed to work as follows: there are two files, thread1.txt and thread2.txt, each containing unique strings I have generated beforehand. I create two threads, and each will read from a file and store each string on an array of strings called str_array. They will then insert all these strings into the hash table and perform random searches (hash_table_contains) and deletions (hash_table_remove). Then, each will free their respective array of strings. However, when I run this test case, Valgrind reports the following:
Please note that there are no memory leaks. What I get from these errors is that a thread is, upon calling hash_table_remove, attempting to free memory already freed by free(str_array[i]). However, that makes no sense, since hash_table_remove is called before free(str_array[i]. I can't figure out what's giving me these invalid reads.
Thank you in advance!
Here, your thread removes at most half the strings it inserted:
for (i = 0; i < num_str_per_thread / 2; i++)
hash_table_remove(table, str_array[rand() % num_str_per_thread]);
(in fact, it is most likely to remove about 39% of the strings it inserted).
Then, it goes on to free all the strings it inserted:
for (i = 0; i < num_str_per_thread; i++)
if (str_array[i])
free(str_array[i]);
However, at least half (and most likely ~61%) of those strings are still in the hash table, where the other threads will try to compare them as they scan through the chained hash bucket entries. That's your use-after-free error.
Instead of freeing all the strings, you could free them as you remove them:
for (i = 0; i < num_str_per_thread / 2; i++)
{
int str_index = rand() % num_str_per_thread;
if (str_array[str_index])
{
hash_table_remove(table, str_array[str_index]);
free(str_array[str_index]);
str_array[str_index] = NULL;
}
}
At this point, the non-NULL entries in str_array[] are the strings still present in the hash table. You can't free them until they're removed from the hash table (or the hash table is no longer in use).
The fact that your test case got this wrong is a good indicator that the ergonomics of your interface are not as good as they could be. You should probably consider a design in which the ownership of the strings inserted is transferred to the hash table, so that hash_table_remove() is itself responsible for freeing the string.
I am creating a deque to store stings in C, and when I call the free() function, the program crashes. I have implemented a similar structure but only storing integers, and encountered no problems, but this seems to be causing me a few. I created a struct containing a multidimensional array or characters, and i think maybe I am not using the pointers correctly? I have searched far and wide and cannot solve it The main area of concern is when i call clear() from the ain body. That in turn calls free(), and the program just stalls. :-( Any help would be extremely useful.
#include <stdio.h>
#define MAX 20 // number of characters for word
typedef struct {
char **deque;
int size;
int pFront;
int pRear;
} deque;
typedef int bool;
enum { false, true };
void initDeque(deque *d, int initialSize)
{
d->size = initialSize;
d->pFront = -1;
d->pRear = -1;
d->deque = (char **)malloc(sizeof(char*)*initialSize);
int idx;
for(int idx = 0; idx < d->size; idx++)
{
d->deque[idx] = (char *)malloc((MAX+1) * sizeof(char));
d->deque[idx] = "";
}
printf("d->size: %zu\n", d->size);
}
void clear(deque *d) {
if(d->pFront == -1)
{
printf("Queue is empty\n");
}
else
{
printf("Attempting to clear...\n");
for(int idx = 0; idx < d->size; idx++)
{
printf("Attempting to clear columns...");
free(d->deque[idx]);
}
printf("Attempting to clear rows...");
free(d->deque);
printf("Freed!!!!\n");
d->deque = NULL;
d->size = 0;
d->pFront = -1;
d->pRear = -1;
}
}
bool isEmpty(deque *d)
{
if(d->pFront == -1){
return true;
}
else
{
return false;
}
}
bool isFull(deque *d)
{
if(d->size == d->pRear+1)
{
return true;
}
else
{
return false;
}
}
void display(deque *d)
{
if(isEmpty(d)){
printf("empty\n");
}
else{
printf("Deque Values:\n");
int idx;
for(int idx = 0; idx <= d->pRear; idx++)
{
printf("Index: %zu\tValue: %s\n", idx, d->deque[idx]);
}
printf("Size: %zu\n", d->size);
}
}
void rAppend(deque *d, char item[]) // as in rear append - same enqueue for queue structure.
{
if(isFull(d))
{
printf("Is Full\n");
int idx;
deque dTemp;
initDeque(&dTemp, d->size);
printf("dTemp Initialised\n");
for(idx = 0; idx < d->size; idx++)
{
dTemp.deque[idx] = d->deque[idx];
}
printf("deque copied to dTemp:\n");
for(idx = 0; idx < d->size; idx++)
{
printf("dTemp[%zu]: %s\n", idx, dTemp.deque[idx]);
}
clear(&d);
printf("d cleared\n");
initDeque(&d, dTemp.size*2);
printf("New deque of double length initialised\n");
for(idx = 0; idx < dTemp.size; idx++)
{
d->deque[idx] = d->deque[idx];
}
printf("dTemp Copied to new deque\n");
clear(&dTemp);
printf("dTemp Cleared\n");
char **tmp = realloc( d->deque, sizeof (d->deque) * (d->size*2) );
if (tmp)
{
d->deque = tmp;
for (int i = 0; i < d->size; i++)
{
d->deque[d->size + i] = malloc( sizeof(char) * MAX );
}
}
}
printf("Appending to rear.. %s\n", item);
d->pRear++;
d->deque[d->pRear] = item;
if(d->pFront == -1)
d->pFront = 0;
}
int main(void)
{
deque d;
initDeque(&d, 5);
rAppend(&d, "when");
rAppend(&d, "will");
rAppend(&d, "wendy");
rAppend(&d, "walk");
rAppend(&d, "with");
display(&d);
clear(&d);
return 0;
}
The problem is your are calling free() on static chain "when", "will",...
You can replace insertion in the function void rAppend(deque *d, char item[]) :
d->deque[d->pRear] = item;
with:
d->deque[d->pRear] = strdup(item);
Doing like this chains are allocated in the heap and free from the heap.
After there is others problems in the code, but it run without crash.
The main problem seems to be that you don't appreciate the difference between copying / assigning pointers and copying / assigning the data to which they point. Secondarily, it seems you may not appreciate the utility of pointers that don't point to anything, especially null pointers. Some details follow.
You are dynamically allocating space for a bunch of strings ...
for(int idx = 0; idx < d->size; idx++)
{
d->deque[idx] = (char *)malloc((MAX+1) * sizeof(char));
... and then leaking all of that space by replacing the pointer to each with a pointer to an empty string literal:
d->deque[idx] = "";
}
As if the leak were not bad enough, you are not permitted to free a string literal or modify its content, which you nevertheless try to do to any of those pointers that remain in the dequeue whenever you clear() it. This is likely the cause of some of your errors.
If you want to set each allocated string to an empty one then modify its content instead of replacing the pointer to it. For example:
d->deque[idx][0] = '\0';
In fact, however, you probably don't need to do even that. You are already performing bookkeeping to know which arrays contain valid (string) data and which don't, and that should be sufficient to do the right thing. Supposing you maintain copies of the strings in the first place.
But that's not all. When you rAppend() elements to your deque you have a similar problem. You create a temporary deque, and then copy the string pointers from your original deque into the temporary:
dTemp.deque[idx] = d->deque[idx];
Not only does this leak the original (empty) data in the temporary deque, it aliases that deque's contents with the main deque's. When you later clear the temporary deque, therefore, you free all the string pointers in the original. Subsequently using or freeing them produces undefined behavior.
Perhaps you instead want to strcpy() all the elements of the main deque into the temp and back, but I suggest instead skipping the temp deque altogether with something along these lines:
void rAppend(deque *d, char item[]) // as in rear append - same enqueue for queue structure.
{
if(isFull(d))
{
printf("Is Full\n");
char **tmp = realloc(d.deque, d->size * 2);
if (tmp)
{
d->deque = tmp;
for (int i = 0; i < d->size; i++)
{
// Copied from the original, but see below
d->deque[d->size + i] = malloc( sizeof(char) * MAX );
}
d->size * 2;
} // else?
}
printf("Appending to rear.. %s\n", item);
d->pRear++;
// Oops, this is another leak / aliasing issue:
d->deque[d->pRear] = item;
if(d->pFront == -1)
d->pFront = 0;
}
The whole point of the temporary deque is lost on me, since the realloc() you need to do preserves the original data anyway (as long as it succeeds, anyway).
Note too, however, that this still has an aliasing issue: you have aliased a deque element with the appended string, and leaked the memory allocated for that element. Furthermore, when you clear the deque, you free that string for everyone holding a pointer to it. Or at least you attempt to do so. You're not permitted to do that to string literals.
I suggest not allocating space in your deque for the individual strings at all, and not freeing it. Continue to use assignment to store elements in your deque, understanding and embracing that these are aliases. This will be more analogous to your implementation for ints.
#include<memory>
#include<iostream>
using namespace std;
struct S {
S() { cout << "make an S\n"; }
~S() { cout << "destroy an S\n"; }
S(const S&) { cout << "copy initialize an S\n"; }
S& operator=(const S&) { cout << "copy assign an S\n"; }
};
S* f()
{
return new S; // who is responsible for deleting this S?
};
unique_ptr<S> g()
{
return make_unique<S>(); // explicitly transfer responsibility for deleting this S
}
int main()
{
cout << "start main\n";
S* p = f();
cout << "after f() before g()\n";
// S* q = g(); // this error would be caught by the compiler
unique_ptr<S> q = g();
cout << "exit main\n";
// leaks *p
// implicitly deletes *q
}
Disclaimer, this is help with a school assignment. That being said, my issue only occurs about 50% of the time. Meaning if I compile and run my code without edits sometimes it will make it through to the end and other times it will not. Through the use of multiple print statements I know exactly where the issue is occurring when it does. The issue occurs in my second call to hugeDestroyer(right after the print 354913546879519843519843548943513179 portion) and more exactly at the free(p->digits) portion.
I have tried the advice found here (free a pointer to dynamic array in c) and setting the pointers to NULL after freeing them with no luck.
Through some digging and soul searching I have learned a little more about how free works from (How do malloc() and free() work?) and I wonder if my issue stems from what user Juergen mentions in his answer and that I am "overwriting" admin data in the free list.
To be clear, my question is two-fold.
Is free(p->digits) syntactically correct and if so why might I have trouble half the time when running the code?
Secondly, how can I guard against this kind of behavior in my functions?
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct HugeInteger
{
// a dynamically allocated array to hold the digits of a huge integer
int *digits;
// the number of digits in the huge integer (approx. equal to array length)
int length;
} HugeInteger;
// Functional Prototypes
int str2int(char str) //converts single digit numbers contained in strings to their int value
{
return str - 48;
}
HugeInteger *parseInt(unsigned int n)
{
int i = 0, j = 0;
int *a = (int *)calloc(10, sizeof(int));
HugeInteger *p = (HugeInteger *)calloc(1, sizeof(HugeInteger));
if(n == 0)
{
p->digits = (int *)calloc(1, sizeof(int));
p->length = 1;
return p;
}
while(n != 0)
{
a[i] = n % 10;
n = n / 10;
i++;
}
p->length = i;
p->digits = (int *)calloc(p->length, sizeof(int));
for(i = 0; i <= p->length; i++, j++)
p->digits[j] = a[i];
return p;
}
HugeInteger *parseString(char *str) //notice datatype is char (as in char array), so a simple for loop should convert to huge int array
{
int i = 0, j = 0;
HugeInteger *p = (HugeInteger *)calloc(1, sizeof(HugeInteger));
if(str == NULL)
{
free(p);
p = NULL;
return p;
}
else
{
for(i=0; str[i] != '\0'; i++)
;
p->length = i;
p->digits = (int *)calloc(p->length, sizeof(int));
for(; i >= 0; i--)
p->digits[j++] = str2int(str[i - 1]);
}
return p;
} //end of HugeInteger *parseString(char *str)
HugeInteger *hugeDestroyer(HugeInteger *p)
{
//printf("No problem as we enter the function\n");
if(p == NULL)
return p;
//printf("No problem after checking for p = NULL\n");
if(p->digits == NULL)
{
free(p);
p = NULL;
return p;
}
//printf("No Problem after checking if p->digits = NULL\n");
//else
//{
free(p->digits);
printf("We made it through free(p->digits)\n");
p->digits = NULL;
printf("We made it through p->digits = NULL\n");
free(p);
printf("We made it through free(p)\n");
p = NULL;
printf("We made it through p = NULL\n");
return p;
//}
//return NULL;
}//end of HugeInteger *hugeDestroyer(HugeInteger *p)
// print a HugeInteger (followed by a newline character)
void hugePrint(HugeInteger *p)
{
int i;
if (p == NULL || p->digits == NULL)
{
printf("(null pointer)\n");
return;
}
for (i = p->length - 1; i >= 0; i--)
printf("%d", p->digits[i]);
printf("\n");
}
int main(void)
{
HugeInteger *p;
hugePrint(p = parseString("12345"));
hugeDestroyer(p);
hugePrint(p = parseString("354913546879519843519843548943513179"));
hugeDestroyer(p);
hugePrint(p = parseString(NULL));
hugeDestroyer(p);
hugePrint(p = parseInt(246810));
hugeDestroyer(p);
hugePrint(p = parseInt(0));
hugeDestroyer(p);
hugePrint(p = parseInt(INT_MAX));
hugeDestroyer(p);
//hugePrint(p = parseInt(UINT_MAX));
//hugeDestroyer(p);
return 0;
}
First of all, really outstanding question. You did a lot of research on topic and generally speaking, solved this issue by yourself, I'm here mainly to confirm your findings.
Is free(p->digits) syntactically correct and if so why might I have trouble half the time when running the code?
Syntax is correct. #Shihab suggested in comments not to release p->digits and release p only, but such suggestion is wrong, it leads to memory leakages. There is a simple rule: for each calloc you must eventually call free, so your current approach in freeing p->digits and then p is totally fine.
However, program fails on a valid line. How is it possible? Quick answer: free can't do its work due to corruption of meta information responsible for tracking allocated/free blocks lists. At some point program corrupted meta information, but this was revealed only on attempt to use it.
As you already discovered, in most implementations memory routines such as calloc results into allocation of buffer with prepended meta-info. You receives pointer to buffer itself, but small piece of information right before this pointer is crucial for further buffer managing (e.g. freeing). Writing 11 integers into buffer intended for 10, you're likely to corrupt meta-info of block following the buffer. Whether corruption actually happens and what would be its consequences, is heavily dependent on both implementation specifics and current memory alignment (what block follows the buffer, what exactly meta-data is corrupted). It doesn't surprise me, that you see one crash per two executions, neither surprises me observing 100% crash reproduction on my system.
Secondly, how can I guard against this kind of behavior in my functions?
Let's start with fixing overflows. There are couple of them:
parseString: loop for(; i >= 0; i--) is executed length+1 times, so p->digits is overflown
parseInt: loop for (i = 0; i <= p->length; i++, j++) is executed length+1 times, so p->digits is overflown
Direct access to memory managing in C++ is error prone and troublesome to debug. Memory leakages and buffers overflows are the worst nightmare in programmers life, it's usually better to simplify/reduce direct usage of dynamic memory, unless you are studying to cope with it, of course. If you need to stick with a lot of direct memory managing, take a look at valgrind, it's intended to detect all such things.
By the way, there is also a memory leakage in your program: each call to parseInt allocates buffer for a, but never frees it.
I have an array which has a key and info for each index in the array.
This builds the array
table_t *table_construct (int table_size, int probe_type)
{
int i;
table_t *hash;
if(table_size < 1) return NULL;
hash = malloc(sizeof(table_t));
hash->table = malloc(sizeof(list_t*) * table_size);
for(i=0; i < table_size - 1; i++)
{
hash->table[i] = NULL;
//hash->table[i]->next = NULL;
}
hash->size = table_size;
hash->probing_type = probe_type;
return hash;
}
So I have the list_t and the table_t structures. I have the following line in my code that is not working correctly:
hash->table[item]->K = K;
It can be seen in this part of my code:
int dec, item, hold;
item = hashing(hash,K);
hold = item;
if(hash->table[item] == NULL)
{
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
When I GDB it, K is a number.
So what is happening here is, I have my table which is indexed with item. Then I add K to the key of the index. When ever this line comes up anywhere in my program I get a seg Fault.
Can you see anything Ive done wrong here?
You verified your pointer is null, so before you can reference off it you need to assign it something:
if(hash->table[item] == NULL)
{
hash->table[item] = malloc(sizeof(list_t)); // you were missing this.
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
According to what you posted in your table_construct function, the elements of table array are null pointers. You are not allowed to perform any kind of access through null pointers.
And this just doesn't make sense
if(hash->table[item] == NULL)
{
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
Here you make an explicit attempt to write data through a null pointer.
You have to make sure a pointer points to a valid object before you make any attempts to access anything (write or read) through that pointer.
In your function table_construct,when you malloc hash->table,you should do it like this.
hash->table = (list_t **)malloc(sizeof(list_t*) * table_size);
for (i=0;i<table_size;i++)
{
hash->table[i] = (list_t *)malloc(sizeof(list_t));
}
You do that made then null,if you want to do like this.
memset(hash->table[i],0,sizeof(list_t));
Then you can use this judgment statement.
if(hash->table[item] != NULL)
{
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
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?