A doubly linked list - c

I wrote a program to manage Bank accounts by the means of a doubly linked list, but I found a problem with the cancellation procedure.
void suppCompte (int numCpt) {
CompteBancaire *pnt = first;
if (first==NULL) {
printf("la liste vide !\n");
}else{
while (pnt != NULL && pnt->idf.numCompte != numCpt) {
pnt=pnt->next;
if (pnt==first) { // Remove the first node
first=pnt->next;
free(pnt);
}else if (pnt->next==NULL) { // Remove the last node
pnt->prc->next=NULL;
free(pnt);
}else{ // Remove a moddle node
pnt->prc->next=pnt->next; // <==== !!!!
pnt->next->prc=pnt->prc; // <==== !!!!
free(pnt);
}
}
}
}
I still have the same problem, even if I tried to do this method:
-(pnt->prc)->next=pnt->next;

The line after the while loop causes the problem, i.e. pnt=pnt->next should be after the if-else if . So if there is only 1 node, then pnt will be NULL, which causes problem in the else part. The modified code is :
void suppCompte (int numCpt)
{
CompteBancaire *pnt=first;
if (first==NULL)
printf("la liste vide !\n");
else
{
while (pnt!=NULL && pnt->idf.numCompte!=numCpt)
CompteBancaire *temp=pnt;
if (pnt==first) // Remove the first node
{ first=pnt->next;
}
else if (pnt->next==NULL) // Remove the last node
{ pnt->prc->next=NULL;
}
else // Remove a moddle node
{ pnt->prc->next=pnt->next; <==== !!!!
pnt->next->prc=pnt->prc; <==== !!!!
}
pnt=temp->next;
free(temp);
}
}

Check your pointers to make sure that they are not NULL. This can be done with two easy if loops. You always have to watch out for this sort of thing with doubly linked lists, and you have to think carefully about the order of your instructions.
Then, after you set the pointers to sort of "point around" the current node, set the pointers of the current node to NULL.
Also, consider using gdb. It is the Gnu DeBugger. If you compile with gcc, you can say gcc -g <files and other stuff> to compile with gdb debugging symbols. Then you can run the program in gdb, and inspect the values of variables, watch stuff evaluate, etc. You can probably find a lot of good material on this.

Related

Recursive Solution to Free Memory in C

I am working on building a shell and have this function that frees memory of the programs in the command line. I am interested in trying to create a recursive solution as I am trying to better understand recursion.
The program struct in the header file looks like this and is implemented as a linked list so it can support pipes.
// The program to be executed
typedef struct prog {
arglist_t args; // Arguments, including the program name
redirection_t redirection; // Optional redirections
struct prog *prev; // The prev program in the pipeline, if any; NULL otherwise
} prog_t;
This is the iterative free memory function implementation:
void free_memory(prog_t *exe) {
prog_t *tmp;
while(exe != NULL) {
for (int i = 0; i < exe->args.size; i++) {
if(exe->args.args[i]) free(exe->args.args[i]);
}
free(exe->args.args);
if (exe->redirection.in) free(exe->redirection.in);
if (exe->redirection.out1) free(exe->redirection.out1);
if (exe->redirection.out2) free(exe->redirection.out2);
if(exe->redirection.in != NULL) {
free(exe->redirection.in);
}
if(exe->redirection.out1 != NULL) {
free(exe->redirection.out1);
}
if(exe->redirection.out2 != NULL) {
free(exe->redirection.out2);
}
tmp = exe;
exe = exe->prev;
free(tmp);
}
}
How would I go about developing a recursive solution?
For recursion, you call instead of looping. For your case, change the while into an if and change the last three lines of the while/if body to
free_memory(exe->prev);
free(exe);
or to make it more efficient (tail recursive):
tmp = exe->prev;
free(exe);
free_memory(tmp);
the tail recursive version will probably generate identical code to your while loop.

reversing a doubled linked list without using any extra pointer

im trying to reverse a double linked list without using any extra pointer.I only have head pointer pointing to the first node of my double linked list.
here is my function to reverse the linked list:
int reverse(){
if(head==NULL || head->next==NULL){
return 0;
}
else{
head->prev=head->next;
head->next=NULL;
head->prev->prev=head->prev->next;
head->prev->next=head;
head=head->prev;
while(head->prev==NULL){
head->prev->prev=head->prev->next;
head->prev->next=head;
head=head->prev;
}
}}
if my linked list have data 1,2,3,4,5 and after running the reverse function ,when i'm trying to display the data i'm getting output: 2,1 (instead of 5,4,3,2,1)
there is a error in while statement while(head->prev==NULL)
the correct code is while(head->prev!=NULL)
so the correct code of the function is:
int reverse(){
if(head==NULL || head->next==NULL){
return 0;
}
else{
head->prev=head->next;
head->next=NULL;
head->prev->prev=head->prev->next;
head->prev->next=head;
head=head->prev;
while(head->prev!=NULL){
head->prev->prev=head->prev->next;
head->prev->next=head;
head=head->prev;
}
}}

C recursively build tree using structure pointer

I'm now implementing Barnes-Hut Algorithms for simulating N-body problem. I only want to ask about the building-tree part.
There are two functions I made to build the tree for it.
I recursively build the tree, and print the data of each node while building and everything seems correct, but when the program is back to the main function only the root of the tree and the child of the root stores the value. Other nodes' values are not stored, which is weird since I printed them during the recursion and they should have been stored.
Here's some part of the code with modification, which I thought where the problem might be in:
#include<...>
typedef struct node{
int data;
struct node *child1,*child2;
}Node;
Node root; // a global variable
int main(){
.
set_root_and_build(); // is called not only once cuz it's actually in a loop
traverse(&root);
.
}
Here's the function set_root_and_build():
I've set the child pointers to NULL, but didn't show it at first.
void set_root_and_build(){
root.data = ...;
..// set child1 and child2 =NULL;
build(&root,...); // ... part are values of data for it's child
}
And build:
void build(Node *n,...){
Node *new1, *new2 ;
new1 = (Node*)malloc(sizeof(Node));
new2 = (Node*)malloc(sizeof(Node));
... // (set data of new1 and new2 **,also their children are set NULL**)
if(some condition holds for child1){ // else no link, so n->child1 should be NULL
build(new1,...);
n->child1 = new1;
//for debugging, print data of n->child1 & and->child2
}
if(some condition holds for child2){ // else no link, so n->child2 should be NULL
build(new2,...);
n->child1 = new2;
//for debugging, print data of n->child1 & and->child2
}
}
Nodes in the tree may have 1~2 children, not all have 2 children here.
The program prints out the correct data when it's in build() function recursion, but when it is back to main function and calls traverse(), it fails due to a segmentation fault.
I tried to print everything in traverse() and found that only the root, and root.child1, root.child2 stores the value just as what I've mentioned.
Since I have to called build() several times, and even in parallel, new1 and new2 can't be defined as global variables. (but I don't think they cause the problem here).
Does anyone know where it goes wrong?
The traverse part with debugging info:
void traverse(Node n){
...//print out data of n
if(n.child1!=NULL)
traverse(*(n.child1))
...//same for child2
}
You may not be properly setting the children of n when the condition does not hold. You might want this instead:
void set_root_and_build()
{
root.data = ...;
build(&root,...); // ... part are values of data for it's child
}
void build(Node *n,...)
{
n->child1 = n->child2 = NULL;
Node *new1, *new2;
new1 = (Node*) malloc(sizeof(Node));
new2 = (Node*) malloc(sizeof(Node));
// set data of new1 and new2 somehow (read from stdin?)
if (some condition holds for new1)
{
n->child1 = new1;
build(n->child1,...);
//for debugging, print data of n->child1
}
else
free(new1); // or whatever else you need to do to reclaim new1
if (some condition holds for new2)
{
n->child2 = new2;
build(n->child2,...);
//for debugging, print data of n->child2
}
else
free(new2); // or whatever else you need to do to reclaim new2
}
Of course, you should be checking the return values of malloc() and handling errors too.
Also, your traversal is a bit strange as it recurses by copy rather than reference. Do you have a good reason for doing that? If not, then maybe you want:
void traverse(Node *n)
{
...//print out data of n
if (n->child1 != NULL)
traverse(n->child1)
...//same for child2
}
The problem in your tree traversal is that you certainly process the tree until you find a node pointer which is NULL.
Unfortunately when you create the nodes, these are not initialized neither with malloc() nor with new (it would be initialized with calloc() but this practice in cpp code is as bad as malloc()). So your traversal continues to loop/recurse in the neverland of random pointers.
I propose you to take benefit of cpp and change slightly your structure to:
struct Node { // that's C++: no need for typedef
int data;
struct node *child1,*child2;
Node() : data(0), child1(nullptr), child2(nullptr) {} // Makes sure that every created are first initalized
};
And later get rid of your old mallocs. And structure the code to avoid unnecessary allocations:
if(some condition holds for child1){ // else no link, so n->child1 should be NULL
new1=new Node; // if you init it here, no need to free in an else !!
build(new1,...);
n->child1 = new1;
...
}
if (... child2) { ... }
Be aware however that poitners allocated with new should be released with delete and note with free().
Edit: There is a mismatch in your code snippet:
traverse(&root); // you send here a Node*
void traverse(Node n){ // but your function defines an argument by value !
...
}
Check that you didn't overllok some warnings from the compiler, and that you have no abusive cast in your code.

Having trouble deleting elements in doubly linked list

I've been trying for about 5 hours to get this code to work properly, and the code is written based on hours of internet research.
I have modified it several times, all of which gave me segmentation faults, so this is the only version that runs.
What is happening, is that the code is cycling through, and deleting not only the element you want to get rid of, but all elements preceding it. So, if you want to delete the last element, everything in the list goes. Or, if you wanted to delete the second element, the first and second go, and so on.
It thinks that every name entered is the top name for some reason.
static void menu_delete_employee(void)
{
char deletename[MAX_NAME_LENGTH+1];
char namecheck[MAX_NAME_LENGTH+1];
int errorcheck = 0;
int foundit = 0;
fprintf(stderr, "Enter the name of the employee you wish to delete\n");
gets(deletename);
employee_list = top;
employee_list->name;
do
{
strcpy (namecheck, employee_list->name);
printf("namecheck = %s\n", namecheck);
errorcheck = (strcmp (namecheck, deletename));
printf("errorcheck = %i\n", errorcheck);
switch (errorcheck)
{
case 0:
{
printf("This is the right name\n");
foundit = 1;
if (employee_list->prev == NULL)
{
printf("top name\n");
top = employee_list->next;
}
else
{
if (employee_list->next == NULL)
{
printf("last one\n");
temp = employee_list->prev;
temp-> next = NULL;
free (employee_list);
}
else
{
printf("somewhere in the middle");
temp = employee_list->prev;
temp->next = employee_list->next;
employee_list->next->prev = temp;
free (employee_list);
}
}
printf("delete successful\n");
break;
}
default:
{
printf("not this one\n");
errorcheck = 0;
employee_list = employee_list->next;
break;
}
}
}
while (foundit == 0);
if (foundit == 0)
printf("Name not recognised\n.");
return;
}
Any help would be much appreciated.
Maybe the doubly-linked list is not built up the way you think it should. This has to be checked first.
Assuming the topology is correct, there are still a couple of issues with this code:
employee_list->name; (just above the do loop): what is this?
strcpy (namecheck, employee_list->name); : you do not need to copy, this is just a shorthand, so namecheck could be a (const) string pointer.
switch (errorcheck) : this has only 2 arms, why don't you use an if ?
if (employee_list->prev == NULL) ...: you just move the top pointer here but do not delete the top item, this will cause memory leaks. You also do not set the prev pointer of the next-to-top item to NULL.
In the "somewhere in the middle" part: you free employee_list which is the current position pointer. The next item to be processed should be temp->next, right? This is probably your problem because you do not take care of moving the current pointer along. Moreover, it is much better to set a pointer explicitly called tobedeleted to the item to be deleted, make sure the pointer used to iterate along the list (employee_list in your case) is moved appropriately, and when *tobedeleted is appropriately isolated out from the doubly linked list then issue the free(tobedeleted) command.
employee_list = employee_list->next; : you should check for employee_list turning into NULL at the last item, and exit the loop. Otherwise Bad Things will happen.
Final advice: you really need to consult a good C book... Kernighan and Ritchie
for instance. Way better than "Internet research".

I have to sort the students record firstly level wise then name wise

The code I have made is as follow...but it is not sorting the result at all.it is just printing the same as it is input. Please help me out
strcpy(newnode->stud_name,name);
strcpy(newnode->stud_intake,id);
strcpy(newnode->stud_branch,course);
newnode->level=slevel;
newnode->next=NULL;
if(list==NULL)
list=newnode;
else
{
if(slevel==list->level)
{
temp=list;
placefound=0;
while(temp!=NULL && slevel==temp->level)
{
if(name>temp->stud_name)
{
prev=temp;
temp=temp->next;
}//else
//placefound=1;
}
newnode->next=prev->next;
prev->next=newnode;
}
Without trying to debug your linked list code in detail, there's one very suspicious point:
if(name>temp->stud_name)
is probably wrong -- you can't compare C strings with ">". Look up how to use the "strcmp" function in the C standard library.

Resources