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.
Related
Disclaimer: I am new to C arrived here from other languages. What I observe breaks my head I do not even have a starting point to explain the observed behavior.
Scenario: Play around with a self-written stack implementation to get a feeling for the language and to compare different approaches.
Compiler in use:
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
Minimized code example:
#include <stdio.h>
struct stack_entry
{
struct stack_entry *next;
int *item;
};
struct stack
{
struct stack_entry *first;
};
void push_to_stack(struct stack *s_ptr, int *item)
{
struct stack_entry new_entry = {.next = s_ptr->first, .item = item};
s_ptr->first = &new_entry;
printf("item_address#push_to_stack %p\n", s_ptr->first->item);
}
void pop_from_stack(struct stack *s_ptr)
{
printf("item_address#pop_from_stack %p\n", s_ptr->first->item);
int* result = NULL;
}
int main()
{
printf("\n--stack test--\n");
struct stack s = {};
struct stack *s_ptr = &s;
int value = 42;
push_to_stack(s_ptr, &value);
printf("item_address#main: %p\n", s_ptr->first->item);
pop_from_stack(s_ptr);
return 0;
}
Unexpected output:
--stack test--
item_address#push_to_stack 0x7fffa759b67c
item_address#main: 0x7fffa759b67c
item_address#pop_from_stack 0x7fffa759b680
As one observes the item_address#pop_from_stack differs for some reason. I expect the output:
--stack test--
item_address#push_to_stack 0x7ffdc30ee19c
item_address#main: 0x7ffdc30ee19c
item_address#pop_from_stack 0x7ffdc30ee19c
To receive the expected output I need to remove the pointer declaration+initialization. In case I leave it in place the unexpected output occurs. So the following does the change:
// int* result = NULL;
But why? This totally puzzles me.
This will trigger undefined behavior later on:
struct stack_entry new_entry = {.next = s_ptr->first, .item = item};
s_ptr->first = &new_entry;
because new_entry will die when push_to_stack() ends.
But why? This totally puzzles me.
When compiled without optimizations, that line is likely making the compiler allocate space for result in the pop_from_stack() frame. Such a thing will make the behavior of the program change due to the undefined behavior shown above.
I want to create an array of struct pointers and set each pointer to null. Eventually I want to have the pointers in the array point to my struct. I believed I had the write code to this but I keep getting a seg fault.
Code:
//struct in my .h
struct bin{
double cac; // current available capacity
struct node *list //pointer to linked list... bin struct points to linked list struct
}
//main file
void main(){
struct bin *bArray[20];
struct bin *binTemp, *pTemp;
for(i=0;i<20;i++) bArray[i]= NULL;
}
I assumed this would create an array of bin pointers, but I'm getting a seg fault here. Shouldn't I be able to make all the pointers NULL regardless of what type of pointer they are?
Eventually I want to make these all point to bin structs and I thought I could do this without having to make the pointers NULL first so i tried:
for(i=0;i<20;i++){
binTemp = (struct bin *)malloc(sizeof(struct bin));
binTemp->cac = 1.0;
binTemp->list = NULL;
bArray[i] = binTemp;
}
Once again I got a seg fault. I have no idea whats going on here. I know seg faults means I'm trying to write to an illegal memory location which makes me think I would have to set the size of the array indexes with malloc. However,
for(i=0;i<20;i++) bArray[i]= malloc(sizeof(struct bin));
also gives me a seg fault. I have no idea what I'm doing wrong.
Actual code I ran:
//Header File
#ifndef hBin_h
#define hBin_h
#include <stdio.h> // stdio used for file io
#include <stdlib.h> // standard c library
#define MAX_S 20
//bin struc
struct bin {
double cac; //current available capacity
struct node *list; // pointer to linked list
};
//linked list node struct
struct node{
char *name; //name of item
double size; // weight of item
struct node *next; //pointer to next
};
//insert the new item into a node in its appropriate location using alphabetical ordering of item names
struct node *oInsert(char *item, double size, struct node *head);
//print the items of the list out along with the list’s capacity
void traverse(struct node *head);
// deallocate the nodes of the list
void destory(struct node *head);
//input info from file - name of object, weight of object
void input(FILE *inFile, char item[], double *weight);
#endif // hBin_h
#include "hBin.h"
void main(){
FILE *inFile;
char *item;
double *weight;
struct bin *bArray[20];
int i;
struct bin *binTemp, *pTemp;
inFile = fopen("run1.txt", "r"); //open file
printf("HERE1\n");
for(i=0;i<20;i++){
binTemp = (struct bin *)malloc(sizeof(struct bin));
binTemp->cac = 1.0;
binTemp->list = NULL;
bArray[i] = binTemp;
}
/*while(!feof(inFile)){
input(inFile, item, weight);
printf("%s, %.2f\n", item, *weight);
}*/
}
I used gdb (not totally sure what I'm doing here):
(gdb) run
Starting program: /home/Christopher/CSC362/Pass_F/Main
[New Thread 813244.0xc7590]
[New Thread 813244.0xc6ce0]
[New Thread 813244.0xc7320]
[New Thread 813244.0xc5994]
HERE1
0 [main] Main 813244 cygwin_exception::open_stackdumpfile: Dumping stack trace to Main.exe.stackdump
[Thread 813244.0xc7320 exited with code 35584]
[Thread 813244.0xc6ce0 exited with code 35584]
[Inferior 1 (process 813244) exited with code 0105400]
(gdb) where
No stack.
(gdb) for(i=0;i<20;i++){
binTemp->cac = 1.0;
binTemp->list = NULL;
bArray[i] = binTemp;
} /usr/src/debug/cygwin-2.2.1-1/winsup/cygwin/crt0.c: No such file or directory.
(gdb) binTemp = (struct bin *)malloc(sizeof(struct bin));
Undefined command: "binTemp". Try "help".
(gdb) binTemp->cac = 1.0;
Undefined command: "binTemp->cac". Try "help".
(gdb) binTemp->list = NULL;
Undefined command: "binTemp->list". Try "help".
(gdb) bArray[i] = binTemp;
Undefined command: "bArray". Try "help".
(gdb) } for(i=0;i<20;i++){
Undefined command: "". Try "help".
(gdb) binTemp = (struct bin *)malloc(sizeof(struct bin));
Undefined command: "binTemp". Try "help".
(gdb) binTemp->cac = 1.0;
Undefined command: "binTemp->cac". Try "help".
(gdb) binTemp->list = NULL;
Undefined command: "binTemp->list". Try "help".
(gdb) bArray[i] = binTemp;
Undefined command: "bArray". Try "help".
(gdb) } for(i=0;i<20;i++){
binTemp->cac = 1.0;
Undefined command: "". Try "help".
(gdb) binTemp = (struct bin *)malloc(sizeof(struct bin));
Undefined command: "binTemp". Try "help".
(gdb) binTemp->cac = 1.0;
Undefined command: "binTemp->cac". Try "help".
(gdb) binTemp->list = NULL;
Undefined command: "binTemp->list". Try "help".
(gdb) bArray[i] = binTemp;
Undefined command: "bArray". Try "help".
Reading your code you commented out, you pass the variable weight to the input function and right after dereference it in your call to printf. There is a major problem here, and that is that the variable weight is not initialized, and that passing it to a function passes it by value, which means that the variable is copied and the function only operates on the copy and not the original, meaning that the weight variable in your main function will still be uninitialized when you dereference it and that leads to undefined behavior and a probable crash.
If you intend to emulate pass by reference (you can only emulate since C doesn't have passing by reference), you should declare weight as a normal variable, and use the address-of operator when calling the function:
double weight;
...
input(inFile, item, &weight);
// ^
// |
// Note ampersand here
You have a similar problem with the item variable. It's uninitialized and doesn't point anywhere special. Using it in any way except to initialize it will lead to undefined behavior. And if you try to initialize it in the input function then you have the same problem as described above, and you need to pass a pointer to the pointer using the address-of operator.
If you don't initialize the item pointer in the input function, but use it like it's already pointing to some valid memory (using e.g. strcpy or similar function) then you also have undefined behavior.
The actual crash you experience might be totally unrelated to the problems I describe above, since you seem to be doing something involving linked lists, which of course means pointers, and pointers used wrongly will give you many chances for further undefined behaviors and crashes.
The first thing you should do is enable more warning when building, as the compiler is usually very good at finding suspect behavior that can lead to UB. You do that by adding e.g. the flags -Wall -Wextra -pedantic when building.
I am working on a C program which has a linked list. I need to remove the last element from the linked list and it is mostly working except when it hits particular part of my code it then has a segmentation fault.
The code that I have is as follows:
int clearOutboundLegFromList(callLogSearchOutboundStruct ** outboundLeg, int dataCol, int rowTargets)
{
//callLogSearchOutboundStruct *currentStruct = *outboundLeg;
//callLogSearchOutboundStruct *temp;
if (*outboundLeg == NULL)
{
return 0;
}
SL_DebugAll(DBG_ALWAYS, "DEBUG: Clearing outbound legs: DataCol: %i RowTargets: %i",
dataCol, rowTargets);
callLogSearchOutboundStruct *legToRemove = NULL;
callLogSearchOutboundStruct *last = NULL;
legToRemove = *outboundLeg;
while (legToRemove->nextLeg != NULL)
{
last = legToRemove;
legToRemove = legToRemove->nextLeg;
}
if (legToRemove->target != NULL)
{
free(legToRemove->target);
legToRemove->target = NULL;
}
if (legToRemove->cleardownCause)
{
free(legToRemove->cleardownCause);
legToRemove->cleardownCause = NULL;
}
free(legToRemove);
if (last != NULL)
{
last->nextLeg = NULL;
}
legToRemove = NULL;
}
It crashes on the line of free(legToRemove->target);.
In the core dump I have the following:
Program terminated with signal 11, Segmentation fault.
#0 0x00b01336 in _int_free () from /lib/libc.so.6
Missing separate debuginfos, use: debuginfo-install cyrus-sasl-lib-2.1.23-13.el6_3.1.i686 glibc-2.12-1.132.el6_5.2.i686 keyutils-libs-1.4-4.el6.i686 krb5-libs-1.10.3-15.el6_5.1.i686 libcom_err-1.41.12-18.el6.i686 libcurl-7.19.7-37.el6_5.3.i686 libidn-1.18-2.el6.i686 libselinux-2.0.94-5.3.el6_4.1.i686 libssh2-1.4.2-1.el6.i686 mysql-libs-5.1.73-3.el6_5.i686 nspr-4.9.2-1.el6.i686 nss-3.14.0.0-12.el6.i686 nss-softokn-freebl-3.12.9-11.el6.i686 nss-util-3.14.0.0-2.el6.i686 openldap-2.4.23-31.el6.i686 openssl-1.0.1e-16.el6_5.14.i686 zlib-1.2.3-29.el6.i686
(gdb) bt
#0 0x00b01336 in _int_free () from /lib/libc.so.6
#1 0x0805cd0b in clearOutboundLegFromList (outboundLeg=0xb5de7984, dataCol=9, rowTargets=11) at performreport.c:6731
#2 0x08058f33 in processDrilldownData (reportParameterArray=..., csvFile=0x8e3fc78, HandleDB=0xbfca7a14, resultReport=0x8e457a8,
If I print from the core dump legToRemove->target gdb outputs the following:
$1 = 0x99235d8 ""
Now that looks like its a properly allocated memory space, it just contains an empty string so I don't understand why this would cause a segfault.
You don't show how your struct looks like or how you add legs to your linked list, but you have an error in your removal function that occurs if you remove the last node: In that case, your list head should be set to NULL.
This special case is the reason to pass the list head as pointer to pointer to leg: The function must be able to update the head when the first node is removed. If you don't do that, the value of the head in the calling function will be the same and it will refer to memory that you have just freed. It is illegal to access such memory.
So, an updated version of your code could look like this:
void clearOutboundLegFromList(callLogSearchOutboundStruct **outboundLeg)
{
callLogSearchOutboundStruct *last = NULL;
legToRemove = *outboundLeg;
if (legToRemove == NULL) return;
while (legToRemove->nextLeg) {
last = legToRemove;
legToRemove = legToRemove->nextLeg;
}
free(legToRemove->target);
free(legToRemove->cleardownCause);
free(legToRemove);
if (last) {
last->nextLeg = NULL;
} else {
*outboundLeg = NULL;
}
}
You need the explicit assignment at the end, because once you have initialised legToRemove, you are operating only with that local pointer.
If you are feeling more confident with double indirections via pointers to pointers, you could iterate to the end without local variabes:
void clearOutboundLegFromList(callLogSearchOutboundStruct **outboundLeg)
{
if (*outboundLeg == NULL) return;
while (*outboundLeg) {
outboundLeg = &(*outboundLeg)->nextLeg;
}
free((*outboundLeg)->target);
free((*outboundLeg)->cleardownCause);
free(*outboundLeg);
*outboundLeg = NULL;
}
This will update the head pointer automatically when the first element is removed. The idea here ist that outboundLeg points to the head node at the beginning and to the previous node's nextLeg pointer on subsequent iterations. The additional indirection via (*outboundLeg) is more or less the same as accessing a node via the nextLeg member, except for the first node, in which you access the pointer through the head node pointer.
(Distraction: Your code is overly cautious when freeing the member pointers. It is legal to free a null pointer; this doesn't do anything, but means that you don't have to check for NULL in client code. Such a check might still be good practice, because many functions won't take null pointers. Setting the member pointers to NULL is a good idea if these pointers were still around for some time. But you are going to free the containing struct anyway soon. Setting the pointers to NULL is a bit like cleaning the bathroom just before you tear down the house. Setting legToRemove to NULL at the end of the function doesn't do anything: The pointer will go out of scope anyway. That's just an aside and retionale for my shorter code. Your checks aren't wrong and it is better to be cautious.)
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.
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.