Free list implementation not working properly - c

So, I have been assigned a task to implement a free list. A list where items that are going to be free:d are added to and later the list is free:d in one go. I have written the following:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct list_t list_t;
struct list_t {
list_t* succ;
list_t* pred;
void* data;
};
list_t* free_list;
void free_list_memory(void)
{
list_t *p , *q;
p = free_list;
while (p != NULL) {
q = p->succ;
free(p);
p = q;
}
}
void add_to_free_list(list_t* add) {
if (free_list != NULL) {
add->pred = free_list->pred;
add->succ = free_list;
free_list->pred->succ = add;
free_list->pred = add;
} else {
free_list = add;
add->succ = add;
add->pred = add;
}
}
static double sec(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + 1e-6 * tv.tv_usec;
}
int empty(list_t* list)
{
return list == list->succ;
}
list_t *new_list(void* data)
{
list_t* list;
list = malloc(sizeof(list_t));
assert(list != NULL);
list->succ = list->pred = list;
list->data = data;
return list;
}
void add(list_t* list, void* data)
{
list_t* link;
list_t* temp;
link = new_list(data);
list->pred->succ= link;
link->succ = list;
temp = list->pred;
list->pred = link;
link->pred = temp;
}
void take_out(list_t* list)
{
list->pred->succ = list->succ;
list->succ->pred = list->pred;
list->succ = list->pred = list;
}
void* take_out_first(list_t* list)
{
list_t* succ;
void* data;
if (list->succ->data == NULL)
return NULL;
data = list->succ->data;
succ = list->succ;
take_out(succ);
free(succ);
return data;
}
static size_t nextsize()
{
#if 1
return rand() % 4096;
#else
size_t size;
static int i;
static size_t v[] = { 24, 520, 32, 32, 72, 8000, 16, 24, 212 };
size = v[i];
i = (i + 1) % (sizeof v/ sizeof v[0]);
return size;
#endif
}
static void fail(char* s)
{
fprintf(stderr, "check: %s\n", s);
abort();
}
int main(int ac, char** av)
{
int n = 50; /* mallocs in main. */
int n0;
list_t* head;
double begin;
double end;
double t = 2.5e-9;
if (ac > 1)
n = atoi(av[1]);
n0 = n;
head = new_list(NULL);
printf("check starts\n");
begin = sec();
while (n > 0) {
add(head, malloc(nextsize()));
n -= 1;
if ((n & 1) && !empty(head)) {
add_to_free_list(take_out_first(head)); //before free(take_out_first(head))
}
}
printf("Done");
while (!empty(head))
add_to_free_list(take_out_first(head)); //before free(take_out_first(head))
free_list_memory(); //added line
end = sec();
printf("check is ready\n");
printf("total = %1.3lf s\n", end-begin);
printf("m+f = %1.3g s\n", (end-begin)/(2*n0));
printf("cy = %1.3lf s\n", ((end-begin)/(2*n0))/t);
return 0;
}
Running the code gives:
a.out(10009,0x7fff79ec0300) malloc: *** error for object 0x7fe160c04b20: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
DoneAbort trap: 6
Running in valgrind gives:
check starts
==10011== Invalid read of size 8
==10011== at 0x1000009B8: free_list_memory (check.c:20)
==10011== by 0x100000D8B: main (check.c:163)
==10011== Address 0x10081e270 is 0 bytes inside a block of size 423 free'd
==10011== at 0x10000894F: free (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==10011== by 0x1000009CA: free_list_memory (check.c:21)
==10011== by 0x100000D8B: main (check.c:163)
==10011==
==10011== Invalid free() / delete / delete[] / realloc()
==10011== at 0x10000894F: free (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==10011== by 0x1000009CA: free_list_memory (check.c:21)
==10011== by 0x100000D8B: main (check.c:163)
==10011== Address 0x10081e270 is 0 bytes inside a block of size 423 free'd
==10011== at 0x10000894F: free (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==10011== by 0x1000009CA: free_list_memory (check.c:21)
==10011== by 0x100000D8B: main (check.c:163)
==10011==
==10011==
==10011== More than 10000000 total errors detected. I'm not reporting any more.
==10011== Final error counts will be inaccurate. Go fix your program!
==10011== Rerun with --error-limit=no to disable this cutoff. Note
==10011== that errors may occur in your program without prior warning from
==10011== Valgrind, because errors are no longer being displayed.
==10011==
^C==10011==
==10011== HEAP SUMMARY:
==10011== in use at exit: 38,785 bytes in 423 blocks
==10011== total heap usage: 602 allocs, 6,176,342 frees, 149,153 bytes allocated
==10011==
==10011== LEAK SUMMARY:
==10011== definitely lost: 0 bytes in 0 blocks
==10011== indirectly lost: 0 bytes in 0 blocks
==10011== possibly lost: 0 bytes in 0 blocks
==10011== still reachable: 4,120 bytes in 2 blocks
==10011== suppressed: 34,665 bytes in 421 blocks
==10011== Rerun with --leak-check=full to see details of leaked memory
==10011==
==10011== For counts of detected and suppressed errors, rerun with: -v
==10011== ERROR SUMMARY: 10000000 errors from 2 contexts (suppressed: 0 from 0)
Now, I don't understand what's wrong since I am removing elements from the list that have been created using malloc...

As WhozCraig diagnosed, the problem is more that the code does not stop when it gets to the end of the free list because it is a circular list and the termination condition is looking for null pointers that don't exist.
You can fix most of the problems by rewriting free_list_memory() as:
static void free_list_memory(void)
{
if (free_list == 0)
return;
list_t *p = free_list;
do
{
list_t *q = p->succ;
// free(p->data); // Removed: see commentary below!
free(p);
p = q;
} while (p != free_list);
}
With that change, I get one unfreed memory block of size 24 (on a 64-bit build). So there is one list_t not being freed. That item is in head; it happens to have a NULL data pointer, so you can fix that final leak with:
free(head);
at the end of main().
Surprise!
At one time, I commented:
You also need to free the data as well as the list entry.
Somewhat to my surprise, on retesting, that isn't necessary. In fact, on my machine, in free_list_memory(), all the data pointers are null. That's actually unfortunate — malloc() is returning zeroed data. What actually happens is that the list freeing code releases the original list_t pointer that held the data, and then adds the original data pointer to the free list, treating it as a list_t structure. That gets iffy if the size of the allocated block (a random number from nextsize()) is smaller than a list_t.
To fix the problems and get a really clean run, even with different numbers of entries, I created this instrumented version of the code (with WhozCraig's function active).
Revised code
Note that the code ensures that the space allocated is at least as big as a list_t structure; that is crucial to avoid memory access errors (on longer runs; I used 200 to get problems with small allocations without adding sizeof(list_t) because it so happens that the first 50 allocations are always big enough).
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
typedef struct list_t list_t;
struct list_t {
list_t* succ;
list_t* pred;
void* data;
};
list_t* free_list;
static
void free_list_memory(void)
{
if (!free_list)
return;
// terminate "last" node (the node that refers
// back to the node pointed to by free_list,
// including a potential self-referencing node)
free_list->pred->succ = NULL;
// now run the loop. uses free_list as the iterator
// as it will finish with NULL, as it will be empty.
while (free_list)
{
void *p = free_list;
if (free_list->data == 0)
printf("2 %p: data is null\n", free_list);
//free(free_list->data); // Not necessary
free_list = free_list->succ;
free(p);
}
}
#if 0
static void free_list_memory(void)
{
if (free_list == 0)
return;
list_t *p = free_list;
do
{
list_t *q = p->succ;
// free(p->data); // Removed: see commentary below!
free(p);
p = q;
} while (p != free_list);
}
#endif
#if 0
/* Broken code from question - does not handle circular list */
void free_list_memory(void)
{
list_t *p , *q;
p = free_list;
while (p != NULL) {
q = p->succ;
free(p);
p = q;
}
}
#endif
static
void add_to_free_list(list_t* add) {
if (free_list != NULL) {
add->pred = free_list->pred;
add->succ = free_list;
free_list->pred->succ = add;
free_list->pred = add;
} else {
free_list = add;
add->succ = add;
add->pred = add;
}
add->data = 0; // Added to avoid access to uninitialized data warning from valgrind
}
static double sec(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + 1e-6 * tv.tv_usec;
}
static
int empty(list_t* list)
{
return list == list->succ;
}
static
list_t *new_list(void* data)
{
list_t* list;
list = malloc(sizeof(list_t));
printf("1: data address is %p\n", data);
assert(list != NULL);
list->succ = list->pred = list;
list->data = data;
return list;
}
static
void add(list_t* list, void* data)
{
list_t* link;
list_t* temp;
link = new_list(data);
list->pred->succ= link;
link->succ = list;
temp = list->pred;
list->pred = link;
link->pred = temp;
}
static
void take_out(list_t* list)
{
list->pred->succ = list->succ;
list->succ->pred = list->pred;
list->succ = list->pred = list;
}
static
void* take_out_first(list_t* list)
{
list_t* succ;
void* data;
if (list->succ->data == NULL)
{
printf("3: %p - data is null\n", list->succ);
return NULL;
}
data = list->succ->data;
succ = list->succ;
take_out(succ);
free(succ);
return data;
}
static size_t nextsize(void)
{
#if 1
size_t v = rand() % 4096 + sizeof(list_t);
printf("Size: %zu\n", v);
return v;
//return rand() % 4096;
#else
size_t size;
static int i;
static size_t v[] = { 24, 520, 32, 32, 72, 8000, 16, 24, 212 };
size = v[i];
i = (i + 1) % (sizeof v/ sizeof v[0]);
return size;
#endif
}
#if 0
static void fail(char* s)
{
fprintf(stderr, "check: %s\n", s);
abort();
}
#endif
int main(int ac, char** av)
{
int n = 50; /* mallocs in main. */
int n0;
list_t* head;
double begin;
double end;
double t = 2.5e-9;
if (ac > 1)
n = atoi(av[1]);
n0 = n;
head = new_list(NULL);
printf("check starts\n");
begin = sec();
while (n > 0) {
add(head, malloc(nextsize()));
n -= 1;
if ((n & 1) && !empty(head)) {
add_to_free_list(take_out_first(head)); //before free(take_out_first(head))
}
}
printf("Done\n");
while (!empty(head))
add_to_free_list(take_out_first(head)); //before free(take_out_first(head))
free_list_memory(); //added line
free(head);
end = sec();
printf("Check is ready\n");
printf("total = %1.3lf s\n", end-begin);
printf("m+f = %1.3g s\n", (end-begin)/(2*n0));
printf("cy = %1.3lf s\n", ((end-begin)/(2*n0))/t);
return 0;
}
The compilation options I habitually use (here I suppressed optimization to avoid having everything inlined in main()) require declarations of non-static functions, so I added static to each function except main() that was not already static. I also added (void) in place of () when necessary.
$ gcc -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror crashing.c -o crashing
$
Valgrind output
$ valgrind --leak-check=full --suppressions=suppressions crashing 10
==41722== Memcheck, a memory error detector
==41722== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==41722== Using Valgrind-3.11.0.SVN and LibVEX; rerun with -h for copyright info
==41722== Command: crashing 10
==41722==
--41722-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option
--41722-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 2 times)
--41722-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 4 times)
1: data address is 0x0
check starts
Size: 447
1: data address is 0x10083f3e0
Size: 2825
1: data address is 0x100842440
Size: 3313
1: data address is 0x100842f90
Size: 3138
1: data address is 0x100843cd0
Size: 1946
1: data address is 0x10083f760
Size: 2784
1: data address is 0x100844960
Size: 3824
1: data address is 0x100845480
Size: 2582
1: data address is 0x100846410
Size: 3931
1: data address is 0x100846ed0
Size: 1125
1: data address is 0x100847ed0
Done
2 0x10083f3e0: data is null
2 0x100842440: data is null
2 0x100842f90: data is null
2 0x100843cd0: data is null
2 0x10083f760: data is null
2 0x100844960: data is null
2 0x100845480: data is null
2 0x100846410: data is null
2 0x100846ed0: data is null
2 0x100847ed0: data is null
Check is ready
total = 0.010 s
m+f = 0.000487 s
cy = 194959.641 s
==41722==
==41722== HEAP SUMMARY:
==41722== in use at exit: 39,132 bytes in 430 blocks
==41722== total heap usage: 528 allocs, 98 frees, 71,359 bytes allocated
==41722==
==41722== LEAK SUMMARY:
==41722== definitely lost: 0 bytes in 0 blocks
==41722== indirectly lost: 0 bytes in 0 blocks
==41722== possibly lost: 0 bytes in 0 blocks
==41722== still reachable: 26,034 bytes in 311 blocks
==41722== suppressed: 13,098 bytes in 119 blocks
==41722== Reachable blocks (those to which a pointer was found) are not shown.
==41722== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==41722==
==41722== For counts of detected and suppressed errors, rerun with: -v
==41722== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 15)
$
And you can see from the printed pointer values that the data added to the free list is indeed the data rather than the list_t structures holding the data.
It would be more conventional (and arguably sensible) to simply move the entire list_t structure from the active list to the free list, rather than freeing the list_t structure and using the data as the list_t structure on the free list.
Also, you should probably record the size of the data so you know whether the stuff on the free list can be used for a particular allocation.

Assuming the rest of your code is correct (and that is a big assumption), your free_memory_list function doesn't account for the fact the list is circular. The last node succ member refers back to the address held in free_list.
If that is the case, this is more akin to what you need:
void free_list_memory(void)
{
if (!free_list)
return;
// terminate "last" node (the node that refers
// back to the node pointed to by free_list,
// including a potential self-referencing node)
free_list->pred->succ = NULL;
// now run the loop. uses free_list as the iterator
// as it will finish with NULL, as it will be empty.
while (free_list)
{
void *p = free_list;
free_list = free_list->succ;
free(p);
}
}
I have to be honest. I did not diagnose the rest of this, but this is a glaring problem if this list is indeed circular.
Best of luck.

Why are you using double linked (closed loop) list for your free list, if only go in one direction.
Your void free_list_memory(void) function crashes when trying to run a second time over your list.
Maybe this helps:
void add_to_free_list(list_t* add) {
if (free_list != NULL) {
free_list->succ = add;
add->succ = NULL;
} else {
free_list = add;
add->succ = NULL;
}
}

Related

valgrind error in freeing memory of a linked list

I am getting myself familiar with the linked list and dynamic memory.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char *name; // name of student
char ID[7]; // student ID (nul terminated)
// you may add fields to this structure if needed
} Student;
typedef struct Course_st {
// add fields here
Student *Student_list;
struct Course * next;
} Course;
// kirjoita ohjelma tähän
int main()
{
Course *course_1 = (Course*)malloc(1*sizeof(Course));
Student *st_1 =malloc(sizeof(Student));
st_1->name = malloc(5*sizeof(char));
strcpy(st_1->name,"Hien");
strcpy(st_1->ID,"001");
course_1->Student_list = st_1;
course_1->next = malloc(sizeof(Course));
Student *st_2 = malloc(4*sizeof(Student));
st_2->name = malloc(4*sizeof(char));
strcpy(st_2->name,"Kim");
strcpy(st_2->ID,"002");
Course* next = (Course*) course_1->next;
next->Student_list = st_2;
next->next= NULL;
while(course_1 != NULL)
{
printf("%s %s\n", course_1->Student_list->name, course_1->Student_list->ID);
free(course_1->Student_list->name);
free(course_1->Student_list);
course_1 = (Course*)course_1->next;
}
free(next);
}
and I got back this error...
in use at exit: 16 bytes in 1 blocks
total heap usage: 7 allocs, 6 frees, 4,217 bytes allocated
16 bytes in 1 blocks are definitely lost in loss record 1 of 1
at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x1086EB: main (teht3.c:21)
LEAK SUMMARY:
definitely lost: 16 bytes in 1 blocks
...
For counts of detected and suppressed errors, rerun with: -v
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Everything you allocate with malloc(...) should also be released with free(...). In your case, you do not free course_1. So the solution should be:
Course * tmp = course_1;
Course * tmp_next;
while(tmp != NULL)
{
printf("%s %s\n", tmp->Student_list->name, tmp->Student_list->ID);
free(tmp->Student_list->name);
free(tmp->Student_list);
tmp_next = tmp->next;
free(tmp);
tmp = tmp_next;
}
I would change the end of your program like this
Course *old_course_1=course_1;
course_1 = (Course*)course_1->next;
free(old_course_1);
}
// free(next);
This way, you free course_1 as soon as you consider the next one; thus the
last call to free(next) is not necessary.
You were correctly freeing the dynamic parts of course_1 but not
course_1 itself.

Printing just some elements of a List using pointers

Create a function that receives two Lists (L1,L2), initialize L2, and insert in L2 the elements of L1 excluding the ones in odd postion (Assume that the first element of the list is in position zero). Then print L2.
My prof gave us the solution (below), but I need to create a main() that calls this function and returns L2, and since I'm a newbie nothing seems to work.
I tried initializing L1 and then calling the function, but all I got was a huge amount of errors.
That's the final function:
struct list{
int value;
struct list * nextPtr;
};
void createSubList(struct list * l1Ptr, struct list ** l2PtrPtr) {
init(l2PtrPtr);
while(l1Ptr!=NULL) {
pre_insert(l2PtrPtr, l1Ptr­>value);
l1Ptr = l1Ptr­>nextPtr;
if (l1Ptr != NULL)
l1Ptr = l1Ptr­>nextPtr;
}
}
I expect to see L2 printed after calling the function.
That's my final file:
#include <stdlib.h>
#include <string.h>
struct list {
int value;
struct list *nextPtr;
};
void init( struct list **ptrptr){
*ptrptr!=NULL;
}
void prn (struct list * lptr) {
while (lptr) {
printf (" %d", lptr->value);
lptr = lptr->nextPtr;
}
putchar ('\n'); }
void pre_insert(struct list ** ptrptr, int value){
struct list * tmp_ptr;
tmp_ptr=*ptrptr;
*ptrptr=(struct list *)malloc(sizeof(struct list));
(*ptrptr)->value=value;
(*ptrptr)->nextPtr=tmp_ptr;
}
void createSubList(struct list* l1Ptr, struct list** l2PtrPtr) {
init(l2PtrPtr);
while(l1Ptr!=NULL) {
pre_insert(l2PtrPtr, l1Ptr->value);
l1Ptr = l1Ptr->nextPtr;
if (l1Ptr != NULL)
l1Ptr = l1Ptr->nextPtr;
}
prn(l1Ptr);
}
void main(){
struct list* l1Ptr;
init(&l1Ptr);
struct list* l2ptr;
init(&l2ptr);
pre_insert(&l1Ptr , 1);
pre_insert(&l1Ptr , 2);
pre_insert(&l1Ptr , 3);
pre_insert(&l1Ptr , 4);
pre_insert(&l1Ptr , 5);
pre_insert(&l1Ptr , 6);
createSubList(l1Ptr,&l2ptr);
}
Errors I get:
[Finished in 0.1s with exit code -11]
[shell_cmd: gcc "/home/vittorio/Scrivania/CProjects/new.c" -o "/home/vittorio/Scrivania/CProjects/new" && "/home/vittorio/Scrivania/CProjects/new"]
[dir: /home/vittorio/Scrivania/CProjects]
[path: /home/vittorio/bin:/home/vittorio/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin]
Once you get the non-ASCII chars squared away. Take your implementation piece-by-piece. For starters, unless you are on a non-conforming system, the proper declarations for main are int main (void) and int main (int argc, char **argv) (which you will see written with the equivalent char *argv[]). note: main is a function of type int and it returns a value. See: C11 Standard §5.1.2.2.1 Program startup p1 (draft n1570). See also: What should main() return in C and C++?.
So, for conforming implementation, main() without arguments should be:
int main (void) {
struct list *l1Ptr = NULL;
struct list *l2ptr = NULL;
...
(note: just ditch your init() function, you don't need to function call overhead just to set a pointer NULL)
Next issue along the way is your pre_insert must distinguish between adding the 1st node to the list, and adding all others. For the 1st node, just set your *ptrptr to your initialize tmp_ptr to establish the head of the list. For the remaining nodes, you are using chaining where you set tmp_ptr->nextPtr = *ptrptr; to make the next pointer in the new node point to the old-start of your list, then set *ptrptr = tmp_ptr; to make it your new start of the list, e.g.
void pre_insert (struct list **ptrptr, int value)
{
struct list *tmp_ptr = malloc (sizeof *tmp_ptr); /* don't cast malloc */
if (tmp_ptr == NULL) { /* validate EVERY allocation */
perror ("malloc-tmp_ptr");
exit (EXIT_FAILURE);
}
tmp_ptr->value = value; /* initialize struct members */
tmp_ptr->nextPtr = NULL;
if (!*ptrptr) /* if 1st node, simply assign */
*ptrptr = tmp_ptr;
else {
tmp_ptr->nextPtr = *ptrptr; /* otherwise, set tmp->next to 1st */
*ptrptr = tmp_ptr; /* now set list to point to tmp */
}
}
Your createSubList had similar redundant logic, showing your were struggling. All you need is a simply 1/0 toggle to add or skip nodes from list1. For example:
void createSubList (struct list *l1Ptr, struct list **l2PtrPtr)
{
int i = 0;
while (l1Ptr != NULL) {
if (i == 0) { /* only store even nodes */
pre_insert (l2PtrPtr, l1Ptr->value);
i = 1;
}
else
i = 0;
l1Ptr = l1Ptr->nextPtr;
}
}
As discussed in the comments, you need a way to print your lists, and equally important, a way to free the memory allocated to the nodes where you are done with them. Simple functions are all you need, e.g.
void prnlist (struct list *lptr)
{
while (lptr) {
printf (" %d", lptr->value);
lptr = lptr->nextPtr;
}
putchar ('\n');
}
void freelist (struct list *lptr)
{
while (lptr) {
struct list *victim = lptr;
lptr = lptr->nextPtr;
free (victim);
}
}
(note: do you see why you have to save a pointer to the current node, and then advance the node before calling free on your victim?)
That's it, aside from my additional comments in-line. Putting it altogether you could do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
int value;
struct list *nextPtr;
};
void pre_insert (struct list **ptrptr, int value)
{
struct list *tmp_ptr = malloc (sizeof *tmp_ptr); /* don't cast malloc */
if (tmp_ptr == NULL) { /* validate EVERY allocation */
perror ("malloc-tmp_ptr");
exit (EXIT_FAILURE);
}
tmp_ptr->value = value; /* initialize struct members */
tmp_ptr->nextPtr = NULL;
if (!*ptrptr) /* if 1st node, simply assign */
*ptrptr = tmp_ptr;
else {
tmp_ptr->nextPtr = *ptrptr; /* otherwise, set tmp->next to 1st */
*ptrptr = tmp_ptr; /* now set list to point to tmp */
}
}
void createSubList (struct list *l1Ptr, struct list **l2PtrPtr)
{
int i = 0;
while (l1Ptr != NULL) {
if (i == 0) { /* only store even nodes */
pre_insert (l2PtrPtr, l1Ptr->value);
i = 1;
}
else
i = 0;
l1Ptr = l1Ptr->nextPtr;
}
}
void prnlist (struct list *lptr)
{
while (lptr) {
printf (" %d", lptr->value);
lptr = lptr->nextPtr;
}
putchar ('\n');
}
void freelist (struct list *lptr)
{
while (lptr) {
struct list *victim = lptr;
lptr = lptr->nextPtr;
free (victim);
}
}
int main (void) {
struct list *l1Ptr = NULL;
struct list *l2ptr = NULL;
for (int i = 1; i < 10; i++)
pre_insert (&l1Ptr , i);
createSubList (l1Ptr, &l2ptr);
prnlist (l2ptr); /* print list 2 */
freelist (l1Ptr); /* don't forget to free what you allocate */
freelist (l2ptr);
}
Example Use/Output
$ ./bin/llcreatesublist
1 3 5 7 9
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/llcreatesublist
==23324== Memcheck, a memory error detector
==23324== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23324== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==23324== Command: ./bin/llcreatesublist
==23324==
1 3 5 7 9
==23324==
==23324== HEAP SUMMARY:
==23324== in use at exit: 0 bytes in 0 blocks
==23324== total heap usage: 14 allocs, 14 frees, 224 bytes allocated
==23324==
==23324== All heap blocks were freed -- no leaks are possible
==23324==
==23324== For counts of detected and suppressed errors, rerun with: -v
==23324== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
You need to add #include <stdio.h>
In the init function the code *ptrptr!=NULL; shall be *ptrptr=NULL;, i.e. no !
Then change void main(){ to int main(){
That should solve the warnings.
Then you need to do the actual printing. So in main do:
prn(l1Ptr);
createSubList(l1Ptr,&l2ptr);
prn(l2ptr);
BTW: Notice that the prn(l1Ptr); inside createSubList will not print anything as l1Ptr is already NULL when you call prn. So you should simply delete that line.
With the above change your output should be:
6 5 4 3 2 1
2 4 6
The created sub-list is reverted compared to the original list due to use of pre_insert that adds new nodes in the front.

c - how to correctly free elements on a hash table

I'm doing a program where I have a hash table in which the elements have a structure of this type
typedef struct _msg_list{
message_t *msg;
struct _msg_list *next;
}msg_list;
typedef struct _hash_elem{
char *nickname;
int nmsg;
msg_list *msg_head;
msg_list *msg_corr;
}hash_elem;
where msg_list is a pointer to a list of received messages. messages have this structure.
typedef struct {
int op;
char sender[33];
} message_hdr_t;
typedef struct {
char receiver[33];
unsigned int len;
} message_data_hdr_t;
typedef struct {
message_data_hdr_t hdr;
char *buf;
} message_data_t;
typedef struct {
message_hdr_t hdr;
message_data_t data;
} message_t;
When I call the freeHashData function to clean memory valgrind gives me this output
==4709== Memcheck, a memory error detector
==4709== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4709== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==4709== Command: ./chatty
==4709==
==4709==
==4709== HEAP SUMMARY:
==4709== in use at exit: 98 bytes in 4 blocks
==4709== total heap usage: 14 allocs, 10 frees, 8,622 bytes allocated
==4709==
==4709== 16 bytes in 1 blocks are indirectly lost in loss record 1 of 4
==4709== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4709== by 0x108F0A: insertMsg (in /home/giacomo/Scrivania/chatty)
==4709== by 0x1092DB: main (in /home/giacomo/Scrivania/chatty)
==4709==
==4709== 32 (16 direct, 16 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 4
==4709== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4709== by 0x108F0A: insertMsg (in /home/giacomo/Scrivania/chatty)
==4709== by 0x1092C8: main (in /home/giacomo/Scrivania/chatty)
==4709==
==4709== 33 bytes in 1 blocks are definitely lost in loss record 3 of 4
==4709== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4709== by 0x1090F4: main (in /home/giacomo/Scrivania/chatty)
==4709==
==4709== 33 bytes in 1 blocks are definitely lost in loss record 4 of 4
==4709== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4709== by 0x109166: main (in /home/giacomo/Scrivania/chatty)
==4709==
==4709== LEAK SUMMARY:
==4709== definitely lost: 82 bytes in 3 blocks
==4709== indirectly lost: 16 bytes in 1 blocks
==4709== possibly lost: 0 bytes in 0 blocks
==4709== still reachable: 0 bytes in 0 blocks
==4709== suppressed: 0 bytes in 0 blocks
the program simply makes the registration of 2 users in the hash table, then I send messages to a user and store them in the message list.
This is the main and other function
typedef struct icl_entry_s {
void* key;
void *data;
struct icl_entry_s* next;
} icl_entry_t;
typedef struct icl_hash_s {
int nbuckets;
int nentries;
icl_entry_t **buckets;
unsigned int (*hash_function)(void*);
int (*hash_key_compare)(void*, void*);
} icl_hash_t;
icl_hash_t *hash;
static inline void setHeader(message_hdr_t *hdr, int op, char *sender) {
#if defined(MAKE_VALGRIND_HAPPY)
memset((char*)hdr, 0, sizeof(message_hdr_t));
#endif
hdr->op = op;
strncpy(hdr->sender, sender, strlen(sender)+1);
}
static inline void setData(message_data_t *data, char *rcv, const char *buf, unsigned int len) {
#if defined(MAKE_VALGRIND_HAPPY)
memset((char*)&(data->hdr), 0, sizeof(message_data_hdr_t));
#endif
strncpy(data->hdr.receiver, rcv, strlen(rcv)+1);
data->hdr.len = len;
data->buf = (char *)buf;
}
/**
* A simple string hash.
*
* An adaptation of Peter Weinberger's (PJW) generic hashing
* algorithm based on Allen Holub's version. Accepts a pointer
* to a datum to be hashed and returns an unsigned integer.
* From: Keith Seymour's proxy library code
*
* #param[in] key -- the string to be hashed
*
* #returns the hash index
*/
unsigned int
hash_pjw(void* key)
{
char *datum = (char *)key;
unsigned int hash_value, i;
if(!datum) return 0;
for (hash_value = 0; *datum; ++datum) {
hash_value = (hash_value << ONE_EIGHTH) + *datum;
if ((i = hash_value & HIGH_BITS) != 0)
hash_value = (hash_value ^ (i >> THREE_QUARTERS)) & ~HIGH_BITS;
}
return (hash_value);
}
static int string_compare(void* a, void* b)
{
return (strcmp( (char*)a, (char*)b ) == 0);
}
/**
* Create a new hash table.
*
* #param[in] nbuckets -- number of buckets to create
* #param[in] hash_function -- pointer to the hashing function to be used
* #param[in] hash_key_compare -- pointer to the hash key comparison function to be used
*
* #returns pointer to new hash table.
*/
icl_hash_t *
icl_hash_create( int nbuckets, unsigned int (*hash_function)(void*), int (*hash_key_compare)(void*, void*) )
{
icl_hash_t *ht;
int i;
ht = (icl_hash_t*) malloc(sizeof(icl_hash_t));
if(!ht) return NULL;
ht->nentries = 0;
ht->buckets = (icl_entry_t**)malloc(nbuckets * sizeof(icl_entry_t*));
if(!ht->buckets) return NULL;
ht->nbuckets = nbuckets;
for(i=0;i<ht->nbuckets;i++)
ht->buckets[i] = NULL;
ht->hash_function = hash_function ? hash_function : hash_pjw;
ht->hash_key_compare = hash_key_compare ? hash_key_compare : string_compare;
return ht;
}
/**
* Search for an entry in a hash table.
*
* #param ht -- the hash table to be searched
* #param key -- the key of the item to search for
*
* #returns pointer to the data corresponding to the key.
* If the key was not found, returns NULL.
*/
void *
icl_hash_find(icl_hash_t *ht, void* key)
{
icl_entry_t* curr;
unsigned int hash_val;
if(!ht || !key) return NULL;
hash_val = (* ht->hash_function)(key) % ht->nbuckets;
for (curr=ht->buckets[hash_val]; curr != NULL; curr=curr->next)
if ( ht->hash_key_compare(curr->key, key))
return(curr->data);
return NULL;
}
/**
* Insert an item into the hash table.
*
* #param ht -- the hash table
* #param key -- the key of the new item
* #param data -- pointer to the new item's data
*
* #returns pointer to the new item. Returns NULL on error.
*/
icl_entry_t *
icl_hash_insert(icl_hash_t *ht, void* key, void *data)
{
icl_entry_t *curr;
unsigned int hash_val;
if(!ht || !key) return NULL;
hash_val = (* ht->hash_function)(key) % ht->nbuckets;
for (curr=ht->buckets[hash_val]; curr != NULL; curr=curr->next)
if ( ht->hash_key_compare(curr->key, key))
return(NULL); /* key already exists */
/* if key was not found */
curr = (icl_entry_t*)malloc(sizeof(icl_entry_t));
if(!curr) return NULL;
curr->key = key;
curr->data = data;
curr->next = ht->buckets[hash_val]; /* add at start */
ht->buckets[hash_val] = curr;
ht->nentries++;
return curr;
/**
* Free hash table structures (key and data are freed using functions).
*
* #param ht -- the hash table to be freed
* #param free_key -- pointer to function that frees the key
* #param free_data -- pointer to function that frees the data
*
* #returns 0 on success, -1 on failure.
*/
int
icl_hash_destroy(icl_hash_t *ht, void (*free_key)(void*), void (*free_data)(void*))
{
icl_entry_t *bucket, *curr, *next;
int i;
if(!ht) return -1;
for (i=0; i<ht->nbuckets; i++) {
bucket = ht->buckets[i];
for (curr=bucket; curr!=NULL; ) {
next=curr->next;
if (*free_key && curr->key) (*free_key)(curr->key);
if (*free_data && curr->data) (*free_data)(curr->data);
free(curr);
curr=next;
}
}
if(ht->buckets) free(ht->buckets);
if(ht) free(ht);
return 0;
}
int insertMsg(char* client_nickname,message_t *msg){
char* buf=malloc(msg->data.hdr.len);
strncpy(buf,msg->data.buf,msg->data.hdr.len);
hash_elem *user = icl_hash_find(hash, client_nickname);
if(user->nmsg == 32){
return -1;
}
msg_list *mex=malloc(sizeof(msg_list));
if(mex==NULL){
return -1;
}
mex->msg=malloc(sizeof(message_t));
if(mex->msg==NULL){
return -1;
}
mex->msg->data.buf=NULL;
setHeader(&mex->msg->hdr,2,msg->hdr.sender);
setData(&mex->msg->data,msg->data.hdr.receiver,buf,msg->data.hdr.len);
mex->next=NULL;
if(user->msg_head==NULL){
user->msg_head=mex;
user->msg_corr=user->msg_head;
}else{
user->msg_corr->next=mex;
user->msg_corr=user->msg_corr->next;
}
user->nmsg++;
return 0;
}
void freeHashData(void* data){
hash_elem* data2=(hash_elem*) data;
msg_list* tmp=data2->msg_head;
while(tmp!=NULL){
free(tmp->msg->data.buf);
free(tmp->msg);
data2->msg_head=data2->msg_head->next;
tmp=data2->msg_head;
}
//free(data2);
free(data);
free(tmp);
}
int main(int argc, char *argv[]) {
//tabelle hash
hash = icl_hash_create(1024, &hash_pjw, NULL); //rivedere 1024 forse troppo
//fai insert per registrazioni
hash_elem *user1 = malloc(sizeof(hash_elem));
user1->nickname=malloc(33);
strncpy(user1->nickname,"user1",33);
user1->nmsg=0;
user1->msg_head=NULL;
user1->msg_corr=NULL;
hash_elem *user2 = malloc(sizeof(hash_elem));
user2->nickname=malloc(33);
strncpy(user2->nickname,"user2",33);
user2->nmsg=0;
user2->msg_head=NULL;
user2->msg_corr=NULL;
icl_hash_insert(hash, "user1", (void*)user1);
icl_hash_insert(hash, "user2", (void*)user2);
message_t msg;
memset(&msg,0,sizeof(message_t));
msg.data.buf=NULL;
message_t msg2;
memset(&msg2,0,sizeof(message_t));
msg2.data.buf=NULL;
setHeader(&msg.hdr,1,"SERVER");
setHeader(&msg2.hdr,1,"SERVER");
setData(&msg.data,"user2","hello",strlen("hello")+1);
setData(&msg2.data,"user2","hello",strlen("hello")+1);
insertMsg("user2",&msg);
insertMsg("user2",&msg2);
icl_hash_destroy(hash, NULL, freeHashData);
return 0;
}
you do not free enough in freeHashData, can be :
void freeHashData(void* data){
hash_elem* data2=(hash_elem*) data;
msg_list* tmp=data2->msg_head;
while (tmp != NULL) {
msg_list* next = tmp->next;
free(tmp->msg->data.buf);
free(tmp->msg);
free(tmp); /* you missed that */
tmp = next;
}
free(data2->nickname); /* you missed that */
free(data2);
}

can't free memory correctly

I'm working on pset6 of Harvard's cs50 now, the problem is to implement a trie dictionary.
I finally managed to make it work with a small problem.
When I run valgrind to check memory leak, it tells me that I've freed one more than I've allocated, but I can't see any problem in my unload function.
It also warns me that there are some uninitialized values, but I can't figure it out although it won't affect the result.
Here is my entire code:
/****************************************************************************
* dictionary.c
*
* Computer Science 50
* Problem Set 6
*
* valgrind warn that there are uninitialized values, could be the node struct, but don't
* know how to initialize it, anyway, it works at last!
*
* Implements a dictionary's functionality.
***************************************************************************/
#include <stdbool.h>
#include <ctype.h>
#include "dictionary.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define HASHTABLE_SIZE 5000
int count = 0; // gloabal counter
typedef struct node { // data structure
bool end_word;
struct node *children[27];
} node;
int
charNumber(char c); // function prototype
void
freeNode(node *currentNode);
node root = {false,{NULL}};
/*
* Returns true if word is in dictionary else false.
*/
bool
check(const char *word)
{
node *ptr = &root;
for (int i=0;i<strlen(word);i++)
{
if (ptr->children[charNumber(word[i])] == NULL)
return false;
ptr = ptr->children[charNumber(word[i])];
}
if (ptr->end_word)
return true;
else
return false;
}
/*
* Loads dictionary into memory. Returns true if successful else false.
*/
bool
load(const char *dictionary)
{
// char word[LENGTH+1]; // must initialize to zero! Or there will be some weird problem.
FILE *fp = fopen(dictionary,"r");
if (fp == NULL)
return false;
while (!feof(fp))
{
char word[LENGTH+1] = {};
fscanf(fp,"%s\n",word); // have to use "%s\n" instead of "%s", or the count will be wrong, don't know why.
count++;
node *ptr = &root;
for (int i=0;i<strlen(word);i++)
{
if (ptr->children[charNumber(word[i])] == NULL)
{
node *new = malloc(sizeof(node));
*new = (node) {false,{NULL}}; // initiallization
ptr->children[charNumber(word[i])] = new;
ptr = new;
}
else
{
ptr = ptr->children[charNumber(word[i])];
}
}
ptr->end_word = true;
}
fclose(fp);
return true;
}
/*
* caculate a number for the character
*/
int
charNumber(char c)
{
int num;
if (c == '\'')
return 26;
else if(c >= 'A' && c <= 'Z')
c += 32;
num = c - 'a';
return num;
}
/*
* Returns number of words in dictionary if loaded else 0 if not yet loaded.
*/
unsigned int
size(void)
{
if (count)
return count;
else
return 0;
}
/*
* Unloads dictionary from memory. Returns true if successful else false.
*/
bool
unload(void)
{
freeNode(&root);
return true; // can't figure out when to return false...
}
void freeNode(node *currentNode)
{
for (int i=0;i<27;i++)
{
if (currentNode->children[i] != NULL)
freeNode(currentNode->children[i]);
}
free(currentNode);
}
Here is some of the valgrind output:
==22110== Invalid free() / delete / delete[]
==22110== at 0x4024ECD: free (vg_replace_malloc.c:366)
==22110== by 0x8048F90: freeNode (dictionary_tries.c:152)
==22110== by 0x8048F45: unload (dictionary_tries.c:141)
==22110== by 0x8048AB5: main (speller.c:158)
==22110== Address 0x804a5a0 is 0 bytes inside data symbol "root"
==22110==
--22110-- REDIR: 0x40b2930 (strchrnul) redirected to 0x4028570 (strchrnul)
==22110==
==22110== HEAP SUMMARY:
==22110== in use at exit: 0 bytes in 0 blocks
==22110== total heap usage: 367,083 allocs, 367,084 frees, 41,113,776 bytes allocated
==22110==
==22110== All heap blocks were freed -- no leaks are possible
==22110==
==22110== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 9)
==22110==
==22110== 1 errors in context 1 of 1:
==22110== Invalid free() / delete / delete[]
==22110== at 0x4024ECD: free (vg_replace_malloc.c:366)
==22110== by 0x8048F90: freeNode (dictionary_tries.c:152)
==22110== by 0x8048F45: unload (dictionary_tries.c:141)
==22110== by 0x8048AB5: main (speller.c:158)
==22110== Address 0x804a5a0 is 0 bytes inside data symbol "root"
==22110==
--22110--
--22110-- used_suppression: 14 U1004-ARM-_dl_relocate_object
==22110==
==22110== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 9)
Suppose your load function opens a blank file. feof(fp) will initially return 0, because a read operation hasn't been used yet; The EOF flag will only be set after a read operation returns a value indicating an error. This is where an error lies. In your case, you need to loop on the return value of fscanf(fp,"%s\n",word); rather than the return value of feof. For example:
while (fscanf(fp, "%s", word) == 1) {
/* ... */
}
if (feof(fp)) {
/* The loop ended due to EOF */
}
else if (ferror(fp)) {
/* The loop ended due to some file input error */
}
else {
/* The loop ended because the input was invalid
* (this applies to input where a conversion is
* required eg. the conversion in %d, %u, %f, etc... */
}
To elaborate, feof is only for determining why the last read failed!
The reason this would cause such a warning in the case of a blank file is that word would contain indeterminate information.
Additionally, freeNode(&root); is erroneous because free is only to be called on pointers that are returned by calloc, realloc and malloc.
node root = {false,{NULL}};
is not allocated on the heap, but then you try to free it like it is
unload(void)
{
freeNode(&root);

Memory Leaks in C Linked List

I've been working on a project for school (Due tonight!), and I'm having some serious memory issues. I'm fairly new to C and am still being thrown for a loop when it comes to mallocing pointers and whatnot, so I could really use some help.
The code is as follows. The order of the files is LinkedLists.h (Header for LinkedList module), LinkedLists.c (LinkedList module), and TestList.c (Main module).
/******************************************************************************
* Base struct to contain data structure element information: deterimined by
* the application needs.
******************************************************************************/
#ifndef _LINKED_LISTS_H_
#define _LINKED_LISTS_H_
typedef struct ElementStructs
{
int ElementPosition;
char* ElementValue;
} ElementStructs;
/************** Nothing else in the module needs to be modified *************/
/******************************************************************************
* Base struct of list nodes, contains user information and link pointers.
* The "ElementStructs" typemark must be defined based on specific needs of the
* application.
******************************************************************************/
typedef struct LinkedListNodes
{
/* The user information field */
ElementStructs *ElementPtr;
/* Link pointers */
struct LinkedListNodes *Next;
struct LinkedListNodes *Previous;
} LinkedListNodes;
/******************************************************************************
* Base struct used to manage the linked list data structure.
******************************************************************************/
typedef struct LinkedLists
{
/* Number of elements in the list */
int NumElements;
/* Pointer to the front of the list of elements, possibly NULL */
struct LinkedListNodes *FrontPtr;
/* Pointer to the end of the list of elements, possibly NULL */
struct LinkedListNodes *BackPtr;
} LinkedLists;
/******************************************************************************
* Initialized the linked list data structure
******************************************************************************/
void InitLinkedList(LinkedLists *ListPtr);
/******************************************************************************
* Adds a record to the front of the list.
******************************************************************************/
void AddToFrontOfLinkedList(LinkedLists *ListPtr, ElementStructs *DataPtr);
/******************************************************************************
* Adds a record to the back of the list.
******************************************************************************/
void AddToBackOfLinkedList(LinkedLists *ListPtr, ElementStructs *DataPtr);
/******************************************************************************
* Removes (and returns) a record from the front of the list ('works' even on
* an empty list by returning NULL).
******************************************************************************/
ElementStructs *RemoveFromFrontOfLinkedList(LinkedLists *ListPtr);
/******************************************************************************
* Removes (and returns) a record from the back of the list ('works' even on
* an empty list by returning NULL).
******************************************************************************/
ElementStructs *RemoveFromBackOfLinkedList(LinkedLists *ListPtr);
/******************************************************************************
* De-allocates the linked list and resets the struct fields as if the
* list was empty.
******************************************************************************/
void DestroyLinkedList(LinkedLists *ListPtr);
#endif /* _LINKED_LISTS_H_ */
LinkedLists.c:
/******************************************************************************
* Extracts and prints the first and last 6 elements from the specified data
* set and prints the total number of words in the input file. Utilizes the
* LinkedList module as specified in LinkedLists.h
* Written by xxxxxxx
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "LinkedLists.h"
void InitLinkedList(LinkedLists *ListPtr)
{
ListPtr->NumElements = 0;
ListPtr->FrontPtr = NULL;
ListPtr->BackPtr = NULL;
}
void AddToFrontOfLinkedList(LinkedLists *ListPtr, ElementStructs
*DataPtr)
{
/* If there are no other elements, create new node and add it,
* assigning it to both the front and back pointers */
if(ListPtr->NumElements == 0)
{
ListPtr->FrontPtr = malloc(sizeof(LinkedListNodes));
ListPtr->FrontPtr->ElementPtr = DataPtr;
ListPtr->FrontPtr->Next = NULL;
ListPtr->FrontPtr->Previous = NULL;
ListPtr->BackPtr = ListPtr->FrontPtr;
}
/* If there are other elements, create new node and add it to the front
* while retaining previous node order */
else
{
/* Initialize new LinkedListNode */
ListPtr->FrontPtr->Previous = malloc(sizeof(LinkedListNodes));
ListPtr->FrontPtr->Previous->ElementPtr = DataPtr;
ListPtr->FrontPtr->Previous->Next = ListPtr->FrontPtr;
ListPtr->FrontPtr->Previous->Previous = NULL;
/* Assign newly initialized node as front node of LinkedList */
ListPtr->FrontPtr = ListPtr->FrontPtr->Previous;
}
/* List size plus one */
(ListPtr->NumElements)++;
}
void AddToBackOfLinkedList(LinkedLists *ListPtr, ElementStructs
*DataPtr)
{
/* If there are no other elements, create new node and add it,
* assigning it to both the front and back pointers */
if(ListPtr->NumElements == 0)
{
ListPtr->FrontPtr = malloc(sizeof(LinkedListNodes));
ListPtr->FrontPtr->ElementPtr = DataPtr;
ListPtr->FrontPtr->Next = NULL;
ListPtr->FrontPtr->Previous = NULL;
ListPtr->BackPtr = ListPtr->FrontPtr;
/*printf("Adding %s\n", DataPtr->ElementValue);*/
}
/* If there are other elements, create new node and add it to the back
* while retaining previous node order */
else
{
/* Initialize new LinkedListNode */
ListPtr->BackPtr->Next = malloc(sizeof(LinkedListNodes));
ListPtr->BackPtr->Next->ElementPtr = DataPtr;
ListPtr->BackPtr->Next->Previous = ListPtr->BackPtr;
ListPtr->BackPtr->Next->Previous = ListPtr->BackPtr;
ListPtr->BackPtr->Next->Next = NULL;
/* Assign newly initialized node as back node of LinkedList */
ListPtr->BackPtr = ListPtr->BackPtr->Next;
printf("Adding %s\n", ListPtr->BackPtr->ElementPtr->ElementValue);
}
/* List size plus one */
(ListPtr->NumElements)++;
}
ElementStructs *RemoveFromFrontOfLinkedList(LinkedLists *ListPtr)
{
if(ListPtr->NumElements > 0)
{
ElementStructs *removedElement = ListPtr->FrontPtr->ElementPtr;
LinkedListNodes *removedNode = ListPtr->FrontPtr;
if(ListPtr->NumElements == 1)
{
ListPtr->FrontPtr = NULL;
}
else
{
ListPtr->FrontPtr = ListPtr->FrontPtr->Next;
ListPtr->FrontPtr->Previous = NULL;
}
(ListPtr->NumElements)--;
free(removedNode);
return removedElement;
}
else
{
ElementStructs *nullElement = NULL;
return nullElement;
}
}
ElementStructs *RemoveFromBackOfLinkedList(LinkedLists *ListPtr)
{
if(ListPtr->NumElements > 1)
{
ElementStructs *removedElement = ListPtr->BackPtr->ElementPtr;
LinkedListNodes *removedNode = ListPtr->BackPtr;
if(ListPtr->NumElements == 1)
{
ListPtr->BackPtr = NULL;
}
else
{
ListPtr->BackPtr = ListPtr->BackPtr->Previous;
ListPtr->BackPtr->Next = NULL;
}
(ListPtr->NumElements)--;
free(removedNode);
return removedElement;
}
else
{
ElementStructs *nullElement = NULL;
return nullElement;
}
}
void DestroyLinkedList(LinkedLists *ListPtr)
{
while(ListPtr->FrontPtr != NULL)
{
LinkedListNodes *removedNode = ListPtr->FrontPtr;
ListPtr->FrontPtr = ListPtr->FrontPtr->Next;
/* Deallocate element in node */
free(removedNode->ElementPtr->ElementValue);
free(removedNode->ElementPtr);
/* Deallocate node */
free(removedNode);
}
free(ListPtr);
}
TestList.c:
/******************************************************************************
* Tests the functionality of the LinkedList specified in LinkedLists.h using
* the file "american-english-words". Reads in individual words and stores them
* as node elements in the LinkedList.
* Written by xxxxx
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkedLists.h"
#define MAX_LENGTH 100 /* Length of longest word in any major English dictionary */
int main(int argc, char** args)
{
if(argc == 2)
{
/* Initialize LinkedList */
LinkedLists *LL;
/* File pointer to input file */
FILE *fp;
/* Node to store input data from file */
ElementStructs *NodeData;
/* Loop completion boolean */
int Done;
/* Loop position counter */
int Position;
/* Iterator */
ElementStructs *CurElement;
/* Open input file and check that it is readable. If not, exit */
fp = fopen(args[1], "r");
if(fp == NULL)
{
fprintf(stderr, "File open failed.");
return 2;
}
/* Initialize linked list and other necessary variables */
LL = malloc(sizeof(*LL));
InitLinkedList(LL);
Done = 0;
Position = 0;
do
{
if(!feof(fp))
{
/* Allocate space for new node data */
NodeData = malloc(sizeof(ElementStructs));
/* Allocate space in node element for input string */
NodeData->ElementValue = malloc(MAX_LENGTH * sizeof(char));
/* Read new node data from file */
fscanf(fp, "%s", NodeData->ElementValue);
/* Assign scanned values to node elements */
NodeData->ElementPosition = Position;
/*strcpy(NodeData->ElementValue, readString);*/
/* Add data node to LinkedList */
AddToFrontOfLinkedList(LL, NodeData);
}
else
Done = 1;
Position++;
}while(Done == 0);
do
{
CurElement = RemoveFromFrontOfLinkedList(LL);
if(CurElement != NULL)
printf("Word #%d: %s\n", CurElement->ElementPosition,
CurElement->ElementValue);
}while(CurElement != NULL);
/* Deallocate linked list */
DestroyLinkedList(LL);
fclose(fp);
}
/* Bad command line input */
else
{
fprintf(stderr, "Incorrect number of arguments");
return 1;
}
return 0;
}
The program compiles fine. However, running it causes a seg fault at the end of execution, and valgrind reports multiple memory leaks (Shown below). Please, if you have any help to offer, I would be extremely grateful. The issue is mostly in the RemoveFromBackOfLinkedList and RemoveFromFrontOfLinkedList methods in the LinkedList.c module. There's a block of code in the main module (TestList.c) that calls one of these functions (I've tried both, but they have nearly identical functionality, and neither works). The block is a do/while loop shown below:
do
{
CurElement = RemoveFromFrontOfLinkedList(LL);
if(CurElement != NULL)
printf("Word #%d: %s\n", CurElement->ElementPosition,
CurElement->ElementValue);
}while(CurElement != NULL);
Valgrind Results:
Word #225921: stoich
.
.
.
.
Word #6: Cam's
Word #5: petrochemistry's
Word #4: Tera
Word #3: benedictions
Word #2: wisted
Word #1: toxins
==4849== Invalid write of size 8
==4849== at 0x400B5C: RemoveFromFrontOfLinkedList (in /home/amb2189/hw3/TestList)
==4849== by 0x40085B: main (in /home/amb2189/hw3/TestList)
==4849== Address 0x10 is not stack'd, malloc'd or (recently) free'd
==4849==
==4849==
==4849== Process terminating with default action of signal 11 (SIGSEGV)
==4849== Access not within mapped region at address 0x10
==4849== at 0x400B5C: RemoveFromFrontOfLinkedList (in /home/amb2189/hw3/TestList)
==4849== by 0x40085B: main (in /home/amb2189/hw3/TestList)
==4849== If you believe this happened as a result of a stack
==4849== overflow in your program's main thread (unlikely but
==4849== possible), you can try to increase the size of the
==4849== main thread stack using the --main-stacksize= flag.
==4849== The main thread stack size used in this run was 8388608.
==4849==
==4849== HEAP SUMMARY:
==4849== in use at exit: 23,965,172 bytes in 413,185 blocks
==4849== total heap usage: 619,775 allocs, 206,590 frees, 28,923,332 bytes allocated
==4849==
==4849== 16 bytes in 1 blocks are possibly lost in loss record 1 of 9
==4849== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4849== by 0x4007E2: main (in /home/amb2189/hw3/TestList)
==4849==
==4849== 200 bytes in 2 blocks are possibly lost in loss record 5 of 9
==4849== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4849== by 0x4007F0: main (in /home/amb2189/hw3/TestList)
==4849==
==4849== 23,963,992 (3,305,392 direct, 20,658,600 indirect) bytes in 206,587 blocks are definitely lost in loss record 9 of 9
==4849== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4849== by 0x4007E2: main (in /home/amb2189/hw3/TestList)
==4849==
==4849== LEAK SUMMARY:
==4849== definitely lost: 3,305,392 bytes in 206,587 blocks
==4849== indirectly lost: 20,658,600 bytes in 206,586 blocks
==4849== possibly lost: 216 bytes in 3 blocks
==4849== still reachable: 964 bytes in 9 blocks
==4849== suppressed: 0 bytes in 0 blocks
==4849== Reachable blocks (those to which a pointer was found) are not shown.
==4849== To see them, rerun with: --leak-check=full --show-reachable=yes
==4849==
==4849== For counts of detected and suppressed errors, rerun with: -v
==4849== Use --track-origins=yes to see where uninitialised values come from
==4849== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 2 from 2)
Segmentation fault (core dumped)
==4769== 8 bytes in 1 blocks are definitely lost in loss record 1 of 4
==4769== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4769== by 0x400B46: RemoveFromFrontOfLinkedList (in /home/amb2189/hw3/TestList)
==4769== by 0x400869: main (in /home/amb2189/hw3/TestList)
This refers to the following code:
LinkedListNodes *removedNode = malloc(sizeof(removedNode));
removedNode = ListPtr->FrontPtr;
You malloc a block of memory then assign it to removedNode then immediately overwrite the pointer value. This does not assign to the contents of removedNode, but it overwrites the pointer.
The next memory leak occurs in main as pointed out by Valgrind:
CurElement = malloc(sizeof(*CurElement));
The next usage of CurElement immediately overwrites the pointer value, which means you have lost your reference to the allocated memory:
CurElement = RemoveFromFrontOfLinkedList(LL);
Make some changes in your 2 delete functions,,
ElementStructs *RemoveFromFrontOfLinkedList(LinkedLists *ListPtr)
{
if(ListPtr->NumElements > 0)
{
/* ElementStructs *removedElement = ListPtr->FrontPtr->ElementPtr;*/
/*LinkedListNodes *removedNode = malloc(sizeof(removedNode)); // no need allocate because you are deleting the node
removedNode = ListPtr->FrontPtr;*/
LinkedListNodes *removedNode = ListPtr->FrontPtr; // use this line
ListPtr->FrontPtr = ListPtr->FrontPtr->Next;
ListPtr->FrontPtr->Previous = NULL;
free(removedNode);
(ListPtr->NumElements)--;
return NULL;
}
else
{
ElementStructs *nullElement = NULL;
return nullElement;
}
}
ElementStructs *RemoveFromBackOfLinkedList(LinkedLists *ListPtr)
{
if(ListPtr->NumElements != 0)
{
ElementStructs *removedElement = ListPtr->BackPtr->ElementPtr;
LinkedListNodes *removedNode = ListPtr->BackPtr;
ListPtr->BackPtr = ListPtr->BackPtr->Previous;
ListPtr->BackPtr->Next = NULL;
free(removedNode);
(ListPtr->NumElements)--; // add this line
return removedElement;
}
else
{
ElementStructs *nullElement = NULL;
return nullElement;
}
}
EDIT 1
CurElement = malloc(sizeof(*CurElement)); this is another mem-leak in main, you don't have to use malloc for it, just remove this line.
EDIT 2: Why aren't you freeing your ELEMENT and ELEMENTVALUE...?
do
{
CurElement = RemoveFromFrontOfLinkedList(LL);
if(CurElement != NULL) {
printf("Word #%d: %s\n", CurElement->ElementPosition,
CurElement->ElementValue);
free(CurElement->ElementValue); //add these 2 line to free ELEMENTVALUE And ELEMENT.
free(CurElement);
}
}while(CurElement != NULL);
I think one leak is from CurElement = malloc(sizeof(*CurElement));. The next use of CurElement over-writes this pointer.
Its also not immediately clear where NodeData->ElementValue gets freed.
what do you want to do with:
LinkedListNodes *removedNode = malloc(sizeof(removedNode));
removedNode = ListPtr->FrontPtr;
you malloc some space and overwride the pointer

Resources