I am trying to make a function that copies a node. I am trying to have the program on error or NULL return NULL, I can only have one return statement
I have the following code and I am not sure what else to do from here.. Any tips/advice I would greatly appreciate
Node *cpnode(Node *curNode)
{
if (curNode == NULL) return NULL;
Node *result = malloc(sizeof *result);
result -> value = curNode -> value;
result -> next = cpnode(curNode -> next;
return(result);
}
EDIT:
I have edited my code when trying to compile I am getting errors such as
Node has no member named 'value' and 'next'. Why is that?
Also I know I can easily return NULL on my if statement and at the end return with my result but how could I just have only one return statement with NULL on error?
To define my Node would I have to do something like this:
Node *cpnode(Node *curNode)
{
struct Node{
*result;
*value;
*next;
}
if (curNode == NULL) return NULL;
Node *result = malloc(sizeof *result);
result -> value = curNode -> value;
result -> next = cpnode(curNode -> next;
return(result);
}
There are several issues with your code: your Node structure isn't properly defined and you're using it as a type which you didn't typedef; your text talks about copying a node but your code copies a linked list of nodes; result doesn't seem like it should be part of the Node structure; your code isn't syntactically correct (e.g. missing paren).
Here's a rework of your code into something that compiles and runs. Since you didn't specify the type for value, I'm assuming it's a string below but you can change that to whatever you want:
#include <stdlib.h>
#include <stdio.h>
typedef struct Node
{
char *value;
struct Node *next;
} Node;
Node *copyNodes(Node *currentNode)
{
Node *result = NULL;
if (currentNode != NULL)
{
if ((result = malloc(sizeof *result)) != NULL)
{
result->value = currentNode->value;
result->next = copyNodes(currentNode->next);
}
}
return result;
}
void freeNodes(Node *currentNode)
{
if (currentNode != NULL)
{
if (currentNode->next != NULL)
{
freeNodes(currentNode->next);
currentNode->next = NULL;
}
}
free(currentNode);
}
int main()
{
Node a, b;
b.value = "last";
b.next = NULL;
a.value = "first";
a.next = &b;
Node *c = copyNodes(&a);
printf("%s\n", c->next->value);
freeNodes(c);
return 0;
}
If we make a copy of all the nodes using malloc(), then when finished, we need to free all the copies in a similar fashion to how they were created. That's what the function freeNodes() does.
Related
Is this a right way to do a linked list ? I am having a problem in a big school project and now i want to make sure that this is true.
void addnode(int a){
struct house* tmp = houses[i].next;
while (tmp != NULL) {
tmp = tmp->next;
}
tmp = (struct house*)malloc(sizeof(struct house));
tmp->id=a;
tmp->next=NULL;
}
i figured out that the error can be in other parts of the code. Now i will share the parts i suspect i hope you can help me.
houses[i] is an array of linked lists. if houses[i].id==-1 it is empty
struct house get_house_byid(int id) {
for (int i = 0; i < 1000; i++) {
if (houses[i].id != -1) {
if (houses[i].id == id) {
return houses[i];
}
if (houses[i].next != NULL) {
struct house* tmp = houses[i].next;
while (tmp != NULL) {
if (tmp->id == id) {
return *tmp;
}
tmp = tmp->next;
}
}
}
}
struct house housep;
housep.id = -1;
return housep;//if it cant find that id it returns housep
}
There may be other issues with your code that is not shown, but there are issues with addnode:
addnode does not set the head of the list (i.e. houses[i].next).
Thus, the newly added node is never connected to anything [and is a memory leak].
Ignoring the [obvious] typo/syntax error: void addnode{int a} instead of void addnode(int a).
The loop on tmp discards the pointer to the tail of the list. We need a separate variable (e.g. prev).
Note that i is global. That's fine, but the function would be cleaner if i was an argument to addnode instead.
Don't cast the return of malloc: Do I cast the result of malloc?
Here's is some refactored code. It is annotated:
void
addnode(int i,int a)
{
struct house *tmp;
struct house *prev;
// find the tail of the list
prev = NULL;
for (tmp = houses[i].next; tmp != NULL; tmp = tmp->next)
prev = tmp;
// allocate the new node
tmp = malloc(sizeof(*tmp));
tmp->id = a;
tmp->next = NULL;
// append to the tail of the [non-empty] list
if (prev != NULL)
prev->next = tmp;
// add to front of the empty list
else
houses[i].next = tmp;
}
I'm writing a simple C program to manage a linked list defined as follow:
typedef struct node {
int value;
struct node *next;
} *List;
I reviewed the code and it seems okay but when printing results something is not working well.
My main, with problems on comments:
int main(void) {
List n = list_create(1);
insert(n, 2);
insert(n, 3);
insert(n, 5);
insert(n, 4);
//something here does not work properly. It produces the following output:
//Value: 1
//Value: 2
//Value: 3
//Value: 4
//where is value 5?
print_list(n);
delete(n, 3);
print_list(n);
return 0;
}
I don't know where am I destroying list structure. These are my functions, to debug, if you are too kind.
List list_create(int value) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = NULL;
return new;
}
List new_node(int value, List next_node) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = next_node;
return new;
}
void print_list(List l) {
List *aux;
for (aux = &l; (*aux) != NULL; aux = &((*aux)->next))
printf("Valor: %d\n", (*aux)->value);
}
void insert(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value > value) {
List tmp = *p;
List new = new_node(value, tmp);
*p = new;
break;
}
*p = new_node(value, NULL);
}
void delete(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value == value) {
List del = (*p);
(*p) = ((*p)->next);
free(del);
break;
}
}
This code has (at least) two bugs:
The line
if ((*p)->value > value){
means that if you start the list with 1 as the first value and then try to insert 2,3,4..., the body of the 'if' statement never runs, so nothing ever gets inserted.
If you insert a value below the starting value, you have to modify the list pointer itself. However, as #EOF alluded, you are trying to modify a value passed to a function by taking its address. This won't work. &l does not give you the address of the List you passed, it gives you the address of the local copy on insert()'s stack. You are better off modifying the values of first element of the list 'in place'. If you really want to make the List parameter mutable, you'll need to pass it as a List *, and call the function with the address of the list (e.g. insert(&n,2); ) Your delete() function suffers from the same problem - try deleting the first element of the list.
Try this for your insert function:
void insert(List l, int value)
{
List p;
// Find end of list or highest item less than value
for(p = l; p->next != NULL && p->next->value < value; p = p->next);
if (p->value >= value) {
// Over-write p with new value, and insert p as a new one after.
// This saves having to modify l itself.
int tmpval = p->value;
p->value = value;
p->next = new_node(tmpval, p->next);
} else {
// Insert new item after p
p->next = new_node(value, p->next);
}
}
A comment: it is possible the way you are using pointers is not helping the debugging process.
For example, your print_list() could be re-written like this:
void print_list(List l){
List aux;
for(aux = l; aux != NULL; aux = aux->next)
printf("Valor: %d\n", aux->value);
}
and still behave the same. It is generally good practice not to 'hide' the pointer-like nature of a pointer by including a '*' in the typedef.
For example, if you define your list like this:
typedef struct node{
int value;
struct node *next;
} List
And pass it to functions like this:
my_func(List *l, ...)
then it'll make some of these issues more apparent. Hope this helps.
There are many problems in your code:
Hiding pointers behind typedefs is a bad idea, it leads to confusion for both the programmer and the reader.
You must decide whether the initial node is a dummy node or if the empty list is simply a NULL pointer. The latter is much simpler to handle but you must pass the address of the head node to insert and delete so they can change the head node.
printlist does not need an indirect pointer, especially starting from the address of the pointer passed as an argument. Simplify by using the Node pointer directly.
in insert you correctly insert the new node before the next higher node but you should then return from the function. Instead, you break out of the switch and the code for appending is executed, replacing the inserted node with a new node with the same value and a NULL next pointer. This is the reason 5 gets removed and lost when you insert 4. Furthermore, you should pass the address of the head node so a node can be inserted before the first.
delete starts from the address of the argument. It cannot delete the head node because the pointer in the caller space does not get updated. You should pass the address of the head node.
You should avoid using C++ keywords such as new and delete in C code: while not illegal, it confuses readers used to C++, confuses the syntax highlighter and prevents compilation by C++ compilers.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node *next;
} Node;
Node *new_node(int value, Node *next_node) {
Node *node = malloc(sizeof(*node));
if (node != NULL) {
node->value = value;
node->next = next_node;
}
return node;
}
void print_list(Node *list) {
for (; list != NULL; list = list->next)
printf("Valor: %d\n", list->value);
}
void insert_node(Node **p, int value) {
while ((*p) != NULL && (*p)->value < value)
p = &(*p)->next;
*p = new_node(value, *p);
}
void delete_node(Node **p, int value) {
while (*p != NULL) {
if ((*p)->value == value) {
Node *found = *p;
*p = (*p)->next;
free(found);
// return unless delete() is supposed to remove all occurrences
return;
} else {
p = &(*p)->next;
}
}
}
int main(void) {
Node *n = NULL;
insert_node(&n, 2);
insert_node(&n, 3);
insert_node(&n, 5);
insert_node(&n, 4);
insert_node(&n, 1);
print_list(n);
delete_node(&n, 3);
print_list(n);
delete_node(&n, 1);
print_list(n);
return 0;
}
I cannot figure out how to run this correctly, gives segmentation error. A piece of code is below. Can you look at head too , i am not sure if it is right way of initialising head to null in another file , it is run as follows :
Table tb ;
tb= initialise_table (table_size);
tb = insert(text_words,tb);
//these 3 typedef declarations are in a "some.h" file
typedef struct node * tree_ptr;
typedef char* Key_Type;
typedef struct table* Table;
struct node {
Key_Type element;
tree_ptr left;
tree_ptr right;
};
struct table {
tree_ptr head;
};
Table init_table() {
Table head = NULL;
}
Table insert(Key_Type key ,Table temp ) {
tree_ptr t = (tree_ptr)malloc(sizeof(tree_ptr));
t->element = key;
// t->left = t->right = NULL;
if (temp->head==NULL) {
temp = (Table)malloc (sizeof (Table));
temp->head = t;
printf("empty tree ");
}
else {
temp = insert(t->element,temp);
printf("inserted into ");
}
return temp;
printf("wowo!");
}
The primary issue is in the code which, you say, is used to invoke the functions:
Table tb;
tb = insert(text_words, tb);
You have an uninitialized pointer, tb, which you pass to the function. Inside the function, you have:
Table insert(Key_Type key, Table temp)
{
tree_ptr t = (tree_ptr)malloc(sizeof(*t)); // Fixed size
t->element = key;
// t->left = t->right = NULL;
if (temp->head==NULL)
{
You're therefore accessing (dereferencing) the undefined pointer, and your program is crashing.
You should, I assume, be initializing your table with table_init(), but that function is actually no help whatsoever. It defines and initializes a local variable, but doesn't return anything even though it promises to do so.
Please see Is it a good idea to typedef pointers? The short answer is 'No, it usually isn't a good idea'.
You still have problems even if you fix the calling code like this (a necessary but not sufficient step):
Table tb = NULL;
tb = insert(text_words, tb);
or maybe:
Table tb = init_table();
tb = insert(text_words, tb);
but you need a seriously upgraded version of init_table(), such as:
Table init_table(void)
{
Table root = malloc(sizeof(*head));
root->head = NULL;
return root;
}
Your code in insert() needs to ensure that it does not dereference a null pointer (instead of an indeterminate pointer).
Table insert(Key_Type key, Table root)
{
tree_ptr t = (tree_ptr)malloc(sizeof(*t)); // Fixed size
t->element = key;
t->left = t->right = NULL;
if (root == NULL)
{
root = init_table();
root->head = t;
}
else
{
…
}
return root;
}
Given the Key_Type is a char * in disguise, you may need to review how you save the keys in the tree structure; you may need to use strdup() to copy the data. It is impossible to say for sure without seeing how you are managing the strings that you pass to the insert() function. It could be OK to just save the pointer if the calling code ensures that a new pointer is passed each time. OTOH, if the same pointer is passed each time, you definitely need to copy the data, and using strdup() is a sensible way of doing that. Note that strdup() is standard on POSIX; it is not part of standard C.
Here's one major problem:
tree_ptr t = (tree_ptr) malloc(sizeof(tree_ptr));
should be:
tree_ptr t = (tree_ptr) malloc(sizeof(struct node));
Your code doesn't actually do any binary search. Indeed, it just infinitely recurses creating new nodes. Try something more like this:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct Node
{
char *element;
struct Node *left;
struct Node *right;
} Node;
typedef struct
{
Node *root;
size_t size;
} Tree;
void Tree_init(Tree *t);
Node *Tree_insert(Tree *t, const char *key);
void Tree_insert_r(Node *subtree, Node *n, size_t size);
void Tree_pre_order_r(Node *subtree);
void Tree_init(Tree *t)
{
t->root = NULL;
t->size = 0;
}
Node *Tree_insert(Tree *t, const char *key)
{
Node *ret = (Node*) malloc(sizeof(Node));
if (ret)
{
ret->left = ret->right = NULL;
if ((ret->element = strdup(key))) /* make a copy of key */
{
if (NULL != t->root)
Tree_insert_r(t->root, ret, t->size);
else
t->root = ret;
++t->size;
}
else
{
free(ret);
ret = NULL;
}
}
return ret;
}
void Tree_insert_r(Node *subtree, Node *n, size_t size)
{
int cmp = strcmp(n->element, subtree->element);
if (cmp < 0 || (cmp == 0 && size % 2 == 0))
{
if (NULL != subtree->left)
subtree = subtree->left;
else
{
subtree->left = n;
return;
}
}
else
{
if (NULL != subtree->right)
subtree = subtree->right;
else
{
subtree->right = n;
return;
}
}
Tree_insert_r(subtree, n, size);
}
void Tree_pre_order_r(Node *subtree)
{
if (NULL == subtree)
return;
fprintf(stdout, "'%s'\n", subtree->element);
Tree_pre_order_r(subtree->left);
Tree_pre_order_r(subtree->right);
}
int main()
{
Tree t;
Tree_init(&t);
Tree_insert(&t, "Hello");
Tree_insert(&t, "World!");
Tree_insert(&t, "etc.");
Tree_pre_order(t.root);
return 0;
}
I've been trying to teach myself c over spring break and it's been a lot more challenging than i had anticipated! I've made some good progress, however i seem to have hit a snag. I've been writing my own implementation of a doubly linked list. After about eight hours of plugging along, I've got what seems to be a fairly coherent program. The compiler is giving me the all clear ahead, and i've successfully built the project multiple times. Now, i started programming in java; so to my mind the aforementioned assurances constitute an ironclad guarantee of success. However C seems to c things differently (pardon the pun)! When i attempt to run my program, i get a 'segfault' run-time error. I've spent some time reading up on this error, and (as im sure i'm about to be informed) it's an issue of memory mis-allocation. I've tried to debug, but no matter where i set my breakpoints i cant seem to preempt the error. I'm in a bit of a quandry, and i'd really appreciate any insights y'all might have to offer me! I apologize for the monolith of text i've just scrawled out... and i'll try to keep the post script brief. Here's a rough outline of my setup:
NetBeans 6.8 IDE with Cygwin environment
Currently running windows 7 x64
I'll post my code below, but certainly don't feel obligated to go sifting through it. What i'm really hoping for is a few suggestions on how to handle segfaults in general. I get the feeling i'll be seeing them a lot, and i'd like to develop a strategy for troubleshooting this particular issue.
Thanks in advance! without you guys i'd be up a serious creek!
main.c
#include <stdlib.h>
#include <stdbool.h>
#include"dll.h"
int main(int argc, char** argv) {
VECT coord1;
coord1->x = 0.0012345;
coord1->y = 0.012345;
coord1->z = 0.12345;
LIST coords = init_list();
list_add(coords, coord1);
return (EXIT_SUCCESS);
}
dll.c (doubley linked list source file)
#include "dll.h"
#include <stdlib.h>
#include <string.h>
#include<stdbool.h>
#include"dll.h"
LIST init_list() {
LIST list = (LIST) malloc(sizeof (struct list));
list->length = 0;
list->first = NULL;
list->last = NULL;
list->destructor = free;
return list;
}
LIST_ITR list_iterator(LIST list, bool from_front) {
LIST_ITR iter = (LIST_ITR) malloc(sizeof (struct list_itr));
if (from_front) {
iter->current = list->first;
} else if (!from_front) {
iter->current = list->last;
} else return NULL;
iter->started = 0;
return iter;
}
void list_add(LIST list, VECT coords) {
NODE node = (NODE) malloc(sizeof (struct node));
node->coord_vector = coords;
if (list->first == NULL) {
node->prev = NULL;
node->next = NULL;
list->first = node;
list->last = node;
} else {
list->last->next = node;
node->prev = list->last;
node->next = NULL;
list->last = node;
}
list->length++;
}
VECT list_itr_current(LIST_ITR iter) {
if (iter->started && iter->current != NULL)
return iter->current->coord_vector;
else {
return NULL;
}
}
VECT list_itr_next(LIST_ITR iter) {
if (!iter->started && iter->current != NULL) {
iter->started = 1;
return iter->current->coord_vector;
}
if (iter->current != NULL) {
iter->current = iter->current->next;
return list_itr_current(iter);
}
return NULL;
}
VECT list_prev(LIST_ITR iter) {
if (!iter->started && iter->current != NULL) {
iter->started = 1;
return iter->current->coord_vector;
}
if (iter->current != NULL) {
iter->current = iter->current->prev;
return list_itr_current(iter);
}
return NULL;
}
VECT list_get_first(LIST list) {
return list->first->coord_vector;
}
VECT list_get_last(LIST list) {
return list->last->coord_vector;
}
VECT list_pop(LIST list) {
NODE last = list->last;
if (last == NULL) return NULL;
if (list->first == list->last) {
list->first = NULL;
list->last = NULL;
} else {
list->last = last->prev;
last->prev->next = NULL;
}
VECT data = last->coord_vector;
free(last);
list->length--;
return data;
}
VECT list_poll(LIST list) {
NODE first = list->first;
if (first == NULL)
return NULL;
if (list->first == list->last) {
list->first = NULL;
list->last = NULL;
} else {
list->first = first->next;
first->next->prev = NULL;
}
VECT data = first->coord_vector;
free(first);
list->length--;
return data;
}
void list_remove(LIST list, bool from_front) {
VECT data;
if (from_front)
data = list_poll(list);
else if (!from_front)
data = list_pop(list);
else return;
list->destructor(data);
}
void destroy_list(LIST list) {
NODE current = list->first;
NODE next;
while (current != NULL) {
next = current->next;
list->destructor(current->coord_vector);
free(current);
current = next;
}
free(list);
}
dll.h (doubley linked list header file)
#include<stdbool.h>
#ifndef _DLL_H
#define _DLL_H
#ifdef __cplusplus
extern "C" {
#endif
/* A C implementation of a doubly-linked list. Contains void pointer values.
Can be used as a LIFO stack of FIFO queue. */
#define FRONT 0
#define BACK 1
struct vector{
double x;
double y;
double z;
};
typedef struct vector* VECT;
struct node{
VECT coord_vector;
struct node* next;
struct node* prev;
};
typedef struct node* NODE;
struct list{
int length;
NODE first;
NODE last;
void (*destructor)(void*);
};
typedef struct list * LIST;
struct list_itr{
NODE current;
char started;
};
typedef struct list_itr * LIST_ITR;
//Initializes the list
LIST init_list();
//initializes the list iterator
LIST_ITR list_iterator(LIST list, bool from_front);
//append element to end
void list_add(LIST list, VECT coords);
//Gets the data stored in the first item of the list or NULL if the list is empty
VECT list_get_first(LIST list);
//Gets the data stored in the last item of the list or NULL if the list is empty
VECT list_get_last(LIST list);
//LIFO pop: remove element and return data
VECT list_pop(LIST list);
//FIFO poll: remove element and return data
VECT list_poll(LIST list);
//Deletes element and frees memory
void list_remove(LIST list, bool from_front);
//Delete list and free all memory
void destroy_list(LIST list);
//returns the data of the element pointed to by current
VECT list_itr_current(LIST_ITR list_itr);
//Increments the index of current by 1 and returns the data stored there
VECT list_itr_next(LIST_ITR list_itr);
//Decrements the index of current by 1 and returns the data stored there
VECT list_prev(LIST_ITR list_itr);
#ifdef __cplusplus
}
#endif
#endif /* _DLL_H */
You should build your code with -Wall flag to compiler. At compile time it will then print:
main.c:9:15: warning: ‘coord1’ is used uninitialized in this function [-Wuninitialized]
This points you to the problem.
coord1 is a pointer type, that you assign to, but coord1 has no memory backing it until it is initialized. In the following snippet coord1 is initialized by allocating memory to store it's components. This gets rid of the segfault.
VECT coord1 = NULL;
coord1 = (VECT)malloc(sizeof(struct vector));
if (NULL == coord1)
{
fprintf(stderr, "Out of memory!\n");
exit(1);
}
coord1->x = 0.0012345;
coord1->y = 0.012345;
coord1->z = 0.12345;
In general, segfaults happen when a program accesses memory that the operating system has not allocated to it. Unintialized pointers usually point to address zero, which is not allocated to any program. Always use gcc -Wall when compiling, this will many times point to these potential problems. Helped me find it right away.
Also, you could have declared your VECT type to be typedef struct vector (a non-pointer type).
VECT coord1;
VECT* v_coord1 = &coord1;
v_coord1->x = 0.0012345;
v_coord1->y = 0.012345;
v_coord1->z = 0.12345;`
Also, variable naming conventions can help here as well.
struct vector{
double x;
double y;
double z;
};
typedef struct vector VECT;
typedef struct vector* pVECT;
I have the following linked list:
struct scoreentry_node {
struct scoreentry_node *next;
int score;
char name[1];
}
;
typedef struct scoreentry_node *score_entry;
I'm trying to write a function that removes all nodes that contain a certain name. Here is what I have so far but I'm not sure I'm right:
score_entry disqualify(score_entry a, char* name)
{
score_entry tmp = a;
while (tmp != NULL){
if (strcmp(tmp->name, name) == 0)
{
score_entry trash = tmp;
tmp = tmp->next;
free(trash);
}
else { tmp = tmp->next; }
}
return a;
}
It gives me heap error's .. Any suggestions?
score_entry disqualify(score_entry a, char* name)
{
score_entry new_front = a, tmp;
// delete "wrong" entries from the front
while (new_front != NULL){
if (strcmp(new_front->name, name) == 0)
{
score_entry trash = new_front;
new_front = new_front->next;
free(trash);
}
else
{
// first list entry is valid
// delete "wrong" entries from inside the list
tmp = new_front;
while ( tmp->next != NULL )
{
if ( strcmp(tmp->next->name,name)==0 )
{
score_entry trash = tmp->next;
tmp->next = tmp->next->next;
free(trash);
} else
{
tmp = tmp->next;
}
}
}
}
return new_front;
}
You should also obtain some book related to common data structures - you seem to be interested in the stuff, and it could be a great help for you.
If you delete a member from the list you must fix the gap this creates by linking the 'next' pointer of the previous entry to the following entry. The code below does that. Note that I have changed score_entry so that the typedef no longer contains the pointer - I prefer not to disguise types. Notice that the function returns the head which might have changed if we deleted the first entry in the list.
typedef struct scoreentry_node score_entry;
static score_entry *
disqualify(score_entry *head, const char *name)
{
score_entry *se = head;
score_entry *prev = head;
while (se) {
if (!strcmp(se->name, name)) {
score_entry *next = se->next;
if (head == se) {
head = next;
} else {
prev->next = next;
}
free(se);
se = next;
} else {
prev = se;
se = se->next;
}
}
return head;
}
You're using strcmp on a non-null-terminated string (tmp->name). I'm assuming it's not null-terminated as it's only of length 1. Seems like you're really comparing a character, not a string, so a simple character equality operator would be the right thing to do.