Map Array in C - Linked List w/ Key: Value - c

Ok my issue is when I write the node it just overwrites the head node, so when you call map_get you only get one node with data. I want to hand the data on the head or push the head node and hang it front either works, whatever one is the easiest would be best thanks for your help.
#include <assert.h>
#include<stdlib.h>
#include "map.h"
#include <string.h>
int main(){
map_t* newList = malloc(sizeof(map_t));
map_init(newList);
const char* passString ="a";
const char* secondString="2";
map_put(newList,"3","3");
map_put(newList,"7","34");
map_put(newList,"a","45");
map_put(newList,passString,secondString);
map_get(newList,secondString);
}
void map_init(map_t* self) {
map_entry_t* newNode= malloc(sizeof(map_entry_t)); // allocate
self->size = 0;
self->entry = newNode; // link next
}
int map_put(map_t* self, const char* key, const char* val) {
assert(self != NULL);
map_entry_t* current;
//current = self->entry->key;
while(current->next != NULL){
current = current->next;
}
self->entry->key = key;
self->entry->value = val;
map_entry_t* newNode = malloc(sizeof(map_entry_t));
printf("\ntry printing the list \n");
printf(self->entry->key);
printf(" :was the key and the value is \n");
printf(self->entry->value);
printf("\n");
}
const char* map_get(map_t* self, const char* key) {
assert(self != NULL);
const char* target = key;
int i=0;
for(i; i<=self->size; i++)
{
printf("\n\ninside the list\n");
printf(self->entry->value);
printf("\n");
}
}
int map_size(map_t* self) {
assert(self != NULL);
}
int map_remove(map_t* self, const char* key) {
assert(self != NULL);
}
int map_serialize(map_t* self, FILE* stream) {
assert(self != NULL);
}
int map_deserialize(map_t* self, FILE* stream) {
assert(self != NULL);
}
void map_destroy(map_t* self) {
assert(self != NULL);
}
map.h
#ifndef __A1_MAP_H__
#define __A1_MAP_H__
#include <stdio.h>
#define SYS_ERROR -1
#define OK 0
#define KEY_EXISTS 1
#define NO_KEY_EXISTS 2
// Strange type definition due to the recursive nature
// of the struct. This technique is called 'forward
// declaration' and is necessary for compilation reasons.
typedef struct _map_entry map_entry_t;
struct _map_entry {
char* key;
char* value;
map_entry_t* next;
} ;
typedef struct _map {
map_entry_t* entry;
int size;
} map_t;
// Part one functions.
void map_init(map_t*);
int map_put(map_t*, const char*, const char*);
const char* map_get(map_t*, const char*);
int map_remove(map_t*, const char*);
int map_size(map_t*);
void map_destroy(map_t*);
// Part two functions.
int map_serialize(map_t*, FILE*);
int map_deserialize(map_t*, FILE*);
#endif

In map_put, you should initialize current to point at the head of the list self. Right now, it starts pointing ... somewhere ... in memory, and then you try to walk a list from there. You then completely ignore that and write directly into the head element of the list (self) instead of a new node (newNode). You'll also need to then set a link from current to your new node.

Related

Pointer disappeared after passing to some functions (even with malloc)

My problem is that I created a pointer at the bottom Main.
Main will call load() to read input from a dictionary and insert the words in a inputfile into a TRIE *dict by calling insert() and getnode(). However, after load() return true, the *dict lost all of the value and I cannot get what I expected(i.e. showing cat is present as it is in my dictionary input file).
I have read from other websites that pointers can retain its value after doing malloc. So I have malloced for the *dict. Please kindly let me know why the value disappeared.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define CHAR_TO_INDEX(c) ((int)c - (int)'a')
#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
struct dict
{
char words[46];
struct dict* dictPath[26];
bool isEndOfWord;
};
// Returns new trie node (initialized to NULLs)
struct dict *getNode(void)
{
struct dict *pNode = NULL;
pNode = (struct dict *)malloc(sizeof(struct dict));
if (pNode)
{
int i;
for (i = 0; i < 26; i++)
pNode->dictPath[i] = NULL;
}
return pNode;
}
void insert(struct dict *root, const char *key)
{
int level;
int length = strlen(key);
int index;
struct dict *pCrawl = root;
for (level = 0; level < length; level++)
{
index = CHAR_TO_INDEX(key[level]);
if (!pCrawl->dictPath[index])
{
pCrawl = malloc(sizeof(struct dict));
pCrawl->dictPath[index] = getNode();
}
printf("%i\n",index);
pCrawl = pCrawl->dictPath[index];
}
// mark last node as leaf
pCrawl->isEndOfWord = true;
}
// Returns true if key presents in trie, else false
bool search(struct dict *root, const char *key)
{
int level;
int length = strlen(key);
int index;
struct dict *pCrawl = root;
for (level = 0; level < length; level++)
{
index = CHAR_TO_INDEX(key[level]);
if (!pCrawl->dictPath[index])
{
return false;
}
pCrawl = pCrawl->dictPath[index];
}
return (pCrawl != NULL && pCrawl->isEndOfWord);
}
bool load(struct dict *root, char *inputfile){
// open the dictionary file
FILE *infile = fopen(inputfile,"r");
int dictchar;
char tmpword[46];
int cnt = 0;
root = getNode();
// start iterating to read char
do
{
// read the character
dictchar = fgetc(infile);
if (dictchar != '\n')
{
// assign the dictionary character to a tmpword. tmpword will be used to fit into TRIES later
tmpword[cnt] = dictchar;
cnt ++;
}
// if the character is '\n', fit tmpword into TRIES
else
{
tmpword[cnt] = '\0';
cnt = 0;
for (int i = 0; i < ARRAY_SIZE(tmpword); i++)
insert(root, tmpword);
}
} while (dictchar != EOF);
return true;
}
int main (int argc, char *argv[]){
if (argc != 2)
{
return 1;
}
struct dict *root = malloc(sizeof(struct dict));
load(root, argv[1]);
char output[][32] = {"Not present in trie", "Present in trie"};
printf("%s --- %s\n", "cat", output[search(root, "cat")] );
return 0;
}
p.s. I took reference from https://www.geeksforgeeks.org/trie-insert-and-search/
In you function,
bool load(struct dict *root, char *inputfile)
you pass a root pointer, but then replace it with the result of getNode.
The calling code will not see this change.
You need to pass a pointer to the root pointer,
bool load(struct dict **root, char *inputfile)
for the calling code to see the change.
More simply, since you throw away the root with
root = getNode();
right near the top of the function, you could change the load signature:
struct dict * load(char *inputfile)
Instead of return true; at the end, return root; instead.
You don't have a path returning flase anyway.
Change the calling code too.
Instead of
struct dict *root = malloc(sizeof(struct dict));
load(root, argv[1]);
try this:
struct dict *root = load(argv[1]);

Inserting nodes in a linked list in decreasing order - C

I have to make a list that arrange the people in decreasing order of their number('no' for my program). I tryed to make it by modifying the addNode function but I got no result(peoples do not arrange by their number). This is my code:
Header code:
#ifndef __EX__
#define __EX__
typedef struct Person{
char name[10];
float no;
struct Person *pNext;
} NODE, *pNODE, **ppNODE;
void addNode(ppNODE, pNODE);
void travers(pNODE, unsigned int*);
#endif
Functions folder:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include "EX.h"
void addNode (ppNODE ppPrim, pNODE p){
pNODE q = (pNODE)malloc(sizeof(NODE));
assert(q!=NULL);
printf("Add name: \n");
scanf("%s", &q->name);
printf("\nAdd no: ");
scanf("%f", &q->no);
if (p == NULL || q->no < p->no) {
q->pNext = *ppPrim;
*ppPrim = q;
} else {
q->pNext = p->pNext;
p->pNext = q;
}
return;
}
void travers(pNODE pPrim, unsigned int *pLen){
*pLen = 0;
pNODE tmp = pPrim;
while (tmp != NULL){
puts (tmp->name);
fprintf(stdout, " no %.2f\n", tmp->no);
tmp = tmp->pNext;
(*pLen)++;
}
return;
}
Main folder:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include "EX.h"
int main(){
unsigned int len;
pNODE prim = NULL;
int i;
for (i=0; i<=1; i++){
addNode(&prim, prim);
addNode(&prim, prim->pNext);
}
travers(prim, &len);
return 0;
}
When you insert a new node to the list, you must traverse the list until you find a suitable place to insert it. Your code takes a second argument, which isn't really needed and causes confusion, and only looks at that.
The code to insert a code q at the end of a list that is defined by its head is:
Node *prev = NULL;
Node *p = *head;
while (p) {
prev = p;
p = p->pNext;
}
q->pNext = p;
if (prev == NULL) {
*head = q;
} else {
prev->pNext = q;
}
You can get rid of keeping track of the previous node and the distinction between inserting at the head and inserting after that by traversing the list with a pointer to node pointer:
Node **p = &head;
while (*p && (*p)->no < q->no) {
p = &(*p)->pNext;
}
q->pNext = *p;
*p = q;
In this concise code, p holds the address of the head at first and the address of the pNext pointer of the previous node. Both can be updated via *p.
You can now use this code to traverse only as far as the numbers associated with each node are smaller than the one of the node to insert. here's a complete program:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct Node Node;
void addNode(Node **p, const char *name, float no);
void travers(Node *pPrim, unsigned int *pLen);
struct Node {
char name[10];
float no;
Node *pNext;
};
void addNode(Node **p, const char *name, float no)
{
Node *q = malloc(sizeof(*q));
assert(q != NULL);
snprintf(q->name, sizeof(q->name), "%s", name);
q->no = no;
while (*p && (*p)->no < q->no) {
p = &(*p)->pNext;
}
q->pNext = *p;
*p = q;
}
void traverse(const Node *pPrim, unsigned int *pLen)
{
*pLen = 0;
while (pPrim != NULL) {
fprintf(stdout, "%-12s%.2f\n", pPrim->name, pPrim->no);
pPrim = pPrim->pNext;
(*pLen)++;
}
}
int main()
{
unsigned int len;
Node *prim = NULL;
addNode(&prim, "Alice", 0.23);
addNode(&prim, "Bob", 0.08);
addNode(&prim, "Charlie", 0.64);
addNode(&prim, "Dora", 0.82);
traverse(prim, &len);
printf("\n%u entries.\n", len);
return 0;
}
Things to node:
I've used Node * and Node ** instead of the typedeffed pNODE and ppNODE. In my opinion using the C pointer syntax is clearer.
You should separate taking user input from adding a node.
In your code you shouldn't pass the address of the char array when scanning a string, just the char array. (It happens to work, but it isn't correct. The compiler should warn you about that.)

Adding and Finding node in LinkedList C

I have a small bug somewhere, was hoping someone with a little more C knowledge than I have to run through it real quick.
Im not certain if something is wrong in the map_put method or the map_get method, but I can only seem to map_get the first object in my list!?
anyhelp would be appreciated! thanks!
//----------------main---------------
#include <assert.h>
#include <stdio.h>
#include "map.h"
#include "map.c"
int main(){
map_t* newList = malloc(sizeof(map_t));
const char* passString ="a";
const char* secondString="2";
map_put(newList,"1","45");
map_put(newList,"3","3");
map_put(newList,"7","34");
map_put(newList,"a","45");
map_put(newList,"f","45");
map_put(newList,"2","45");
map_put(newList,passString,secondString);
map_get(newList, "3");
//printf("%d\n", map_size(newList));
printf("%1s\n", map_get(newList, "3"));
printf("%1s\n", map_get(newList, "1"));
printf("%1s\n", map_get(newList, "2"));
}
-----------------map.c----------------------
#include <assert.h>
#include "map.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef int bool;
enum { false, true };
int size;
void map_init(map_t* self)
{
if(self==NULL)
self = (map_t*)malloc(sizeof(map_t));
self->entry = NULL;
self->size = 0;
}
int map_put(map_t* self, const char* key, const char* val)
{
assert(self != NULL);
//Create The Node Here For Storing Info;
struct _map_entry *node = (struct _map_entry *)malloc(sizeof(struct _map_entry));
node->key = (char *)key;
node->value = (char *)val;
node->next = NULL;
if(self==NULL)
{
map_init(self);
self->entry = node;
self->size = 1;
}
else
{
struct _map_entry *TempNode = self->entry;
if(TempNode==NULL)
{
TempNode = node;
self->entry = TempNode;
self->size = 1;
}
else
{
bool KeyExist = false;
while(TempNode->next != NULL)
{
if(strcmp(TempNode->key,node->key)==0)
{
KeyExist = true;
TempNode->value = node->value;
break;
}
TempNode = TempNode->next;
}
if(KeyExist)
{
return "Already Exists";
}
TempNode ->next = node;
self->size = self->size + 1;
}
}
}
const char* map_get(map_t* self, const char* key)
{
assert(self != NULL);
if(self==NULL)
return "";
struct _map_entry *StartNode = self->entry;
while(StartNode != NULL)
{
if(strcmp(StartNode->key,key)==0){
return StartNode->value;
}
else
StartNode = StartNode->next;
}
return "";
}
int map_size(map_t* self)
{
assert(self != NULL);
if(self==NULL)
return 0;
else
return size;
}
int map_remove(map_t* self, const char* key)
{
assert(self != NULL);
if(self==NULL)
return 0;
int totalRemovedNode = 0;
struct _map_entry *StartNode = self->entry;
struct _map_entry *TempNode = NULL;
while(StartNode != NULL)
{
if(strcmp(StartNode->key,key)==0)
{
struct _map_entry *Node = StartNode->next;
free(StartNode);
StartNode = TempNode;
TempNode = StartNode;
TempNode->next = Node;
size = size - 1;
totalRemovedNode = totalRemovedNode + 1;
}
StartNode = StartNode->next;
size = size - totalRemovedNode;
}
return totalRemovedNode;
}
void map_destroy(map_t* self)
{
assert(self != NULL);
struct _map_entry *StartNode = self->entry;
struct _map_entry *TempNode = NULL;
while(StartNode != NULL)
{
TempNode = StartNode->next;
free(StartNode);
StartNode = TempNode;
}
self->size = 0;
self->entry = NULL;
free(self);
}
int map_deserialize(map_t* self, FILE* stream)
{
assert(self != NULL);
assert(stream != NULL);
self->entry = NULL;
if(stream == NULL)
{
return 0;
// error
} else {
char *line = malloc(1024);
while(fgets(line,1024,stream))
{
char *value = strstr(line,":");
int keylength = value - line;
char *key = malloc(sizeof(keylength));
int i;
for(i = 0; i < keylength; i++)
{
key[i] = line[i];
}
key[keylength] = '\0';
value++;
map_put(self,key,value);
}
}
fclose(stream);
return self->size;
}
int map_serialize(map_t* self, FILE* stream)
{
assert(self != NULL);
assert(stream != NULL);
if(stream == NULL)
{
return 0;
}
struct _map_entry *it = self->entry;
while (it != NULL)
{
fwrite (it->key, sizeof (it->key), 1, stream);
fwrite (":", 1, 1, stream);
fwrite (it->value, sizeof (it->value), 1, stream);
fwrite ("\r\n", 2, 1, stream);
it = it->next;
}
return self->size;
}
----------------------map.h---------------------------
#ifndef __A1_MAP_H__
#define __A1_MAP_H__
#include <stdio.h>
typedef struct _map_entry map_entry_t;
struct _map_entry {
char* key;
char* value;
map_entry_t* next;
};
typedef struct _map {
map_entry_t* entry;
int size;
} map_t;
// Part one functions.
void map_init(map_t*);
int map_put(map_t*, const char*, const char*);
const char* map_get(map_t*, const char*);
int map_remove(map_t*, const char*);
int map_size(map_t*);
void map_destroy(map_t*);
// Part two functions.
int map_serialize(map_t*, FILE*);
int map_deserialize(map_t*, FILE*);
#endif
---------------------------
General Notes
According to 9899:2011 section 7.1.3 Reserved Identifiers, "all identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use". The same section of the C standard also says "All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces".
Please note that "reserved" means "you aren't allowed to do it". This means that when you #define __A1_MAP_H__, you are treading on namespace that doesn't belong to you, which is always considered to be inadvisable. Similarly, your struct _map_entry and your struct _map are also treading on reserved namespace. Consider renaming all these symbols.
You should not be casting the value that is returned by the malloc() function. You do this, inconsistently.
You should not be using the assert() macro for normal error checking. The assert() function is for debug-level sanity checks during the development process, that can be safely excluded from the code in production builds.
map_init()
Your map_init() function is wrong. If you pass a NULL to the map_init() function it allocates storage for one map_t, and initializes it, but doesn't have any way of returning it to the caller, so that storage is leaked (lost) as soon as the function returns, and the caller doesn't get anything. You should rewrite this function either to require a valid object be passed to it, or to allow it to return a pointer to a newly allocated object.
map_put()
You declare and define the map_put() function as returning a value of type int, but the only code path that returns anything at all, returns a char *.Additionally, this function doesn't copy the strings that are passed to it, but you're passing it both string literals and strings that are allocated using malloc().
map_get()
HINT: What does this function return if the first node is a match? If the second node is a match? If no node is a match?
map_size()
Why is the function returning the value of a file-scope variable that is never properly initialized? Did you perhaps intend, instead, for it to return the value of one of the elements of the map_t structure?
map_remove()
This function is so seriously messed up, that all I can advise you to do is go back to whatever reference you're learning about linked lists from, and re-read it.
map_destroy()
You aren't free()ing the strings attached to each node. You can't, of course, because you aren't copying them in, in map_put(), but some of what you put in there was allocated with malloc(), so you're leaking memory here.
map_deserialize()
This function does an odd half-init of the map_t that's passed to it, and it does it before validating prerequisites.
You allocate storage for line only once, using malloc(), then proceed to pass pointers into the middle of that storage to map_put(), which just stores the pointers instead of copying them, so you're overwriting the value every time you read the next line.
You malloc() storage for key each time through the loop, but you're allocating one byte fewer than you need, so you're constantly writing into storage that you don't own, every time you null-terminate that key you've just copied.
map_serialize()
HINT: If you have a char *foo, what is sizeof(foo)? How does this differ from strlen(foo)?

Heap error in DLL

I'm looking for some help with some C dll programming. I am getting an error in Visual Studio that occurs when I call free from within the dll. The program runs fine in debug mode within the IDE, but when I try to execute it as "Start without debugging", the program crashes. I read that with debugging, the heap is shared, which probably explains why the code runs fine with F5 and not Ctrl-F5. Is this correct??
I've searched around, and I learned that it is dangerous to pass dynamically allocated memory through the dll-exe boundary, however as I am calling malloc and free from within the same dll, this should not be a problem. I have posted the code below. Any help would be greatly appreciated. Please note that this code works on my Linux box, I am simply trying to port it to Windows to garner experience programming in Windows.
Thank you
#ifndef HASHTABLE_H
#define HASHTABLE_H
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the HASHTABLE_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// HASHTABLE_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef HASHTABLE_EXPORTS
#define HASHTABLE_API __declspec(dllexport)
#else
#define HASHTABLE_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* This is a naive implementation
* of a hashtable
*/
typedef struct node {
struct node *next;
char *value;
char *key;
} Node;
typedef struct hashtable {
struct node **nodes;
int num_elements;
int size;
int (*hash_function)(const char * const);
} Hashtable_str;
// Construction and destruction
HASHTABLE_API void tbl_construct(Hashtable_str **table);
HASHTABLE_API void tbl_destruct(Hashtable_str *table);
// Operations
HASHTABLE_API int tbl_insert (Hashtable_str *table, const char * const key, const char * const element); // return the key
HASHTABLE_API int tbl_remove(Hashtable_str *table, const char * const key);
HASHTABLE_API char * tbl_find(Hashtable_str *table, const char * const key); // return the element
HASHTABLE_API int size(Hashtable_str *table); // Return the size
// default hash function
int def_hash(const char * const key);
#ifdef __cplusplus
}
#endif
#endif
Here is the implementation code
// hashtable.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "hashtable.h"
#include <stdlib.h> // for memcpy
#include <stdio.h>
#include <string.h>
#define SIZE 100
int def_hash(const char * const key)
{
// simply sum the ascii
// values and take modulo
// 100
//int i;
//int sum;
//sum = 0;
//for (i=0; key[i] != '\0'; i++)
// sum += key[i];
//return sum % SIZE;
return 0;
}
// construct a hashtable and return a pointer
HASHTABLE_API void tbl_construct(Hashtable_str **tbl)
{
int i;
Hashtable_str *tbl_ptr;
*tbl = (Hashtable_str*) malloc (sizeof(Hashtable_str*));
tbl_ptr = *tbl;
tbl_ptr->nodes = (Node**) malloc (SIZE * sizeof(Node*));
for (i=0; i < SIZE; i++) tbl_ptr->nodes[i] = NULL;
tbl_ptr->hash_function = &def_hash;
tbl_ptr->num_elements = 0;
tbl_ptr->size = SIZE;
}
HASHTABLE_API void tbl_destruct(Hashtable_str *tbl)
{
void free_tbl_node(Node*); // declare the release function
int i;
for (i=0; i < tbl->size; i++)
{
if (tbl->nodes[i] != NULL)
free_tbl_node(tbl->nodes[i]);
}
}
void free_tbl_node(Node *curr_node)
{
if (curr_node->next != NULL)
free_tbl_node(curr_node->next);
free(curr_node->value);
curr_node->value = NULL;
free(curr_node->key);
curr_node->key = NULL;
//free(curr_node);
//Node *temp = NULL;
//Node *temp2 = NULL;
//temp = temp2 = curr_node;
//while (temp->next != NULL)
//{
// temp2=temp->next;
// free(temp->key);
// free(temp->value);
// free(temp);
// temp=temp2;
//}
}
// table operations
HASHTABLE_API int count(Hashtable_str *tbl) { return tbl->num_elements; }
HASHTABLE_API int size(Hashtable_str *tbl) { return tbl->size; }
HASHTABLE_API int tbl_insert(Hashtable_str *table, const char * const key, const char * const element)
{
int hash;
Node *temp_ptr = NULL;
hash = table->hash_function(key);
// printf("Placing into column %d\n", hash);
if (table->nodes[hash] == NULL)
{
table->nodes[hash] = (Node*) malloc(sizeof(Node*));
temp_ptr = table->nodes[hash];
temp_ptr->next = NULL;
temp_ptr->key = (char*) malloc (strlen(key) + 1 * sizeof(char));
temp_ptr->value = (char*) malloc (strlen(element) + 1 * sizeof(char));
strcpy_s(temp_ptr->key, strlen(key)+1, key);
strcpy_s(temp_ptr->value, strlen(element)+1, element);
table->num_elements += 1;
}
else
{
// Collision!!
temp_ptr = table->nodes[hash];
while (temp_ptr->next != NULL)
temp_ptr = temp_ptr->next;
temp_ptr->next = (Node*) malloc(sizeof(Node));
temp_ptr->next->key = (char*) malloc (strlen(key)+1 * sizeof(char));
temp_ptr->next->value = (char*) malloc (strlen(element)+1 * sizeof(char));
temp_ptr->next->next = NULL;
strcpy_s(temp_ptr->next->key, strlen(key)+1, key);
strcpy_s(temp_ptr->next->value, strlen(element)+1, element);
table->num_elements += 1;
}
// Return the hash value itself for hacking
return hash;
}
HASHTABLE_API int tbl_remove(Hashtable_str *tbl, const char * const key)
{
int hash;
Node *temp_ptr = NULL;
Node *chain = NULL;
hash = tbl->hash_function(key);
if (tbl->nodes[hash] == NULL)
return 1;
else
{
temp_ptr = tbl->nodes[hash];
if (strcmp(key, temp_ptr->key) == 0)
{
// The next node is the node in question
chain = temp_ptr->next;
free(temp_ptr->value);
printf("Deleted the value\n");
free(temp_ptr->key);
printf("Deleted the key\n");
//printf("About to delete the node itself\n");
//free(temp_ptr);
tbl->nodes[hash] = chain;
tbl->num_elements -= 1;
return 0;
}
else
{
while (temp_ptr->next != NULL)
{
if (strcmp(key, temp_ptr->next->key) == 0)
{
// The next node is the node in question
// So grab a pointer to the node after it
// and remove the next node
chain = temp_ptr->next->next;
free(temp_ptr->next->key);
free(temp_ptr->next->value);
//free(temp_ptr->next);
temp_ptr->next = chain;
tbl->num_elements -= 1;
return 0;
}
else
temp_ptr = temp_ptr->next;
}
}
// Couldn't find the node, so declare not existent
return 1;
}
}
HASHTABLE_API char * tbl_find(Hashtable_str *tbl, const char * const key)
{
// Compute the hash for the index
int hash;
Node *temp_ptr = NULL;
hash = tbl->hash_function(key);
if (tbl->nodes[hash] == NULL)
return NULL;
else
{
temp_ptr = tbl->nodes[hash];
if (strcmp(key, temp_ptr->key) != 0)
{
while (temp_ptr->next != NULL)
{
temp_ptr = temp_ptr->next;
if (strcmp(key, temp_ptr->key) == 0)
return temp_ptr->value;
}
}
// Couldn't find the node, so declare not existent
return NULL;
}
}
Here's my main
#include <hashtable.h>
#include <utils.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int i=0;
Hashtable_str *my_table = NULL;
tbl_construct(&my_table);
tbl_insert(my_table, "Daniel", "Student");
tbl_insert(my_table, "Derek", "Lecturer");
//tbl_insert(my_table, "Melvyn", "Lecturer");
tbl_print(my_table);
printf("\nRemoving Daniel...\n");
tbl_remove(my_table, "Daniel");
//tbl_print(my_table);
tbl_destruct(my_table);
my_table = NULL;
scanf_s("%d", &i);
return 0;
}
This is incorrect as allocates the size of a pointer, not a Hashtable_str:
*tbl = (Hashtable_str*) malloc (sizeof(Hashtable_str*));
it should be:
*tbl = malloc(sizeof(Hashtable_str));
Same issue with:
table->nodes[hash] = (Node*) malloc(sizeof(Node*));
See Do I cast the result of malloc?

Linked List problems with process sync

This program is a work in progress. It is going to simulate a multiprocessor and I am programming it with producer-consumer sync.
Few problems here:
- My pending_request counter starts 1 lower than it should and goes down to -1. It should stop at 0.
- My remove_queue function also keeps removing one over. It will remove until the list is blank, but it doesn't recognize the list is empty. Then if I run remove_queue one more time, then it recognizes the list empty. SAMPLE OUTPUT AT THE BOTTOM at http://tinyurl.com/3ftytol
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <stdlib.h>
typedef struct pr_struct{
int owner;
int burst_time;
struct pr_struct *next_prcmd;
} prcmd_t;
static prcmd_t *pr_head = NULL;
static prcmd_t *pr_tail = NULL;
static int pending_request = 0;
static pthread_mutex_t prmutex = PTHREAD_MUTEX_INITIALIZER;
int add_queue(prcmd_t *node)
{ pthread_mutex_lock(&prmutex);
//code
prcmd_t *curNode = pr_head;
if(pr_head == NULL) { pr_head = node; return;}
while(curNode->next_prcmd)
{
curNode = curNode->next_prcmd;
}
curNode->next_prcmd = node;
//
pending_request++;
pthread_mutex_unlock(&prmutex);
return(0);
}
int remove_queue(prcmd_t **node)
{
pthread_mutex_lock(&prmutex);
if(pr_head == NULL)
{
//your code
printf("Queue is empty\n");
//
pthread_mutex_unlock(&prmutex);
return(-1);
}
else
{
//your code
prcmd_t *tempNode; tempNode = (prcmd_t*)malloc(sizeof(prcmd_t));
tempNode = *node;
*node = tempNode->next_prcmd;
free(tempNode);
//
pending_request--;
pthread_mutex_unlock(&prmutex);
return(0);
}
}
int get_number_request(void)
{ return pending_request; }
void display_list(prcmd_t *node)
{
if (pr_head == NULL)
{
printf("List is empty!\n\n");
}
printf("-----------\n");
while(node)
{
printf("%i %i\n", node->owner,node->burst_time);
node = node->next_prcmd;
}
int r = get_number_request();
printf("Pending requests: %i\n", r);
}
int main()
{
int i=0;
int length = 4;
prcmd_t *pr[length];
for(i =0;i<length;i++)
{
pr[i] = (prcmd_t*)malloc(sizeof(prcmd_t));
pr[i]->owner = i+1;
pr[i]->burst_time = i + 2;
add_queue(pr[i]);
}
display_list(pr_head);
remove_queue(&pr_head);
display_list(pr_head);
remove_queue(&pr_head);
display_list(pr_head);
remove_queue(&pr_head);
display_list(pr_head);
remove_queue(&pr_head);
display_list(pr_head);
remove_queue(&pr_head);
display_list(pr_head);
}
some things (although maybe not all):
There is no need for a tail pointer if the list is not doubly linked, because there is no way to go from tail to head (no previous pointer)
Why do you malloc in your remove queue?
*node = prHead;
prHead = prHead->next_prcmd;
--pending_request;
in add_queue you have to node->next_prcmd = NULL; otherwwise you will never know the end.
again, some things, but maybe not all...
Mario

Resources