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.
Related
I've seen this question in multiple posts but I have yet to find one that has a good explanation for me. Im trying to create a linked list but the struct nor the functions cant be called without getting the error cannot cast to a pointer. Its really bugging me. Any help would be appreciated on how to get this working right. Heres some of the code below thats the issue.
typedef struct node
{
void *data;
struct node *next;
} node;
node *head = NULL;
node* create(void *data, node *next)
{
node *new_node = (node*)malloc(sizeof(node));
if(new_node == NULL)
{
exit(0);
}else{
new_node->data = data;
new_node->next = next;
return new_node;
}
}
node* prepend(node *head, void *data)
{
node *new_node = create(data,head);
head = new_node;
return head;
}
void preload_adz(int adz_fd)
{
struct adz adz_info;
char adz_data[40];
char adz_text[38];
int adz_delay;
char adz_delayS[2];
read(adz_fd,adz_data,40);
strncpy(adz_text,adz_data + 2,40-2);
sprintf(adz_delayS, "%c%c",adz_data[0],adz_data[1]);
adz_delay = atoi(adz_delayS);
adz_info.delay = adz_delay;
strncpy(adz_info.text,adz_text,38);
head = prepend(head, (void*)adz_info); //<---This line throws the error
while(read(adz_fd,adz_data,40) > 0)
{
}
}
struct adz adz_info;
...
head = prepend(head, (void*)adz_info); //<---This line throws the error
The problem here is adz_info is not a pointer, it's the actual struct on the stack. Passing adz_info into a function will copy the struct.
You need a pointer to that struct. Use & to get its address. Once you have the pointer, you don't need to cast it to void pointer, that cast is automatic.
head = prepend(head, &adz_info);
Note that casting is a bookkeeping thing. Casting to void * doesn't turn a struct into a pointer, it says "compiler, ignore the declared type of this variable and just trust me that this is a void pointer".
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.
I'm trying to create a small list for each element in a main list. I have the main list working fine but I don't know how to access and add elements to the small list.
struct smallList
{
char data;
struct smallList *next;
};
struct bigList
{
char data;
struct bigList *next;
struct smallList *head;
} *root;
When I add stuff to the main list, I declare for each new node:
newNode->head = NULL;
I use this function to get the current pointer to an element in main list:
struct bigList *pointer = getPointer(root, value);
Then, to add stuff to its smallList| using that pointer. I pass alongpointer->head` to this function. And its not working.
insert(pointer->head, value)
As WhozCraig suggests, you can resolve your problem using a pointer to a pointer. Something like this:
void insert(struct smallList **head, char value)
{
*head = newSmallList(value, *head);
}
newSmallList would be something like:
struct smallList *newSmallList(char value, struct smallList *rest)
{
struct smallList *result = malloc(sizeof(struct smallList));
result->next = rest;
result->data = value;
return result;
}
The problem with your current setup is that you are passing the value of the pointer->head field (which happens to be null) to the function, when what you want is to alter what is stored in the field. Here is a program using integers that illustrates a similar mistake:
void setFive(int i)
{
i = 5;
}
int main(void)
{
int myInt = 7;
setFive(myInt);
printf("%d\n", myInt); /* still 7! */
return 0;
}
I have this basic Linked List structure:
struct node
{
char *name;
float salary;
struct node *nextNode;
};
struct list
{
struct node *firstNode;
};
This is my insert function:
void insert(struct list *pList, char *newName, float newSalary)
{
struct node *newNode;
newNode = (struct node *)malloc(sizeof(struct node));
newNode->salary = newSalary;
newNode->name = newName;
if (pList->firstNode == NULL)
{
pList->firstNode = newNode;
newNode->nextNode = NULL;
}
else
{
struct node *pos = pList->firstNode;
for(; pos->nextNode; pos = pos->nextNode);
pos->nextNode = newNode;
newNode->nextNode = NULL;
}
}
This is my main():
int main(void)
{
struct list lst;
struct list *plst = &lst;
createList(plst); //initializes the list
char name1[] = "John";
char name2[] = "Thomas";
char name3[] = "Albert";
insert(plst, name1, 1000);
insert(plst, name2, 2000);
insert(plst, name3, 3000);
}
Everything works great except for the transfer of the char array. I thought the best way to pass a char array would be by passing a pointer to the first char in the char array, but I can't see what I did wrong.
Also, would it be better to first create a new node and then pass a pointer to this node to the insert function? It's similar, but perhaps it is more acceptable?
newNode->name = newName;
This is not the right way to copy c-strings. use strcpy or strncpy:
strcpy(newNode->name,newName);
As #Pablo pointed out you didn't allocate memory for string, so first allocate and then copy:
newNode->name = malloc(strlen(newName)+1);
strcpy(newNode->name,newName);
The code seems fine to me. But what do you mean by works great except for the transfer of the char array? Do you get an error, segfault, something unexpected and if so what?
i dont know why the list returned is NULL, this is the code:
In my List.h
struct nodo_ {
char* dato;
struct nodo_ *next;
};
struct nodo_ *Lista;
/*Def list */
void createList(struct nodo_ **Lista);
in my main.c
struct nodo_ *Lista;
int main(){
createList(Lista);
while(Lista != NULL){
printf("The date is %s\n ",Lista->dato); //Error here now
Lisa = Lista->next;
}
return 0 ;
}
in my List.c im create the List :
void createList(struct nodo_ *Lista){
struct nodo_ *Aux_List = list_D;
aux_List = malloc(sizeof(struct nodo_));
char* path_a = "Hello";
char* path_B = "Minasan";
/* Store */
aux_List->dato = path_a;
aux_List = Aux_List->next;
aux_List = malloc(sizeof(struct nodo_));
aux_List->dato = path_b;
aux_List->next = NULL;
}
Thanks.
That pointer is being passed by value, i.e., a copy is made. If you wish to initialize the pointer to a completely new value then you must use another level of indirection (i.e., a nodo_**).
On a side note, typedefing pointer types is almost always a bad idea unless the type is truly opaque (which yours is not). One reason for this "rule" is evident when you consider another bug in your code:
auxList = (Lista*)malloc(sizeof(Lista));
You're allocating space for a pointer to noda_, not enough for a noda_ object. Also, don't cast the return value of malloc in C. It is redundant as a void* is safely and implicitly converted to any other pointer type and, if you forget to include stdlib.h, malloc will be assumed to be a function which returns int, and the cast hides the error. (only applies to compilers which implement C89 or an older version)
EDIT:
To initialize a pointer argument within a function:
void init(struct node **n) {
if(n)
*n = malloc(sizeof(struct node));
}
int main() {
struct node *n;
init(&n);
}
Short answer to your actual question before I dig into the code:
... why the list returned is NULL ...
There is no returned list, you neither use return to pass a result, nor set the value of an out parameter.
In your edited code:
void createList(struct nodo_ **Lista){
struct nodo_ *Aux_List = list_D;
aux_List = malloc(sizeof(struct nodo_));
you first set Aux_List to the current value of Lista, which you know isn't initialized yet, because you're trying to initialize it. Then you discard that value, overwriting aux_List with a new address returned by malloc. You never store anything into *Lista, which would be the only way for this function to work as declared.
As Ed suggests, your typedef is hiding lots of useful information from you, so let's expand it out
struct nodo {
char* dato;
struct nodo *next;
};
/*Def list */
void createList(struct nodo* list_D);
Now, you can see this createList is wrong: you can pass in the head node of a list (which is no use to it anyway), but there is no way for it to return a newly-allocated list to the caller.
Frankly your createList isn't a useful primitive anyway, so I'm going to start with a sensible foundation first:
struct nodo *alloc_nodo(char *dato, struct nodo *next)
{
struct nodo *n = malloc(sizeof(*n));
n->dato = dato;
n->next = next;
return n;
}
Now, before we re-write your createList using this, let's see what it does now:
void createList(struct nodo *list_D)
{
struct nodo *aux_List = list_D;
aux_List = malloc(sizeof(struct nodo_));
/* ^ so, we take the input argument and immediately discard it */
char* path_a = "Hello";
char* path_B = "Minasan";
/* Store */
aux_List->dato = path_a;
aux_List = Aux_List->next;
/* ^ note that we haven't initialized aux_List->next yet,
so this is a random pointer value */
aux_List = malloc(sizeof(struct nodo_));
/* again, we set aux_List to something,
but immediately overwrite and discard it */
aux_List->dato = path_b;
aux_List->next = NULL;
}
So, it ignores its input, returns no output, and leaks two partially-initialized nodes which aren't connected to each other. I believe you wanted to achieve something more like this:
struct nodo* create_my_list()
{
struct nodo *tail = alloc_nodo("Minasan", NULL);
/* the end (tail) of the linked list has a NULL next pointer */
struct nodo *head = alloc_nodo("Hello", tail);
/* the head of the linked list points to the next node */
return head;
/* like a snake, you hold a singly-linked list by the head */
}
If we write main to use this function now, it looks like:
int main()
{
struct nodo *head = create_my_list();
struct nodo *n;
for (n = head; n != NULL; n = n->next)
{
printf("The date is %s\n ", n->dato);
}
}