How to free a void pointer allocated after read a file - c

i have this structure filled by loading data from a file. I just found out by sanitaizer that string allocated in this way doesn't be free but i don't know how to do it cause it start as a void* item so i can't free it or give me error. I put here my code where, for every row read from the file there will be a leak of byte of an object.
=================================================================
==12111==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 86031 byte(s) in 711 object(s) allocated from:
#0 0x7ff09a17c867 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
#1 0x55dd7970854b in load_dictionary (/home/matteo/Scrivania/Algo/laboratorio-algoritmi-2021-2022-main/Esercizio 2/ex2/build/main+0x154b)
#2 0x55dd797086da in main (/home/matteo/Scrivania/Algo/laboratorio-algoritmi-2021-2022-main/Esercizio 2/ex2/build/main+0x16da)
#3 0x7ff099ec9d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
I tried to free directly the variable row but then progema doesn't work cause a free the variable in the skipList and i can't read or search in it.
**Where i must put the free of the item? **
I put the code of the allocation and deallocation...with the read of file
There is a better and faster way to read the file?
Cause the process seems to stock, it takes more than 5/10 minutes to read the file but the algorithm does not proceed. It doesn't seem to freeze but it does nothing. With the sanitaizer it gives the error of memory that needs to be freed.
struct _SkipList {
Node *head;
unsigned int max_level;
int (*compare)(void*, void*);
};
struct _Node {
Node **next;
unsigned int size;
void *item;
};
static unsigned int load_dictionary(char *filename,SkipList *list )
{
unsigned int words_count = 0;
FILE *fp = fopen(filename, "r");
char *line = NULL;
size_t len = 0;
if (list == NULL)
{
list = create_skip_list();
}
char *word;
while (getline(&line, &len, fp) != -1)
{
words_count++;
word = malloc((len + 1) * sizeof(char));
strcpy(word, line);
strtok(word,"\n");
insert_skip_list(list, word);
}
free(line);
fclose(fp);
return words_count;
}
SkipList* create_skip_list(){
SkipList *list = malloc(sizeof(SkipList));
list->max_level = 0;
list->compare = NULL;
list->head = create_head_node(NULL,MAX_HEIGHT);
return list;
}
Node* create_head_node(void* item, int level){
if(level <1)
return NULL;
Node *node = malloc(sizeof(Node));
if(node == NULL){
printf("error malloc node\r\n");
/* Returning here prevent the program from accessing non allocated
* memory. */
return NULL;
}
node->item = item;
node->size = level;
node->next = (Node**)malloc(level * sizeof(Node *));
if (!node->next) {
printf("error malloc node next\r\n");
free(node);
return NULL;
}
for (int i = 0; i < level; i++)
{
node->next[i] = NULL;
}
return node;
}
void delete_node_array(Node* node){
if(node == NULL) return;
delete_node_array(node->next[0]);
node = free_node(node);
}
SkipList* delete_skip_list(SkipList *list){
if(list == NULL) return NULL;
delete_node_array(list->head);
free(list);
list=NULL;
return list;
}
Node* free_node(Node *node){
free(node->next);
free(node);
node = NULL;
return node;
}
int insert_skip_list(SkipList* list,void* item){
if (list == NULL || item ==NULL) return -1;
Node* node = create_node(item,random_level()); //is the same of create_head_node but without the initial check of the null Item
if(node == NULL){
printf("\nisert_skip_list:error malloc node");
return -1;
}
if(node->size > list->max_level){
list->max_level = node->size;
}
Node *x = list->head;
for (int k = list->max_level-1; k >= 0; k--)
{
if(x->next[k] == NULL || strcmp(item,x->next[k]->item) < 0 ){
if(k < node->size){
node->next[k] = x->next[k];
x->next[k] = node;
}
}else{
x = x->next[k];
k++;
}
}
return 0;
}

I solved by put in :
Node* free_node(Node *node){
free(node->item); --> new line
free(node->next);
free(node);
node = NULL;
return node;
}
But this is strange cause the first time didn't work. Otherwise still too slow for a correct solution. Any suggest how to improve the read function's speed?

Related

C: getchar() destroys pointer

typedef struct LinkedList LinkedList;
struct LinkedList {
LinkedList* next;
char* head;
char current;
};
LinkedList makeList()
{
char* headPointer = calloc(60, sizeof(char));
LinkedList temp = { 0xCCCCCCCC, headPointer, 0 };
return temp;
}
int addToList(LinkedList* lstPointer, char toAdd) {
if (lstPointer->head == NULL || lstPointer->head == 0xCCCCCCCC)
return -1;
if (lstPointer->current + 1 < 60) { /* enough space in the list to add */
*(lstPointer-> head + lstPointer -> current) = toAdd;
lstPointer->current = lstPointer->current + 1;
}
else /* not enough space, will create new node in the list */
{
if (lstPointer->next == 0xCCCCCCCC) {
LinkedList nextNode = makeList();
lstPointer->next = &nextNode;
}
return addToList(lstPointer->next, toAdd);
}
/*Added succsessfully*/
return 0;
}
int main(){
char chr;
LinkedList lst = makeList();
while ((chr = getchar()) != EOF) {
if (addToList(&lst, chr) == -1)
return -1;
}
return 0;
}
i am trying to use linked list but after i fill the first, i create a new one and able to add an item to it. on the second item the next list pointer get destroyed by getchar(). i have no idea why or how is it related.
In makelist you need to allocate a new list, but then instead of returning it, you copy it into a local variable, leaking the memory that you just allocated. Instead, return a pointer:
LinkedList *makeList() // Note *
{
LinkedList *temp = calloc(1, sizeof(LinkedList));
temp->head = calloc(60, sizeof(char));
temp->next = 0;
temp->current = toAdd;
return temp; // Note temp is a pointer
}
In addToList you don't need the nextNode variable:
lstPointer->next = makelist();

Can you tell me why my function to select a random string from a linked list isn't working?

I am building a program for a project. One of the requirements for the project is a function that selects a random node from my linked list of 3000 words.
I tried to do this by creating a function that generates a random number from 0 to 2999. After this, I created another function that follows a for loop starting from the head and moving to the next node (random number) times.
My random number generator is working fine, but my chooseRand() function is not.
Please help, the random number generator and the chooseRand() function are the last two functions above main. Also, my code is a bit messy, sorry.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int nodeNum;
int chances;
char* secret;
/*Node of linked list*/
typedef struct node {
char *data;
struct node *next;
} node;
node *start = NULL;
node *current;
/*Void function to print list*/
void printList(struct node *node)
{
while (node != NULL) {
printf("%s ", node->data);
node = node->next;
}
}
/*Appending nodes to linked list*/
void add(char *line) {
node *temp = malloc(sizeof(node));
temp->data = strdup(line);
temp->next = NULL;
current = start;
if(start == NULL) {
start = temp;
} else {
while(current->next != NULL) {
current = current->next;
}
current->next = temp;
}
}
void readfile(char *filename) {
FILE *file = fopen(filename, "r");
if(file == NULL) {
exit(1);
}
char buffer[512];
while(fgets(buffer, sizeof(buffer), file) != NULL) {
add(buffer);
}
fclose(file);
}
node *listSearch(node* start, char *nodeSearched){
node *p;
for (p = start; p != NULL; p = p->next)
if (strcmp(p->data, nodeSearched) == 0)
printf("%s", p->data);
return NULL;
}
node *letterSearch(node* start, int i){
node *p;
for (p = start; p != NULL; p = p->next)
if (strlen(p->data) == i)
{
printf("\n %s", p->data);
free(p);
p = NULL;
}
return NULL;
}
void chooseRand(struct node* start)
{
node* p;
int n;
p = start;
for(n = 0; n != nodeNum; n++)
{
p = p->next;
}
printf("%s", p->data);
}
void randNum(int lower, int upper)
{
srand(time(0));
nodeNum = (rand() % (upper - lower + 1)) + lower;
}
int main(){
randNum(0, 2999);
chooseRand(start);
return 0;
}
As others has said, the problem is that you don't have initialized the linked list yet, because of what your are getting a segmentation fault. So, in addition to initializing the list first, you must also introduce checks in the implementation of the chooseRand function, to check that if you reach the end of the list, without reaching the desired index, you stop executing the foor loop, otherwise you will be potentially exposed to segmentation faults.
Improve chooseRand implementation, to prevent segmentation fault either, when the linked list is empty, or when the randomly generated nodeNum is grater than the the index of the list's last item:
void chooseRand(struct node* start)
{
node* p;
int n;
p = start;
if(p == NULL){
printf("The list is empty!");
return;
}
// Also, we must stop the iteration, if we are going to pass the end of the list, you don't want a segmentation fault because trying to access a NULL pointer:
for(n = 0; n != nodeNum && p->next != NULL; n++)
{
p = p->next;
}
// If p == NULL, the list was not big enough to grab an item in the `nodeNum` index:
printf("%s", (n != nodeNum) ? "Not found!" : p->data);
}
Initialize the linked list, with the content of some file on disk:
int main(){
randNum(0, 2999);
// Fill the linked list with the content of a file in disk, calling your method:
char fileName[] = "PutYourFileNameHere.txt";
readfile(fileName);
chooseRand(start);
return 0;
}
There is another fix that you must do, and it is free the memory being hold by the pointer field data of your structure, in the implementation of your method letterSearch. Inside the if statement, you're de-allocating the memory hold by the p pointer, but you aren't de-allocating the memory assigned to the pointer p->data, this will cause a memory leak. When you in the function add, initialized p->data with the result of the call to the function strdup(line), what this function does is allocate enough memory in the heap, copies to it the buffer pointed by the line argument, and give to you back a pointer to the new allocated memory, that you're storing in the p.data field; a pointer that you should free when you're done with it, otherwise your program will have potential memory leaks. So I will modify your function letterSearch as folollows:
node *letterSearch(node* start, int i){
node *p;
for (p = start; p != NULL; p = p->next)
if (strlen(p->data) == i)
{
printf("\n %s", p->data);
// Free p->data before free p:
free(p->data);
free(p);
p = NULL;
}
return NULL;
}
References:
strdup

Double free or corruption - error when deleting first node of list

I have the following code to delete elements from a list. When one of the elements of the struct is lower than the value I use it, I must delete the node.
The code is as follows:
void DeleteNode(frota** head, int MAX, int nSquareW){
int i, eliminate = 0;
frota* curr = *head;
frota* curr1 = curr;
if(*head != NULL)
{
while(curr1 != NULL)
{
if(curr1->bateria < MAX)
{
if( *head == curr1){
if(curr1->next != NULL){
(curr1->next)->prev = NULL;
}
*head = curr1->next;
}else if(curr1 -> next == NULL){
(curr1->prev)->next = NULL;
}else{
(curr1->next)->prev = curr1->prev;
(curr1->prev)->next = curr1->next;
}
eliminate = 1;
}
curr1 = curr1->next;
if(eliminate == 1){
eliminate = 0;
printf("entrei1");
for(i=0;i<nSquareW;i++){
free(curr->percorridos[i]);
}
free(curr->percorridos);
free(curr);
}
curr = curr1;
}
}
}
The code is working well when I try to delete the last and middle nodes (value head is equal to first node, unless there is none, then value is NULL), but when I try to delete the first node, I get the following error:
*** Error in './iClean': double free or corruption (!prev): 0x09bd4a20 ***
Someone has already told me that the problem is when deleting the node (the free() ) and that I can't do anything about that.
Any help would be appreciate.
EDIT
nSquareWidth is the width of the map.
This is the code which generates percorridos:
void faz_mapa(matriz *** mapa, int nSquareW, int nSquareH){
*mapa = malloc(nSquareW * sizeof(matriz*));
for (int i = 0; i < nSquareW; i++)
{
(*mapa)[i]= malloc( nSquareH * sizeof(matriz));
}
for (int i = 0; i < nSquareW; i++)
{
for (int j = 0; j < nSquareH; j++)
{
//inicializa divisao suja
(*mapa)[i][j].limpo = 0;
(*mapa)[i][j].ocupado = NULL;
}
}
}
And struct:
typedef struct robot {
int bateria;
char nome[STRING_SIZE];
int pos_x;
int pos_y;
int target_x;
int target_y;
int limpos;
matriz ** percorridos;
struct robot * next;
struct robot * prev;
}frota;
I haven't run your code, but it is apparent that there is only one spot where we can run into a double free.
for(i=0;i<nSquareW;i++){
free(curr->percorridos[i]);
}
free(curr->percorridos);
free(curr);
Either you have a case where curr->percorridos is the same as curr, or maybe curr->percorridos[i] is the same as curr->percorridos?
You could find this out by adding a print statement before each call to free. Then find out which is being called twice.
for(i=0;i<nSquareW;i++){
printf("Freeing curr->perrcorridos[i] at %p\n", curr->percorridos[i]);
free(curr->percorridos[i]);
}
printf("Freeing curr->perrcorridos at %p\n", curr->percorridos);
free(curr->percorridos);
printf("Freeing curr at %p\n", curr);
free(curr);
Since double linked list programming questions show up so often on Stack Overflow, my answer will showcase how to do a double linked list in a pretty safe way. It uses a top level list type definition and sentinel entries. There is still some room to mess up, but the code is pretty easy to test and debug as different aspects are treated locally by individual functions.
The delete() function in the original question has the problem that it is in charge of 2 different things: 1. handle the double linked list removal stuff 2. Do some application specific filtering.
My code also shows, that application code running on such a list can be separated from list management code.
#include <stdint.h>
#include <stdlib.h>
typedef struct NodeType_tag { int32_t value; NodeType_tag *Next; NodeType_tag *Prev; } NodeType;
typedef struct { NodeType sentinel; NodeType *head; NodeType *tail; } NodeList;
void NodeListInit(NodeList * nodeList)
{
nodeList->sentinel.Next = &nodeList->sentinel;
nodeList->sentinel.Prev = &nodeList->sentinel;
nodeList->head = &nodeList->sentinel;
nodeList->tail = &nodeList->sentinel;
}
int NodeListIsEmpty(NodeList * nodeList)
{
return nodeList->head == &nodeList->sentinel;
}
void NodeListAddFront(NodeList* nodeList, uintptr_t value)
{
NodeType *newNode = (NodeType*)malloc(sizeof(NodeType));
if (NULL != newNode)
{
newNode->value = value;
newNode->Prev = nodeList->head->Prev;
newNode->Next = nodeList->head;
nodeList->head->Prev = newNode;
nodeList->head = newNode;
if (nodeList->tail == &nodeList->sentinel)
nodeList->tail = newNode;
}
}
void NodeListAddBack(NodeList* nodeList, int32_t value)
{
NodeType *newNode = (NodeType*)malloc(sizeof(NodeType));
if (newNode != NULL)
{
newNode->value = value;
newNode->Prev = nodeList->tail;
newNode->Next = nodeList->tail->Next;
nodeList->tail->Next = newNode;
nodeList->tail = newNode;
if (nodeList->head == &nodeList->sentinel)
nodeList->head = newNode;
}
}
NodeType *NodeListHead(NodeList*nodeList)
{
if (&nodeList->sentinel != nodeList->head)
return nodeList->head;
return NULL;
}
NodeType *NodeListTail(NodeList* nodeList)
{
if (&nodeList->sentinel != nodeList->tail)
return nodeList->tail;
return NULL;
}
NodeType *NodeListNext(NodeList * nodeList, NodeType * current)
{
if (NULL != current)
{
if (current->Next != &nodeList->sentinel)
return current->Next;
}
return NULL;
}
NodeType *NodeListPrev(NodeList *nodeList, NodeType *current)
{
if (NULL != current)
{
if (current->Prev != &nodeList->sentinel)
return current->Prev;
}
return NULL;
}
NodeType* NodeListRemoveForward(NodeList* nodeList, NodeType *target)
{
NodeType* next = NULL;
if (target != NULL)
{
target->Prev->Next = target->Next;
target->Next->Prev = target->Prev;
if (target == nodeList->head)
nodeList->head = target->Next;
if (target == nodeList->tail)
nodeList->tail = target->Prev;
if (&nodeList->sentinel != target->Next)
next = target->Next;
free(target);
}
return next;
}
// return 1 if value passes filter.
// return 0 if value is not passing filter.
typedef int(*FilterFunction_t)(int32_t value);
size_t NodeListFilter(NodeList *nodeList, FilterFunction_t filter)
{
NodeType * current = NodeListHead(nodeList);
size_t removeCount = 0;
while (current != NULL)
{
if (filter(current->value))
{
// passed filter -> keep it.
current = NodeListNext(nodeList, current);
}
else
{
// did not pass filter - kill it!
current = NodeListRemoveForward(nodeList, current);
removeCount++;
}
}
return removeCount;
}
void NodeListClear(NodeList *nodeList)
{
NodeType *current = NodeListHead(nodeList);
while (current != NULL)
{
current = NodeListRemoveForward(nodeList, current);
}
}
void DumpNodeList(NodeList* nodeList)
{
NodeType * current = NodeListHead(nodeList);
size_t i;
for (i = 0; current != NULL; i++, current = NodeListNext(nodeList,current))
{
printf("%d: %d\n", i, current->value);
}
}
int FilterAllOddValues(int32_t value)
{
if (0 == value % 2)
return 1;
return 0;
}
void TestNodeList()
{
NodeList myNodeList;
NodeListInit(&myNodeList);
for (int32_t value = 0; value < 10; value++)
{
NodeListAddBack(&myNodeList, value);
}
DumpNodeList(&myNodeList);
size_t removeCount = NodeListFilter(&myNodeList, FilterAllOddValues);
printf("%d nodes removed by filter.\n", removeCount);
DumpNodeList(&myNodeList);
NodeListClear(&myNodeList);
}
One obvious aspect is, that the number of head/tail special handling if-branches is greatly reduced compared to a non-sentinel implementation.
Another obvious aspect is that I ran it with a c++ compiler and thusly added a cast to the malloc() statements. Please resist the urge to write comments like "Don't cast malloc()", all you hardcore c-programmers ;)
I did a brief smoke test with the test code given below. There still might be errors in functions not covered by the test code.

segmentation fault linked-list in c

please dont press the rep minus button so easily im new here- be nice please
i have slist.h implementing by slist.c
here is the slist.h
#ifndef DBLLIST_H
#define DBLLIST_H
//! The definition of a double linked list node
typedef struct dbllist_node
{
void *data; // Pointer to data of this node
struct dbllist_node *next; // Pointer to next node on list
struct dbllist_node *prev; // Pointer to previous node on list
}dbllist_node_t;
//! The definition of a double linked list
struct dbllist
{
dbllist_node_t *head; // Pointer to head of list
dbllist_node_t *tail; // Pointer to tail of list
unsigned int size; // The number of elements in the list
};
//! double linked list type
typedef struct dbllist dbllist_t;
// you have to use these macros, do not use the inner variables of the list!!
//! Macro to get the head node of a list l
#define dbllist_head(l) l->head
//! Macro to get the tail node of a list l
#define dbllist_tail(l) l->tail
//! Macro to get the size of a list l
#define dbllist_size(l) l->size
//! Macro to get the next node of l
#define dbllist_next(n) n->next
//! Macro to get the prev node of l
#define dbllist_prev(n) n->prev
//! Macro to get the data of node l
#define dbllist_data(n) n->data
//! Specifies whether dbllist_destroy should deallocate or not stored elements
typedef enum { DBLLIST_LEAVE_DATA = 0, DBLLIST_FREE_DATA } dbllist_destroy_t;
/** Initialize a double linked list
\param list - the list to initialize */
void dbllist_init(dbllist_t *);
/** Destroy and de-allocate the memory hold by a list
\param list - a pointer to an existing list
\param dealloc flag that indicates whether stored data should also be de-allocated */
void dbllist_destroy(dbllist_t *,dbllist_destroy_t);
/** Append data to list (add as last node of the list)
\param list - a pointer to a list
\param data - the data to place in the list
\return 0 on success, or -1 on failure */
int dbllist_append(dbllist_t *,void *);
/** Prepend data to list (add as first node of the list)
\param list - a pointer to list
\param data - the data to place in the list
\return 0 on success, or -1 on failure
*/
int dbllist_prepend(dbllist_t *,void *);
/** \brief Remove the specific node from the list.
\param to a pointer to the list
\param pointer to the node that should be removed.
\param dealloc flag that indicates whether to de-allocated the data in the node
\return 0 on success, or -1 on failure
*/
int dbllist_remove(dbllist_t *, dbllist_node_t* ,dbllist_destroy_t);
#endif
and now the slist.c i wrote
my problem is when ever i call the destroy function im facing segmentation fault at the last node.. i can provide main that i wrote too.
#include "slist.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void dbllist_init(dbllist_t *list)
{ if(list != NULL)
{
dbllist_head(list) = NULL;
dbllist_tail(list) = NULL;
dbllist_size(list) = 0;
}
}
int dbllist_append(dbllist_t *list,void *data)
{
dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(temp == NULL)
return -1;
dbllist_data(temp) = data;
if(list!=NULL)
{
if(dbllist_head(list) == NULL)
{
//dbllist_next(temp) = NULL;
dbllist_prev(temp) = NULL;
dbllist_head(list) = temp;
dbllist_tail(list) = temp;
dbllist_size(list)++;
return 0;
}
else
{
dbllist_next(temp) = NULL;
dbllist_prev(temp) = dbllist_tail(list);
dbllist_next(dbllist_tail(list)) = temp;
dbllist_tail(list) = temp;
dbllist_size(list)++;
return 0;
}
}
return -1;
}
int dbllist_prepend(dbllist_t *list,void *data)
{
dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(temp == NULL)
return -1;
dbllist_data(temp) = data;
if(list!=NULL)
{
if(dbllist_head(list) == NULL)
{
//dbllist_next(temp) = NULL;
dbllist_prev(temp) = NULL;
dbllist_head(list) = temp;
dbllist_tail(list) = temp;
dbllist_size(list)++;
return 0;
}
else
{
dbllist_next(temp) = dbllist_head(list) ;
dbllist_prev(temp) = NULL;
dbllist_prev(dbllist_head(list)) = temp;
dbllist_head(list) = temp;
dbllist_size(list)++;
return 0;
}
}
return -1;
}
/**
int dbllist_remove(dbllist_t *list, dbllist_node_t* pointer,dbllist_destroy_t dealloc)
{
dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(temp == NULL)
return -1;
temp = dbllist_head(list);
if(list != NULL && pointer !=NULL)
{
if(pointer == dbllist_head(list))
{
if(dealloc != DBLLIST_LEAVE_DATA)
free(dbllist_data(pointer));
dbllist_head(list) = NULL;
dbllist_size(list) = 0;
dbllist_tail(list) = NULL;
free(dbllist_head(list));
free(temp);
return 0;
}
if(pointer == dbllist_tail(list))
{
dbllist_tail(list) = dbllist_prev(dbllist_tail(list)) ;
dbllist_next(dbllist_tail(list)) = NULL;
if(dealloc != DBLLIST_LEAVE_DATA)
free(dbllist_data(pointer));
free(temp);
free(pointer);
dbllist_size(list)--;
return 0 ;
}
int tempSize = 1;
for(temp = dbllist_next(temp) ; tempSize< dbllist_size(list); temp = dbllist_next(temp),tempSize++)
if(temp == pointer)
{
dbllist_next(dbllist_prev(temp)) = dbllist_next(temp);
dbllist_prev(dbllist_next(temp)) = dbllist_prev(temp);
if(dealloc != DBLLIST_LEAVE_DATA)
free(dbllist_data(pointer));
free(temp);
free(pointer);
dbllist_size(list)--;
return 0;
}
}
return -1;
}
*/
int dbllist_remove(dbllist_t *list, dbllist_node_t* pointer,dbllist_destroy_t dealloc)
{
if(list == NULL || pointer == NULL )
return -1;
//printf("%d \n",(int)dbllist_data(current));
if( pointer == dbllist_head(list))
{
dbllist_head(list) = dbllist_next(dbllist_head(list));
if(dealloc == DBLLIST_FREE_DATA)
free(dbllist_data(dbllist_prev(dbllist_head(list))));
free(dbllist_prev(dbllist_head(list)));
dbllist_prev(dbllist_head(list)) = NULL;
dbllist_size(list)--;
return 0;
}
if(pointer == dbllist_tail(list))
{
dbllist_tail(list) = dbllist_prev(dbllist_tail(list));
if(dealloc == DBLLIST_FREE_DATA)
free(dbllist_data(dbllist_next(dbllist_tail(list))));
free(dbllist_next(dbllist_tail(list)));
dbllist_next(dbllist_tail(list)) = NULL;
dbllist_size(list)--;
return 0;
}
//int i = 1;
dbllist_node_t *current = dbllist_next(dbllist_head(list));
while(current)
{
if(current == pointer)
{
dbllist_next(dbllist_prev(current)) = dbllist_next(current) ;
dbllist_prev(dbllist_next(current)) = dbllist_prev(current) ;
dbllist_size(list)--;
if(dealloc == DBLLIST_FREE_DATA)
free(dbllist_data(current));
free(current);
current = NULL;
return 0;
}
current = dbllist_next(current);
}
free(current);
return -1;
}
void dbllist_destroy(dbllist_t *list ,dbllist_destroy_t dealloc)
{
//dbllist_node_t *current = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
//dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
while (dbllist_head(list) != NULL)
{
//dbllist_node_t *current;
dbllist_node_t *temp ;
temp = dbllist_tail(list);
while(temp)
{
dbllist_remove(list,temp , dealloc);
printf("in\n");
temp = dbllist_tail(list);
printf("out \n");
}
//temp = dbllist_head(list);
//dbllist_remove(list,temp , dealloc);
//free(temp);
}
//free(current);
//free(temp);
}
can someone understand the error and explain to me how to fix it
im trying over a feew hours now without success
In this code:
if( pointer == dbllist_head(list))
{
// After next line: list->head points to next node (could be null)
dbllist_head(list) = dbllist_next(dbllist_head(list));
if(dealloc == DBLLIST_FREE_DATA)
// -- If head is now NULL, what happens below? --
free(dbllist_data(dbllist_prev(dbllist_head(list))));
free(dbllist_prev(dbllist_head(list)));
dbllist_prev(dbllist_head(list)) = NULL;
dbllist_size(list)--;
return 0;
}
the right answer is:
if(!dbllist_next(dbllist_head(list)))
{
if(dealloc == DBLLIST_FREE_DATA )
free(dbllist_data(dbllist_head(list)));
free(dbllist_head(list));
dbllist_head(list) = NULL;
dbllist_size(list)--;
return 0;
}
add this before the head part in remove function
because of a null pointer exception i did when in the head of the list.
thanks
In your Remove function dbllist_remove the section that is for the head case(pun intended ;)) tries to free memory that is NULL and not allocated.
The arguments free(dbllist_data(dbllist_prev(dbllist_head(list)))) AND dbllist_data(dbllist_prev(dbllist_head(list))) will not work as you have already removed the next element as well as its pointers. It was freed earlier in your destroy function. So, you cannot rely on the previous pointer actually pointing to anything.
So, I would modify your while loop in the destroy function to wait until head->next is null and then simply delete it outside of the loop and not use the standard remove function. Or modify your head case to take into account when head->next is null.

Hashmap with Linked List to find word count

I have been working on this little project for quite some time and I can't figure out why I'm not getting the results that are expected. I am a beginner to C programming so my understanding with pointers and memory allocation/deallocation is novice. Anyways, I have constructed this segment of code by originally building a hash function, then adding a count to it. However, when I test it, sometimes the count works, sometimes it doesn't. I'm not sure whether it's the fault of the hash function, or the fault of the way I set up my count. The text file is read one line at a time and is a string consisting of a hexadecimal.
struct node {
char *data;
struct node *next;
int count; /* Implement count here for word frequencies */
};
#define H_SIZE 1024
struct node *hashtable[H_SIZE]; /* Declaration of hash table */
void h_lookup(void)
{
int i = 0;
struct node *tmp;
for(i = 0; i < H_SIZE; i++) {
for(tmp = hashtable[i]; tmp != NULL; tmp = tmp->next) {
if(tmp->data != 0) {
printf("Index: %d\nData: %s\nCount: %d\n\n", i,
tmp->data, tmp->count);
}
}
}
}
/* self explanatory */
void h_add(char *data)
{
unsigned int i = h_assign(data);
struct node *tmp;
char *strdup(const char *s);
/* Checks to see if data exists, consider inserting COUNT here */
for(tmp = hashtable[i]; tmp != NULL; tmp = tmp->next) {
if(tmp->data != 0) { /* root node */
int count = tmp->count;
if(!strcmp(data, tmp->data))
count= count+1;
tmp->count = count;
return;
}
}
for(tmp = hashtable[i]; tmp->next != NULL; tmp = tmp->next);
if(tmp->next == NULL) {
tmp->next = h_alloc();
tmp = tmp->next;
tmp->data = strdup(data);
tmp->next = NULL;
tmp->count = 1;
} else
exit(EXIT_FAILURE);
}
/* Hash function, takes value (string) and converts into an index into the array of linked lists) */
unsigned int h_assign(char *string)
{
unsigned int num = 0;
while(*string++ != '\0')
num += *string;
return num % H_SIZE;
}
/* h_initialize(void) initializes the array of linked lists. Allocates one node for each list by calling h_alloc which creates a new node and sets node.next to null */
void h_initialize(void)
{ int i;
for(i = 0; i <H_SIZE; i++) {
hashtable[i] = h_alloc();
}
}
/* h_alloc(void) is a method which creates a new node and sets it's pointer to null */
struct node *h_alloc(void)
{
struct node *tmp = calloc(1, sizeof(struct node));
if (tmp != NULL){
tmp->next = NULL;
return tmp;
}
else{
exit(EXIT_FAILURE);
}
}
/* Clean up hashtable and free up memory */
void h_free(void)
{
struct node *tmp;
struct node *fwd;
int x;
for(x = 0; x < H_SIZE; x++) {
tmp = hashtable[x];
while(tmp != NULL) {
fwd = tmp->next;
free(tmp->data);
free(tmp);
tmp = fwd;
}
}
}
I assume that the count is not being incremented when it does not work. It is possible that strdup is not able to allocate memory for the new string and is returning NULL. You should check the return value to and exit gracefully if it fails.

Resources