void insert_tree(tree_t *tree, void *name, void *movie){
node_t *new;
new = malloc(sizeof(*new));
assert(new!=NULL);
strcpy(new->name, name);
strcpy(new->movie, movie);
new->left = new->right = NULL;
insert_node(&(tree->root), new);
}
typedef struct node node_t;
struct node{
char name[128];
char movie[422498];
node_t *left;
node_t *right;
};
typedef struct {
node_t *root;
} tree_t;
Code above inserts nodes to a binary search tree. I have been having thing trouble of overflowing while running the binary search tree algorithm with large files with more than 200000 lines.
With the
assert(new!=NULL)
statement, I found that the overflow is occurring in this part of the code.
I'm guessing that it is due to too many nodes being created?
How could I resolve this?
I haven't used realloc and malloc anywhere except in this part of the code.
All of the other codes also do not implement recursion they all use loops.
When the file is small enough it works perfectly with precision when it get larger it fails.
Try instead to make your nodes a bit more space efficient, having such a large array for a movie name (?) is a waste.
Instead declare the structure like this
struct node
{
char* name;
char* movie;
nde_t* left;
node_t* right;
};
then in your insert function:
void insert_tree(tree_t* tree, const char* name, const char* movie)
{
node_t *new = NULL;
// to catch unexpected arguments
assert( tree != NULL && name != NULL && movie != NULL );
new = malloc(sizeof(node_t)); // i prefer this style for sizeof
// don't use assert for runtime errors
if (new!=NULL)
{
new->name = strdup(name); // short form for malloc/strcpy
new->movie = strdup(movie);
new->left = new->right = NULL;
insert_node(&(tree->root), new);
}
else
{
fprintf(stderr, "out of memory");
exit(EXIT_FAILURE);
}
}
You should later free the memory for name and movie for each node.
Related
I tried to create a program to add elements to a linked list. The elements consist of name and age. But it fails to add without giving me any error. Could you please show me my mistake?
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAX 9999
struct data {
char name[MAX];
int age;
struct data *next;
};
void pushHead(struct data **head, struct data **tail, char name[], int age) {
struct data *node = (struct data *)malloc(sizeof(struct data));
strcpy(node->name, name);
node->age = age;
if (*head == NULL) {
node = *head;
node = *tail;
node->next = NULL;
} else {
node->next = *head;
*head = node;
}
}
void view(struct data *head) {
struct data *curr = head;
if (curr == NULL)
printf("No Data\n");
else {
while (curr != NULL) {
printf("%s(%d)\n", curr->name, curr->age);
curr = curr->next;
}
}
}
int main(int argc, char const *argv[]) {
struct data *head = NULL;
struct data *tail = NULL;
pushHead(&head, &tail, "Felix", 19);
view(head);
return 0;
}
Output : No Output
My code is working when I put the head on global scope (by changing all the functions to work globally), but when I try to put the head in main scope it doesn't work.
In pushHead(), you are doing:
node = *head;
node = *tail;
this end up assigning NULL to node pointer because *head and *tail both are NULL. Note that this is a memory leak as your program loose the memory reference which the node pointer is holding. Instead, you should do
*head = node;
*tail = node;
Some suggestions:
For storing name in the list node, you are taking buffer of size
9999 (MAX macro) which is (IMO) very large. I believe, a buffer
of size 256 is more than enough for this purpose. Or, you can also
have buffer of exact size required for storing name by allocating
the memory dynamically to it. For this , you have to take a char *
member instead of char array for name and allocate memory to it
dynamically based on size of name parameter of pushHead() and in
this case, you need to make sure to free it explicitly when deleting
the list nodes.
When using strcpy() to copy string, make sure that destination
buffer is large enough to contain the source string to avoid
overflows.
Follow good programming practice. Always check malloc return and
ensure to free the allocated memory once you are done with it.
Do not cast the malloc return.
To include standard library header files use <>, i.e. #include "stdio.h" -> #include <stdio.h>, check this.
I'm trying to create a function that does sorted insertion based on two variables, level and name. Apparently I'm having some logic and syntax errors.
My linked list structure:
struct node {
struct node *next;
int level;
char name;
};
My string compare function:
int compare(struct node *one, struct node *two)
{
return strcmp(one->name, two->name);
}
My insertion function:
void insert(struct node **head, const int level, const char name, int(*cmp)(struct node *l, struct node *r))
{
struct node *new =NULL;
/* Find the insertion point */
for (; *head; head = &(*head)->next)
{
if ((*head)->level > level) { // I think this is what is causing the issue
if (compare(*head, new) > 0)
break;
}
}
new = malloc(sizeof *new);
new->level = level;
new->name = name;
new->next = *head;
*head = new;
}
and this is the call stack:
insert(node **head, const int level, const char name, int(*)(node *, node *))
Your syntax error is this line:
return strcmp(one->name, two->name);
The function strcmp expect two char* (aka char pointers) but you give it two char.
The problem is... Do you want
char name;
or
char* name;
That is important in order to get compare right.
Further you need to rearrange your insert function so that you create the new node before using it. Something like:
void insert(struct node **head, const int level, const char name, int(*cmp)(struct node *l, struct node *r))
{
struct node *new =NULL;
// Create and initialize new....
new = malloc(sizeof *new);
new->level = level;
new->name = name;
/* Find the insertion point */
for (; *head; head = &(*head)->next)
{
if ((*head)->level > level) { // I think this is what is causing the issue
if (cmp(*head, new) > 0)
// ^^^ So that you can use it here
break;
}
}
new->next = *head;
*head = new;
}
You are passing a NULL value to the cmp function (?!? probably the correct function is int compare(...). Try to initialize the value of the new variable before to pass it to the function.
You declare node.name to be of type char, but your comparison function is written as if they were null-terminated arrays of char or pointers into such arrays (i.e. C strings). You appear to want this:
struct node {
struct node *next;
int level;
char *name;
};
or maybe this:
struct node {
struct node *next;
int level;
char name[MY_MAXIMUM_NAME_LENGTH_PLUS_ONE];
};
Furthermore, your insert() function passes a NULL pointer to the comparison function as its second argument, because you never allocate any memory for pointer new, and, of course, never assign values to the non-existent members. That doesn't even make sense. What do you think you're comparing to? You seem to want something like this:
struct node *new = malloc(sizeof *new);
if (!new) {
// allocation failure -- abort ...
}
new->level = level;
new->name = /* hmmmm ... */;
Of course, the problem with the type of your names crops up here, too.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 8 years ago.
Improve this question
I'm having a small issue here with my linked list.
I built a linked list with strings and it worked perfectly.
Now since i'm using strtok() to separate the string I need help on storing the struct separately but keeping them connected.
Hope i explained it well
for now here's what i've got:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dict_word *word;
typedef struct node *Node;
typedef struct double_linked_list *DLL;
struct dict_word
{
char words[100];
int year[10];
char eng_synonyms[100];
char heb_synonyms[100];
};
struct node
{
word data;
Node *next;
Node *previous;
};
struct double_linked_list
{
Node *head;
Node *last;
};
char *split(char words[100])
{
int i;
char *word=strtok(words, "_#_");
char *year=strtok(NULL, "_#_");; // assigning NULL for previousely where it left off
char *definition=strtok(NULL,"_#_");
char *synonyms=strtok(NULL,"_#_");
i=atoi(year);
printf("%s\n", word);
printf("%i\n",i);
printf("%s\n", definition);
printf("%s\n", synonyms);
return 0;
}
and this is my function to insert node by having only one string:
void insert_beginning(char words[99])
{
struct node *var, *temp;
var=(struct node *)malloc(sizeof(struct node)); //explination about the (node *)
strncpy(var->data, words,99);
if (head==NULL)
{
head=var;
head->previous=NULL;
head->next=NULL;
last=head;
}
else
{
temp=var;
temp->previous=NULL;
temp->next=head;
head->previous=temp;
head=temp;
}
}
I am a bit surprised to see plain C code used to handle such abstract data in 2014.
Nevertheless, I think you should separate the actual book data from the list.
strtok will modify your initial string (inserting '\0' at the end of each token). If you want to access the various bits strtok has split the string into, you must memorize all the pointers to the tokens (word, definition, etc).
So you should create a structure to hold all this together :
typedef struct {
const char * words;
int year;
const char * definition;
const char * synonyms;
} dict_word;
Now to create a new record, you will have to make a copy of the various tokens, just like you did previously in your linked list insertion.
But this time the copy will occur sooner, using the strdup function.
dict_word * create_record (char * raw) // raw record string
{
// allocate a new object
dict_word record = (dict_word *) malloc (sizeof (record));
assert (record != NULL);
/*
* sanity checks left out for concision,
* but you should make sure your input is properly formatted
*/
// populate the fields
record->word = strdup (strtok(raw , "_#_"));
record->year = atoi (strtok(NULL, "_#_"));
record->definition = strdup (strtok(NULL, "_#_"));
record->synomyms = strdup (strtok(NULL, "_#_"));
// done
return record;
}
You will need a cleanup function to free all the memory allocated during record creation:
void delete_record (record * r)
{
// first free all strings
free (r->word);
free (r->definition);
free (r->synomyms);
// then free the object
free (r);
}
Now for the list.
Instead of mixing up the code that handles the list with the one that cares about books, you can define the list as a more independent object:
typedef struct sNode {
struct sNode * next;
struct sNode * prev;
void * data; // this will point to the linked objects
} listNode;
typedef struct
{
listNode *head;
listNode *tail; // either first/last or head/tail, but keep it consistent :)
} List;
First you will need to initialize the list:
void List_init (List * l)
{
l->head = l->tail = NULL;
}
Then you will want to add elements to it
void List_put (List * list, void * data)
{
// allocate a node
listNode * node = (listNode *) malloc (sizeof (node));
assert (node != NULL);
// store data reference
node->data = data;
// insert the node at the end of list
node->prev = list->tail;
node->next = NULL;
list->tail = node;
if (list->head == NULL) list->head = node;
}
Finally, to use all this:
// create the list
List book_list;
List_init (&book_list);
/* ... */
// create the records
char * raw_record;
while ((raw_record = read_from_database ()) != DONE_READING)
{
List_put (book_list, create_record (raw_record));
}
/* ... */
// browse the records
listNode * node;
for (node = book_list->head; node != NULL; node = node->next)
{
dict_word * record = (dict_node *) node->data;
// do whatever you want with your record
}
All this being said and done, C is inadequate at best to handle this kind of high-level data.
You could write a very much more compact, reliable and efficient equivalent in a variety of more modern languages, starting with C++.
Now if you're just a student asked by an old geezer of a professor to do some dusty C homework and hoping to get it done for you by an old geezer of a StackOverflow contributor, well... it's your lucky day.
I've been stuck on the insertion part of the binary search tree. I get so confused with nested structs. The basic idea of this program is to create a bst that is able to hold names and double values which get stored by value (obviously).
Example: I want to store
Jane 3.14
John 3.233
Luke 6.4
Mike 1.4
so the bst would look like
3.14
/ \
1.4 3.233
\
6.4
however I'm having trouble with the insertHelper recursion portion of the code. The hash table is a bonus part of the code that I'll try implementing at a later time. Thank you for your help!
typedef struct name_val // holds name and value
{
char *name;
double value;
}NAME_VAL;
typedef struct node //binary search tree
{
NAME_VAL *nV;
struct node *left;
struct node *right;
}NODE;
struct tmap_struct //handle for bst and hashtable
{
int nL; //nodes on left
int nR; //nodes on right
NODE *root;
NODE **table;
};
int tmap_insert(TMAP_PTR hashTree, char * name, double val)
{
if(hashTree->root == NULL)
{
NODE *bst = (NODE *)malloc(sizeof(NODE));
NAME_VAL *root = (NAME_VAL *)malloc(sizeof(NAME_VAL));
bst->nV = root;
bst->nV->value = val;
strcpy(bst->nV->name, name);
hashTree->root = bst;
hashTree->nL = 0;
hashTree->nR = 0;
}
else
insertHelper(hashTree->root, val, name);
}
void insertHelper(TMAP_PTR hashTree, int val, char * name)
{
if(val < hashTree->root->nV->value)
{
if(hashTree->root->left == NULL)
{
hashTree->root->left = (NODE *)malloc(sizeof(NODE));
hashTree->root->left->nV = (NAME_VAL *) malloc(sizeof(NAME_VAL));
strcpy(hashTree->root->left->nV->name, name);
hashTree->root->nV->value = val;
(hashTree->nL)++;
}
else
insertHelper(hashTree->root->left, val, name);
}
else
{
if(hashTree->root->right == NULL)
{
hashTree->root->right = (NODE *)malloc(sizeof(NODE));
hashTree->root->right->nV = (NAME_VAL *)malloc(sizeof(NAME_VAL));
strcpy(hashTree->root->left->nV->name,name);
hashTree->root->nV->value = val;
(hashTree->nR)++;
}
else
insertHelper(hashTree->root->right, val, name);
}
}
I doubt this compiles. Is that the problem you're having?
From what I can see, you have declared insertHelper with the wrong type for its first parameter. It should take NODE* values, not TMAP_PTR values. That's because you always call it with nodes out of your tree.
So the first part of the function should look like this:
void insertHelper(NODE *node, int val, char * name)
{
if(val < node->nV->value)
{
if(node->left == NULL)
{
node->left = (NODE *)malloc(sizeof(NODE));
node->left->nV = (NAME_VAL *) malloc(sizeof(NAME_VAL));
strcpy(node->left->nV->name, name);
node->left->nV->value = val;
}
else
insertHelper(node->left, val, name);
}
//.....
Note that I removed the line:
(hashTree->nR)++;
It hardly even makes sense to track this information, unless maybe you do it at the node level.
But if you must, you could have insertHelper recursively return a positive or negative value to indicate what side it inserted on. But that doesn't makes sense. What is it on the right of? You may have inserted it on the right of a node that was in the left half of the tree.
If you store this information on each node, you can recursively update the node above as you return from insertHelper. Maybe that's what you were trying to do. Balanced tree implementations do something similar - AVL trees store the maximum depth of the tree at a node and use that to do branch rotations for rebalancing.
You'll have to adapt mine(It's almost standard C besides the unneeded template and class), but it's a similar algorithm: (I believe, I didn't look at any source for my own purposes.)
template<typename T>
class BST {
protected:
typedef struct node_t {
struct node_t * dir[2];
T data;
} node;
node * root;
void insert_node(node * active_node, T data){ //call with node *root;
int next = data < active_node->data ? 0 : 1;
if(active_node->dir[next] == NULL){
active_node->dir[next] = new node;
active_node->dir[next]->dir[0] = NULL;
active_node->dir[next]->dir[1] = NULL;
active_node->data = data;
} else
insert_node(active_node->dir[next], data);
}
public:
BST() : root(new node){root->dir[0] = NULL; root->dir[1] = NULL; root->data = 0;}
~BST(){}
}
in my assignment i have to create a binary tree where the user inputs the details.
the first thing the user does is enter 1 if they want to create a number tree or 2 if they want a word tree.
the type of tree they pick is the type it will be for the duration of the running of the program.
there are many functions (and a few structs) that must be written in order to complete the assignment.
my question is how can i write general functions that will work for both int and char?
for example if it is a number tree then the struct for node would include:
int key;
list_t* valueslist;
node* left;
node* right;
but if it was a word list than the struct would look the same except instead of int key it would be char key.
thanks in advance for any help!
The way you may go about it, is to define that data in the struct as a union like so:
struct _Node
{
...
union
{
char* c;
int i;
} data;
};
Than when user makes the choice, access the correct union member according to it.
EDIT
So, let's say the user picked a type, int for instance. And you wish to insert a new value into the tree. (I'll omit error checking fro brevity, but remember to check memory allocation succeeded).
struct _Node* newElem = allocNode();
if (get_user_elected_type() == INT)
newElem->data.i = user_input.i; // Your methods will also need to accept a union
This way has it's serious drawbacks (it's not easy to add a new type, for instance). And most of all it demonstrates how yucky generic programming can be in C. (Using void* can get just as yucky eventually).
There are few solutions to resolve this problem (what you are trying to do is called generic programming)
Use void * key, and fill it with the right data (this is
recommended, because is more generic, but it is also more complicated)
Use a union with 2 fields: an int and a char*
For a homework assignment, the simpler approach will be to use a union type for your data:
struct node {
union {
char *s
int i;
} data;
struct node *left;
struct node *right;
};
and create two sets of functions, one to manage integer values and the other to manage string values:
void insertIntNode(struct node *root, struct node *newNode)
{
if (newNode->data.i < root->data.i)
if (root->left != NULL)
insertIntNode(root->left, newNode);
else
root->left = newNode;
else
if (root->right != NULL)
insertIntNode(root->right, newNode);
else
root->right = newNode;
}
void insertWordNode(struct node *root, struct node *newNode)
{
if (strcmp(root->data.s, newNode->data.s) < 0)
if (root->left != NULL)
insertWordNode(root->left, newNode);
else
root->left = newNode;
else
if (root->right != NULL)
insertWordNode(root->right, newNode);
else
root->right = newNode;
}
bearing in mind you'll need to do some additional memory management for word data:
struct node *createWordNode(char *str)
{
struct node *r = malloc(sizeof *r);
if (r)
{
r->data.s = malloc(strlen(str) + 1);
if (r->s)
strcpy(r->data.s, str);
r->left = r->right = NULL;
}
return r;
}
void destroyWordNode(struct node **n)
{
free((*n)->data.s);
free(*n);
*n = NULL;
}
A more flexible approach is to use a void * to point to your data item, and then delegate all type-aware operations (allocation, assignment, comparison, display, etc.) to other functions which are hidden behind a set of function pointers. For example:
struct node {
void *data;
struct node *left;
struct node *right;
};
struct node *newNode(void *data, void *(*copy)(const void *))
{
struct node *n = malloc(sizeof *n);
if (n)
{
n->left = n->right = NULL;
n->data = copy(data);
}
return n;
}
void insert(struct node *root, struct node *newNode,
int (*compare)(const void *, const void *))
{
if (compare(newNode->data, root->data) < 0)
if (root->left != NULL)
insert(root->left, newNode, compare);
else
root->left = newNode;
else
if (root->right != NULL)
insert(root->right, newNode);
else
root->right = newNode;
}
In the examples above, the details of allocating memory for a node's data element and comparing two data elements are delegated to other functions, and pointers to those functions are passed as parameters to the list management functions. This way you wind up writing a single newNode and insert function, but one that's capable of handling arbitrary node data types. So, for your integer tree, you'd write functions like
void *copyInt(const void *data)
{
const int *src = data;
int *dst = malloc(sizeof *dst);
if (dst)
{
*dst = *src;
}
return dst;
}
int compareInt(const void *lhs, const void *rhs)
{
const int *ilhs = lhs;
const int *irhs = rhs;
if (*ilhs < *irhs)
return -1;
else if (*ilhs == *irhs)
return 0;
else
return 1;
}
then you'd call newNode and insert like
void insertIntValue(struct node *root, int value)
{
struct node *n = newNode(&value, copyInt);
if (n)
insert(root, n, compareInt);
}
The big disadvantage of this approach is that you throw type safety right out the window and into oncoming traffic; because we're using void * for everything. the compiler won't be able to catch type mismatches for us. There's nothing to stop you from passing the wrong copy or comparison function to the generic routines for a particular type.
Which brings us to our second disadvantage - you still need to write a type-aware interface (such as the insertIntValue function above) for each data type you want to support (insertFloatValue, insertStringValue, insertMyObnoxiousDataTypeValue, etc.) along with all of the delegates. Partly to avoid type-safety issues, and partly because our "generic" functions really aren't designed to be called directly. For example, the newNode function expects a pointer as the first parameter, meaning you can't write something like
struct node *n = newNode(10, copyInt);
or
struct node *n = newNode(3.14159, copyDouble);
IOW, you can't pass a literal as the first argument; you must pass the address of an object.
The third main disadvantage is you wind up doing a lot of memory management, which is a pain. You have to create copies of your inputs; otherwise, you wind up assigning the same pointer value (the one passed to newNode) to every node in your tree. Every malloc must have a matching free or you will wind up leaking a lot of memory. You have to be disciplined in how you allocate and deallocate your data items.
Building robust generic containers in C is, frankly, a massive pain in the ass. The only real reason to do it is so you can truly appreciate the value of templates in C++ and generics in Java and C#.