Expanding a hashtable with linked lists there are some errors and warnings. I wanna make sure that the following code is right (expand function) and find out what happens that raise these warnings/errors
EDIT:Thanks to #nos who noticed that my prototype was missing the warnings+errors I refered to gone. Unfortunately now there is this one: " In function expand': undefined reference toadd' collect2: ld returned 1 exit status
EDIT2: I noticed that add function returns back a List* which on expand function there is none variable to "get" it. I put a value there...but error remains :/
EDIT3: Segmentation Fault :( Running with gdb: * glibc detected corrupted double-linked list: 0x0804c6b0 ** CORRECTED. NEW ADD FUNCTION ADDED.
EDIT: Segmentation Fault on strcmp on lookup function. Running with gdb:
(gdb) bt full
0 0x080487b9 in lookup (hashtable=0x804b008, hashval=27,
number=0xbffff3f2 "6900101001") at pro.c:80
list = 0xffffffff
1 0x0804883b in add (hashtable=0x804b008,
number=0xbffff3f2 "6900101001", name=0x804b6e0 "Irgaedggfs",
time=6943)
at pro.c:96
new_elem = 0xffffffff
hashval = 27
2 0x08048bc1 in main (argc=1, argv=0xbffff4b4) at pro.c:234
number = "6900101001"
name = 0x804b6e0 "Irgaedggfs"
time = 6943
typedef struct
{
int length;
struct List *head;
} HashTable;
//resolving collisions using linked lists - chaining
typedef struct
{
char *number;
char *name;
int time;
struct List *next;
}List;
HashTable* expand( HashTable* h )
{
HashTable* new;
int n;
List *node,*next;
PrimesIndex++;
int new_size= primes[PrimesIndex]; /* double the size,odd length */
if (!(new=malloc((sizeof( List*))*new_size))) return NULL;
for(n=0; n< h->length; ++n) {
for(node=h[n].head; node; node=next) {
add (new, node->number, node->name,node->time);
next=node->next;
free(node);
}
}
free(h);
return new;
}
int add ( HashTable* hashtable,char number[10],char* name,int time)
{
List *new_elem;
int hashval=hash (hashtable,number);
new_elem=hashtable[hashval].head;
if(hashtable[hashval].length>0)
{
if ((lookup (hashtable,hashval,number))!=NULL) {return 0;}
}
if (!(new_elem=malloc(sizeof(struct List)))){ return -1;}
//insert values for the new elem
new_elem->number=strdup(number);
new_elem->name=strdup(name);
new_elem->time=time;
hashtable[hashval].head=new_elem;
new_elem->next=NULL;
hashtable[hashval].length++;
/* rehash existing entries if necessary */
if( TableSize(hashtable)>= 2*size])
{
hashtable = expand(hashtable);
if (hashtable ==NULL){
return 0;
}
}
return 1;
}
List *lookup ( HashTable *h ,int hashval,char number[10])
{
List *list=h[hashval].head;
for(list; list!=NULL; list=list->next){
if (strcmp(number,list->number)==0) //**SEGMENTATION**!!!!
return list;
}
return NULL;
}
You need to declare functions before you call them. Otherwise C will, among other things, assume your expand function returns an int.
Simply, place a prototype like this one at the top of your file, after your struct declarations, before your function definitions.
HashTable* expand( HashTable* h ,char number[10],char* name,int time);
declare the function "add" before you define "expand", in which you use "add".
List* add ( HashTable* hashtable,char number[10],char* name,int time);
define expand here..
define add here...
(I don't know how to change lines in the computer; so I have to post an new answer rather than follow your comment. sorry)
Pls try:
int add ( HashTable** phashtable,char number[10],char* name,int time){
...
if(hashTableSize( *phashtable)== 2*(primes[PrimesIndex])){
*phashtable = expand( *phashtable);
}
}
you may need to modify "add" and the invoke of "add" accordingly.
I'm not sure whether this would help. At least this is one of the bugs.
The bug is that if Hashtable is expanded in an add call, after the add call returns, the value of the variable "hashtable" won't change.
Related
source code from tbaMUD
In file "handler.c", we have this "obj_to_room" function, which takes any object dropped in the room and adds it to a linked list. This creates a stack of objects, with the first object at the bottom (head) of the stack, the second object stacked on top the first, and so on. This is the default behavior for linked lists in C.
In file "act.informative.c" we have the "look_at_room" function. That calls the "list_obj_to_char" function. This uses a "for loop" to read the list/stack.
When using a "for loop" to read the list/stack/node, it does so from top (tail) to bottom (head). This, too is the default behavior in C. Therefore, objects dropped in the room are displayed with the most recently dropped object at the top of the list and the first object dropped at the bottom.
That's what causes this issue:
www.tbamud.com/forum/2-general/5530-has-anyone-else-noticed
My goal is to invert the order of objects in that linked list. There are a few hacks I might pull off, but that's just what they would be - hacks, not exactly proper and certainly not elegant. I think the best solution is coding a function using "appendNode" to add objects at the tail (top) of the list instead of its head (bottom).
Toward that end, I need to change this:
/* put an object in a room */
void obj_to_room(struct obj_data *object, room_rnum room)
{
if (!object || room == NOWHERE || room > top_of_world)
log("SYSERR: Illegal value(s) passed to obj_to_room. (Room #%d/%d, obj %p)",
room, top_of_world, (void *)object);
else {
object->next_content = world[room].contents;
world[room].contents = object;
IN_ROOM(object) = room;
object->carried_by = NULL;
if (ROOM_FLAGGED(room, ROOM_HOUSE))
SET_BIT_AR(ROOM_FLAGS(room), ROOM_HOUSE_CRASH);
}
}
to something like this:
/*put an object in a room */
void obj_to_room(struct obj_data *object, room_rnum room)
{
if (!object || room == NOWHERE || room > top_of_world)
{
log("SYSERR: Illegal value(s) passed to obj_to_room. (Room #%d/%d, obj %p)",
room, top_of_world, (void*) object);
}
else
{
/*function to add objects at the tail of the list instead of its head*/
/*everything hinges on this single line and I probably have it all kinds of wrong*/
/*struct node* appendNode(struct node** head, int key)*/
struct world[room].contents* appendNode(struct world[room].contents** object, room_rnum room)
{
/* special case for length 0*/
if (object == NULL)
{
*object = world[room].contents;
}
else
{
/* locate the last node */
while (object->next_content != NULL)
{
object = object->next_content;
}
object->next_content = world[room].contents;
world[room].contents = object;
IN_ROOM(object) = room;
object->carried_by = NULL;
if (ROOM_FLAGGED(room, ROOM_HOUSE))
SET_BIT_AR(ROOM_FLAGS(room), ROOM_HOUSE_CRASH);
}
}
}
}
Problem 1
Although I'm familiar with multiple programming languages, C is not one of them. When it comes to the idiosyncrasies and technical fine points of the language, I know nothing. That makes reading C code challenging and writing it even more so.
Problem2
I understand the format should be:
struct node* appendNode(struct node** head, int key)
I think the head and int key are correct, but I'm unable to identify the node in the original code. So I used my best guess.
It's not surprising that attempting to compile this code yields:
handler.c: In function ‘obj_to_room’:
handler.c:681:19: error: expected identifier or ‘(’ before ‘[’ token
681 | struct world[room].contents* appendNode(struct world[room].contents** object, room_rnum room)
| ^
make[1]: *** [<builtin>: handler.o] Error 1
Ok, I suspect there's all sorts of things wrong with that line, but I don't know how to fix it. I'm hoping that some brilliant coder will be kind enough to help out.
This does the trick.
/* put an object in a room */
void obj_to_room(struct obj_data* object, room_rnum room)
{
if (!object || room == NOWHERE || room > top_of_world) {
log("SYSERR: Illegal value(s) passed to obj_to_room. (Room #%d/%d, obj %p)", room, top_of_world, (void *)object);
}
else {
if (world[room].contents == NULL) { // here, we have an empty list.
world[room].contents = object; // Just add it.
}
else {
struct obj_data* i = world[room].contents; // define a temporary pointer
while (i->next_content != NULL) {
i = i->next_content; // find the first without a next_content
}
i->next_content = object; // add it at the end
}
object->next_content = NULL; // end of the linked list
IN_ROOM(object) = room;
object->carried_by = NULL;
if (ROOM_FLAGGED(room, ROOM_HOUSE)) {
SET_BIT_AR(ROOM_FLAGS(room), ROOM_HOUSE_CRASH);
}
}
}
<DBDLinkedList.h>
...
typedef struct _dbDLinkedList
{
Node * head;
Node * tail;
Node * cur;
int numOfData;
} DBDLinkedList;
typedef DBDLinkedList List;
...
<mysourcecode.c>
int main(void)
{
...
List list;
int data;
ListInit(&list);
for(i=0; i<ID_LEN; i++)
LInsert(&list, new_id[i]);
solution(list, data);
...
}
int solution(List list, int data)
{
...
if(LFirst(&list, &data))
{
int i=1;
if(data==46)
LRemove(&list);
i++;
while(LNext(&list, &data))
{
if(i==numOfData)
if(data==46)
LRemove(&list);
i++;
}
}
...
}
I used dummy node doubly linked list.
When I complied this project, error occurred :
‘numOfData’ undeclared (first use in this function).
I'm not used to using Linked list.
How do I send the linked list as a function argument(for solution())?
from what I could see, the problem might not be in sending the linked list as a function argument. In "if(i==numOfData)", you are trying to access the numOfData, which is a part of a 'List' structure, so you need to access it through 'List' variable.... Perhaps replacing that line of code with something like "if(i == list.numOfData)" will do the trick
numOfData is not a variable. You most probably intended to access the current node's numOfData member.
But you really don't need to access that member directly. It seems likely (without seeing the code) that LNext will put that value in your data variable -- it is the reason why you pass &data as argument to LNext.
This brings us to another issue in your code. You call solution with data, but you never gave data a value. If the intention is to remove the node with value 46, then the main program should call solution as follows:
solution(list, 46);
And solution should be implemented as follows:
int solution(List list, int dataToRemove) {
if (!LFirst(&list, &data)) {
return 0; // to indicate that value to delete was not found
}
while (data != dataToRemove) {
if (!LNext(&list, &data)) {
return 0; // to indicate that value to delete was not found
}
}
LRemove(&list);
return 1; // to indicate success
}
So let's say I have 3 nodes in my linked lists, each with a first name in it. The list is supposed to be ordered alphabetically. I need to navigate with pointers
I have a .h interface and a .c file implementation, so you can assume anything prototyped int he List.c file is not in the header file.
Let me explain what's going on logically, to make my code a bit easier to understand. ListP is a pointer to struct List that has simple attributes like logical size, physical size and a pointer to the head of the linked list. The character strings are typedefd as ListItemP for easy reconstruction to an integer linked list etc if need be.
List.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "List.h"
typedef struct Entry *EntryP;
EntryP newEntry(ListItemP thisItem);
struct List
{
int sizeL;
int sizeP;
ListItemP head;
};
struct Entry
{
ListItemP content;
struct Entry *next;
};
ListP newList()
{
ListP thisList = (ListP) malloc(sizeof(ListP));
thisList->head = 0x00;
thisList->sizeL = 0;
thisList->sizeP = 0;
return thisList;
}
void insertItemList(ListP thisList, ListItemP thisItem)
{
EntryP thisEntry = newEntry(thisItem);
thisEntry->content = thisItem;
// Make a conditional for the first condition (no items in list)
if ((thisList->head == 0x00) || (strcmp(thisItem, thisList->head) < 0)) {
thisList->head = thisEntry->content;
thisEntry->next = 0x00;
}
// The other conditional are what I don't understand, how to put go through
navigate through the list via pointers and such.
thisList->sizeL++;
thisList->sizeP++;
}
void displayList(ListP thisList)
{
printf("First Item: %s\n",thisList->head);
}
/*
* Not in the interface
*/
EntryP newEntry(ListItemP thisItem)
{
EntryP thisEntry = (EntryP) malloc(sizeof(EntryP));
thisEntry->content = thisItem;
thisEntry->next = NULL;
return thisEntry;
}
I would post my main.c (or tester.c or whatever you want to call it) but I don't really think its going to help at all, all the linked list navigation is going to occur in the List.c file.
So my question is this, assuming I have 3 or 4 or however many nodes, how can I navigate around them so I can do things like string compares and yadda yadda in order to place new strings in the linked list in alphabetical order.
Thank you!
I am fairly new to C and have been learning from K&R's book The C Programming Language.
After doing the exercises on Binary trees I wanted to make a header for binary trees for
char*, long and double.
There is a function in the following code that has been giving me grief - it should fill an array of character pointers with the values stored in the tree in lexicographical order however it has a bug somewhere. Here's the code for the String Tree Header btree.h:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/************** TYPES **************/
typedef struct ctree
{
char *name;
ctree *left;
ctree *right;
};
/************** Globals **************/
static int c_inc = 0;
/************** Function Prototypes **************/
ctree *add_to_c_tree (ctree *cnode, char *name);
void print_c_tree (ctree *cnode);
ctree *c_tree_alloc (void);
void c_tree_free (ctree *cnode);
void return_c_tree (ctree *cnode, char **array);
/************** Function Definitions **************/
/* add_to_c_tree() : Adds a new node to a *character binary tree */
ctree *add_to_c_tree (ctree *cnode, char *name){
/* If the node is null, allocate memory for it,
* copy the name and set the internal nodes to null*/
if(cnode == NULL){
cnode = c_tree_alloc();
cnode->name = strdup(name);
cnode->left = cnode->right = NULL;
}
/* If initialised then add to the left node if it is lexographically
* less that the node above it else add it to the right node */
else{
if(strcmp(name, cnode->name) < 0)
cnode->left = add_to_c_tree(cnode->left,name);
else if(strcmp(name, cnode->name) > 0)
cnode->right = add_to_c_tree(cnode->right,name);
}
return cnode;
}
/* print_c_tree() : Print out binary tree */
void print_c_tree(ctree *cnode){
if (cnode != NULL) {
print_c_tree(cnode->left);
printf("%s\n",cnode->name);
print_c_tree(cnode->right);
}
}
/* return_c_tree() : return array of strings containing all values in binary tree */
void return_c_tree (ctree *cnode, char **array){
if (cnode != NULL) {
return_c_tree (cnode->left,array+c_inc);
c_tree_free(cnode->left);
*(array+c_inc++) = strdup(cnode->name);
// printf("arr+%d:%s\n", c_inc-1,*(array+(c_inc-1)));
return_c_tree (cnode->right,array+c_inc);
c_tree_free(cnode->right);
}
}
/* c_tree_alloc() : Allocates space for a tree node */
ctree *c_tree_alloc(void){
return (ctree *) malloc(sizeof(ctree));
}
/* c_tree_free() : Free's Memory */
void c_tree_free (ctree *cnode){
free(cnode);
}
Which I have been testing with bt.c:
#include "btree.h"
int main(void){
ctree *node = NULL; char *arr[100];
node = add_to_c_tree(node, "foo");
node = add_to_c_tree(node, "yoo");
node = add_to_c_tree(node, "doo");
node = add_to_c_tree(node, "woo");
node = add_to_c_tree(node, "aoo");
node = add_to_c_tree(node, "boo");
node = add_to_c_tree(node, "coo");
print_c_tree(node);
return_c_tree(node,arr);
for (int i = 0; i < 7; ++i)
{
printf("%d:%s ..\n",i, arr[i]);
}
return 0;
}
The reason for this question is that I have been having issues with the return_c_tree() function, which is meant to mimic the behaviour of K&R's print_c_tree() function except instead of recursively calling itself until a NULL ptr and printing out the name of the nodes in lexicographical order it is meant to add their names to an array of character ptrs and free the nodes memory.
However the output I get when run as above is:
aoo
boo
coo
doo
foo
woo
yoo
0:aoo ..
1:(null) ..
2:boo ..
3:doo ..
4:foo ..
5:coo ..
6:(null) ..
Which shows that the print function works fine but the return function obviously isn't.
The confusing thing is that if the call to printf() in return_c_tree() is uncommented this is the result:
aoo
boo
coo
doo
foo
woo
yoo
arr+0:aoo
arr+1:boo
arr+2:coo
arr+3:doo
arr+4:foo
arr+5:woo
arr+6:yoo
0:aoo ..
1:(null) ..
2:boo ..
3:doo ..
4:foo ..
5:coo ..
6:(null) ..
Which implies that it actually does add the strings in the right order.
Also I have tried it without the c_inc variable -> ie just incrementing array
before passing it to the right node which the produces the same results from the printf
in return_c_tree() but different from main:
arr+-1:aoo
arr+-1:boo
arr+-1:coo
arr+-1:doo
arr+-1:foo
arr+-1:woo
arr+-1:yoo
0:foo ..
1:yoo ..
2:coo ..
3:(null) ..
4:(null) ..
5:(null) ..
6:(null) ..
I'm rather confused, so If anyone can help I would appreciate it greatly. I'm sure I'm just incrementing it in the wrong place but I can't work out where.
I thought I had finally understood pointers but apparently not.
Best
P
Your problem is how you handle your pointer to array when you recursively call. This will fix your return_c_tree function:
void return_c_tree (ctree *cnode, char **array)
{
if (cnode != NULL) {
return_c_tree (cnode->left,array); // <--- CHANGED 2ND PARAM
c_tree_free(cnode->left);
*(array+c_inc++) = strdup(cnode->name);
return_c_tree (cnode->right,array); // <--- AGAIN, CHANGED 2ND PARAM
c_tree_free(cnode->right);
}
}
You're using a global variable c_inc to keep track of the current index into the array. However, when you recursively called return_c_tree, you passed in array+c_inc, but you did not offset c_inc to account for this. Basically, you double-counted c_inc each time.
While this solves your particular problem, there are some other problems with your code.
In general, using global variables is asking for trouble. There's no need to do it here. Pass c_inc as a parameter to return_c_tree.
Also, mixing global variables with recursion is especially prone to problems. You really want recursive routines to keep their state on the stack.
As a commenter pointed out, all of your code in btree.h should really be in btree.c. The point of header files is to define an interface, not for code.
(This is more stylistic) Your return_c_tree function is really two distinct functions: copy the elements of the tree (in order) into the array, and free the memory used by the tree. These two operations are conceptually distinct: there are times that you'll want to do one and not both. There can be compelling performance (or other) reasons to mix the two, but wait until you have some hard evidence.
I'm admittedly a straight-C newbie, but this has got me stumped. I'm working on a linked list implementation for practice, and I'm getting a segfault by simply adding a variable to the split_node function:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Node {
struct Node *child;
char *content;
};
void print_list(struct Node node);
void split_node(struct Node *node, int position);
int main() {
struct Node head, second, third;
head.content = "first";
second.content = "second";
third.content = "i'm third";
head.child = &second;
second.child = &third;
print_list(head);
split_node(&head, 3);
print_list(head);
return 0;
}
void print_list(struct Node node) {
printf("%s\n", node.content);
if(node.child) print_list(*node.child);
}
/*
Split node into two nodes, with the first position characters of the node's content remaining with node, and the remainder being copied to the new node. (It doesn't yet truncate the first node's string, but does do the copy.)
*/
void split_node(struct Node *node, int position) {
if(position >= strlen((*node).content)) return;
struct Node newNode;
newNode.child = (*node).child;
(*node).child = &newNode;
int length = (strlen((*node).content) - position);
newNode.content = malloc(sizeof(char) * (length + 1));
strncpy(newNode.content, (*node).content + sizeof(char) * position, length);
newNode.content[length] = '\0';
//int foo;
}
This code compiles (gcc -Wall -o list list.c) and runs fine:
$ ./list
first
second
i'm third
first
st
second
i'm third
But if I uncomment int foo at the end of split_node, compile and run, I get:
$ ./list
first
second
i'm third
first
st
Segmentation fault
gdb gives me this backtrace:
#0 0x91d6ae70 in strlen ()
#1 0x91dd3126 in puts ()
#2 0x00001f21 in print_list (node={child = 0xbcec815b, content = 0x8b000000 <Address 0x8b000000 out of bounds>}) at list.c:41
#3 0x00001f3c in print_list (node={child = 0x8fe0154b, content = 0x1ff6 "i'm third"}) at list.c:42
#4 0x00001f3c in print_list (node={child = 0xbffff568, content = 0x1fef "second"}) at list.c:42
#5 0x00001f3c in print_list (node={child = 0xbffff570, content = 0x1fe9 "first"}) at list.c:42
#6 0x00001ee0 in main () at list.c:33
Why would adding a variable definition cause a segfault? It appears to be smashing the content pointer of the newly created node. I'm confused; any help?
You need to dynamically allocate your nodes (using malloc).
As you have it, your new node is declared on the stack. When the split function returns, that new node is no longer valid memory.
Adding a variable causes a segfault because that variable changes the layout of the stack causing slightly different behavior when the function returns.
Try setting the Nodes child property to NULL, C doesn't automagically zero out memory so it looks like your may have garbage in child (or your could use calloc instead of malloc). SoapBox's answer is also correct.
Valgrind is a great tool to help find these types of problems. You can just do "valgrind myappname" from the command line and it will give you details on these types of errors.