Find the minimum even number in a list recursively - c

I've written this function:
struct nodo * MinimoPariListaRic(struct nodo * top) {
struct nodo * minimo_p = NULL; //this should be the minimum even number
//list have one or no one element
if(top) {
if(!top->next)
if(top->valore % 2 == 0) return top; // valore(italian) = value
else return NULL;
}
else return NULL;
if(top->next)
minimo_p = MinimoPariListaRic(top->next);
if (top->valore % 2 == 0)
{
if(minimo_p->valore < top->valore) return minimo_p;
else return top;
}
else return minimo_p;
}
If the list's elements are all even, the function will return the minimum, and it's ok.
But if an odd number appears, the function doesn't work correctly.
If all the numbers are odd, function should return NULL.

Because minimo_p can be NULL after the function returns from recursion if the list contains an odd integer at the last position and at least one even integer anywhere.
This line is erroneous:
if(minimo_p->valore < top->valore) return minimo_p;
You can just add the null condition here:
if(minimo_p && minimo_p->valore < top->valore) return minimo_p;

your algorithm is wrong, you can have an undefined behavior if the recursive call return NULL because setting minimo_p to NULL and you will dereference it if (top->valore % 2 == 0), and it is too much complicated, you do not need a recursive call, just to go throw the list, for instance :
struct nodo * MinimoPariListaRic(struct nodo * l) {
struct nodo * minimo_p = NULL; //this should be the minium even number
while (l != NULL) {
if (l->valore % 2 == 0) {
if ((minimo_p == NULL) || (l->valore < minimo_p->valore))
minimo_p = l;
}
l = l->next;
}
return minimo_p;
}
Because your edited topic requires a recursive call you can do for instance :
struct nodo * MinimoPariListaRic(struct nodo * l) {
if (l == NULL)
return NULL;
else {
struct nodo * minimo_p = MinimoPariListaRic(l->next);
return ((l->valore % 2 == 0) &&
((minimo_p == NULL) || (l->valore < minimo_p->valore)))
? l : minimo_p;
}
}
as you can see this is simple, I check only one times in the program if valore is odd or not etc
using a full program to check :
#include <stdio.h>
#include <stdlib.h>
struct nodo {
struct nodo * next;
int valore;
};
struct nodo * MinimoPariListaRic(struct nodo * l) {
if (l == NULL)
return NULL;
else {
struct nodo * minimo_p = MinimoPariListaRic(l->next);
return ((l->valore % 2 == 0) &&
((minimo_p == NULL) || (l->valore < minimo_p->valore)))
? l : minimo_p;
}
}
int main(int argc, char ** argv)
{
/* make a list from the args */
struct nodo * l = NULL;
while (argc > 1) {
struct nodo * r = malloc(sizeof(*r));
r->next = l;
if (sscanf(argv[--argc], "%d", &r->valore) != 1) {
puts("invalid number");
return 0;
}
l = r;
}
/* show list well made */
struct nodo * ll;
for (ll = l; ll != NULL; ll = ll->next)
printf("%d ", ll->valore);
putchar('\n');
/* */
ll = MinimoPariListaRic(l);
if (ll == NULL)
puts("no even value");
else
printf("min even value is %d\n", ll->valore);
/* free resources */
while (l) {
ll = l->next;
free(l);
l = ll;
}
return 0;
}
Compilation and executions:
pi#raspberrypi:/tmp $ gcc -Wall l.c
pi#raspberrypi:/tmp $ ./a.out 1 4 2 7 8
1 4 2 7 8
min even value is 2
pi#raspberrypi:/tmp $ ./a.out
no even value
pi#raspberrypi:/tmp $ ./a.out 3
3
no even value
pi#raspberrypi:/tmp $ ./a.out 3 3 1 5
3 3 1 5
no even value
pi#raspberrypi:/tmp $ valgrind ./a.out 3 4 5 2 0
==16881== Memcheck, a memory error detector
==16881== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16881== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==16881== Command: ./a.out 3 4 5 2 0
==16881==
3 4 5 2 0
min even value is 0
==16881==
==16881== HEAP SUMMARY:
==16881== in use at exit: 0 bytes in 0 blocks
==16881== total heap usage: 6 allocs, 6 frees, 1,064 bytes allocated
==16881==
==16881== All heap blocks were freed -- no leaks are possible
==16881==
==16881== For lists of detected and suppressed errors, rerun with: -s
==16881== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
pi#raspberrypi:/tmp $

if you have to use recursion you should try write this down in pseudo language first:
if current list has only one element
-> return it if even, else return null
if list has more elements
get minimum of rest of list
if current element is odd
return the rest-minimum
else if rest is null
return this element
else if rest is not null
return the smaller one
I would not go with recusion on this. With really long lists you will crash your stack.
A simple loop would be even simpler and less mind bending:
init minimum to NULL
init iterator with list
while iterator != Null
if iterator even and minimum == Null
minimum = iterator
else if even and iterator < minimum
minimum = iterator
advance iterator

My five cents. I have also included a recursive function that finds the node with the maximum even value.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct nodo
{
int valore;
struct nodo *next;
};
int push_front( struct nodo **top, int valore )
{
struct nodo *nodo_nuovo = malloc( sizeof( struct nodo ) );
int success = nodo_nuovo != NULL;
if ( success )
{
nodo_nuovo->valore = valore;
nodo_nuovo->next = *top;
*top = nodo_nuovo;
}
return success;
}
FILE * display( struct nodo *top, FILE *fp )
{
for ( ; top != NULL; top = top->next )
{
fprintf( fp, "%d -> ", top->valore );
}
fputs( "null", fp );
return fp;
}
struct nodo * MinimoPariListaRic( struct nodo * top )
{
if ( !top )
{
return top;
}
else
{
struct nodo *minimo = MinimoPariListaRic( top->next );
if ( minimo == NULL )
{
minimo = top->valore % 2 == 0 ? top : minimo;
}
else if ( top->valore % 2 == 0 )
{
minimo = minimo->valore < top->valore ? minimo : top;
}
return minimo;
}
}
struct nodo * MassimoPariListaRic( struct nodo * top )
{
if ( !top )
{
return top;
}
else
{
struct nodo *massimo = MassimoPariListaRic( top->next );
if ( massimo == NULL )
{
massimo = top->valore % 2 == 0 ? top : massimo;
}
else if ( top->valore % 2 == 0 )
{
massimo = top->valore < massimo->valore ? massimo : top;
}
return massimo;
}
}
int main(void)
{
struct nodo *top = NULL;
enum { N = 10 };
srand( ( unsigned int )time( NULL ) );
for ( int i = 0; i < N; i++ )
{
push_front( &top, rand() % N );
}
fputc( '\n', display( top, stdout ) );
struct nodo *minimo = MinimoPariListaRic( top );
if ( minimo != NULL )
{
printf( "Minimo pari valore is %d\n", minimo->valore );
}
else
{
puts( "there is no minimo pari valore" );
}
struct nodo *massimo = MassimoPariListaRic( top );
if ( massimo != NULL )
{
printf( "Massimo pari valore is %d\n", massimo->valore );
}
else
{
puts( "there is no massimo pari valore" );
}
return 0;
}
The program output might look like
8 -> 9 -> 9 -> 9 -> 7 -> 9 -> 7 -> 3 -> 1 -> 2 -> null
Minimo pari valore is 2
Massimo pari valore is 8
As for your function definition then you need to check whether the pointer
minimo_p returned by the call
if(top->next)
minimo_p = MinimoPariListaRic(top->next);
is equal to NULL in the next if statement
if (top->valore % 2 == 0)
{
if(minimo_p->valore < top->valore) return minimo_p;
else return top;
}

Related

Keep one occurrence of all numbers in a linked list

I want to find an algorithm to keep only one occurrence of each number in a linked list using recursion
,I know recursion is not at all a good choice to solve this problem ,but I want to try it.
for more calirification:
input : 1->2->1->3->3->2->1->4
output : 1->2->3->4
Here is the program that i've made to keep only one occurrence of a given number using recursion, but i couldn't develop it in order to solve the whole problem. can I get some help? thanks in advance.
list* wipe(list* head,int val)
{
if(head==NULL) return head;
static int occ=1;
if(head->data == val)
{
if(occ-- < 1)
{
list* temp=head;
head=head->next;
free(temp);
return wipe(head,val);
}
}
head->next=wipe(head->next,val);
return head;
}
occ is set to 1 only the very time you execute the function, so from the second time (head->data == val) is true whatever val the test (occ-- < 1) will be true, this is not the right way.
You can do something like that where the list is modified to only contain unique numbers :
#include <stdio.h>
#include <stdlib.h>
typedef struct List {
struct List * next;
int data;
} List;
/* remove from l all the cells having data equals to v */
List * wipe(int v, List * l)
{
if (l == NULL)
return l;
else if (l->data != v) {
l->next = wipe(v, l->next);
return l;
}
else {
List * n = l->next;
free(l);
return wipe(v, n);
}
}
/* modify the argument to not have duplicated numbers */
void simplify(List * l)
{
while (l != NULL) {
l->next = wipe(l->data, l->next);
l = l->next;
}
}
/* helper function to construct a list */
List * mk(int v, List * n) {
List * l = malloc(sizeof(*l));
l->data = v;
l->next = n;
return l;
}
/* print the list */
void pr(List * l)
{
while (l != NULL) {
printf("%d ", l->data);
l = l->next;
}
putchar('\n');
}
int main()
{
List * l = mk(1, mk(2, mk(1, mk(3, mk(3, mk(2, mk(1, mk(4, NULL))))))));
pr(l);
simplify(l);
pr(l);
/* free the rest of the list */
while (l) {
List * n = l->next;
free(l);
l = n;
}
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -Wall c.c
pi#raspberrypi:/tmp $ ./a.out
1 2 1 3 3 2 1 4
1 2 3 4
pi#raspberrypi:/tmp $ valgrind ./a.out
==3988== Memcheck, a memory error detector
==3988== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3988== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==3988== Command: ./a.out
==3988==
1 2 1 3 3 2 1 4
1 2 3 4
==3988==
==3988== HEAP SUMMARY:
==3988== in use at exit: 0 bytes in 0 blocks
==3988== total heap usage: 9 allocs, 9 frees, 1,088 bytes allocated
==3988==
==3988== All heap blocks were freed -- no leaks are possible
==3988==
==3988== For lists of detected and suppressed errors, rerun with: -s
==3988== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
pi#raspberrypi:/tmp $
That way have the complexity O(n2)
A faster way is to first sort the elements in the list then remove the duplicates, allowing to have the complexity of the sort so possibly O(n*log(n)) (probably using a temporary array to sort)
If I have understood correctly you need a recursive function that appends a number to a list only in case when the number is not present already in the list.
If so then the recursive function can look for example like
int append( list **head, int val )
{
if ( *head == NULL )
{
*head = malloc( sizeof( **head ) );
int success = *head != NULL;
if ( success )
{
( *head )->data = val;
( *head )->next = NULL;
}
return success;
}
else if ( ( *head )->data != val )
{
return append( &( *head )->next, val );
}
else
{
return 0;
}
}
And if in main you have a declaration like this
list *head = NULL;
then the function can be called for example like
append( &head, val );
Or like
if ( append( &head, val ) )
{
printf( "The value %d is appended to the list.\n", val );
}

Delete element from doubly linked list using recursive

I want to delete an element from doubly linked list, but i need to using recursion.
I write function but it doesn't work. Can someone tell me where did i a mistake?
int deleteNode(struct dll_node **front, int data){
if((*front) == NULL){
return 0;
}
if(data == (*front)->data){
int tmp = (*front)->data;
(*front)->next = (*front)->prev;
(*front)->prev = (*front)->next;
free(*front);
return tmp;
}
deleteNode((*front)->next, data);
}
there are several problems
you save data in tmp for nothing
you do not update rightly the list
your recursive call does not give right the first argument (must be deleteNode(&(*front)->next, data);, and in fact you must return it), note it is terminal so you can also use a loop
return is missing if the two tests are false
It can be :
int deleteNode(struct dll_node **front, int data){
if((*front) == NULL){
return 0;
}
if(data == (*front)->data){
struct dll_node * d = *front;
if (d->prev == NULL) {
if ((*front = d->next) != NULL)
(*front)->prev = NULL;
}
else if ((d->prev->next = d->next) != NULL)
d->next->prev = d->prev;
free(d);
return data;
}
return deleteNode(&(*front)->next, data);
}
Full code to check :
#include <stdio.h>
#include <stdlib.h>
struct dll_node {
int data;
struct dll_node * prev;
struct dll_node * next;
};
int deleteNode(struct dll_node **front, int data){
if((*front) == NULL){
return 0;
}
if(data == (*front)->data){
struct dll_node * d = *front;
if (d->prev == NULL) {
if ((*front = d->next) != NULL)
(*front)->prev = NULL;
}
else if ((d->prev->next = d->next) != NULL)
d->next->prev = d->prev;
free(d);
return data;
}
return deleteNode(&(*front)->next, data);
}
struct dll_node * mk(int d)
{
struct dll_node * r = malloc(sizeof(struct dll_node));
r->data = d;
r->prev = NULL;
r->next = NULL;
return r;
}
void pr(struct dll_node * l)
{
while (l != NULL) {
printf("%d", l->data);
if (l->prev)
printf(" prev:%d\n", l->prev->data);
else
putchar('\n');
l = l->next;
}
}
int main()
{
struct dll_node * head = mk(1);
struct dll_node * a = mk(2);
struct dll_node * b = mk(3);
head->next = a;
a->prev = head;
b->prev = a;
a->next = b;
pr(head);
puts("\ndel 3");
deleteNode(&head, 3);
pr(head);
puts("\ndel 1");
deleteNode(&head, 1);
pr(head);
puts("\ndel 2");
deleteNode(&head, 2);
pr(head);
}
Compilation and executions :
pi#raspberrypi:/tmp $ gcc -Wall l.c
pi#raspberrypi:/tmp $ ./a.out
1
2 prev:1
3 prev:2
del 3
1
2 prev:1
del 1
2
del 2
pi#raspberrypi:/tmp $ valgrind ./a.out
==8496== Memcheck, a memory error detector
==8496== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8496== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==8496== Command: ./a.out
==8496==
1
2 prev:1
3 prev:2
del 3
1
2 prev:1
del 1
2
del 2
==8496==
==8496== HEAP SUMMARY:
==8496== in use at exit: 0 bytes in 0 blocks
==8496== total heap usage: 4 allocs, 4 frees, 1,060 bytes allocated
==8496==
==8496== All heap blocks were freed -- no leaks are possible
==8496==
==8496== For lists of detected and suppressed errors, rerun with: -s
==8496== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
pi#raspberrypi:/tmp $

Delete all the nodes from a list that respect a condition influenced by another list

I am studying the lists and I came across this exercise which asks me to do the following steps:
Define a function that, given two lists of integers L1 and L2, and an integer n>0, eliminate from the first list the nodes for which the sum of the contents of L1 and L2 in the corresponding position (with respect to the original positions) is a multiple of n. If L2 ends, consider only the content of L1 instead of the sum.
I tried to analyze the problem with a single list and in this case I had no problems, but in this specific case I couldn't figure out how to proceed.
my problem is that I can't understand how properly build the various cases (L1 must be always != NULL, so I have: L1 != NULL && L2 != NULL or L1 != NULL && L2 == NULL).
Can someone explain to me the procedure to be performed and where am I wrong?
This is my attempt:
struct data
{
int d;
struct data *next;
};
typedef struct data Nodo;
typedef Nodo *LIST;
void function(LIST *l1, LIST l2, int n)
{
LIST p, head_1, head_2;
while((*l1 != NULL && l2 != NULL)&&((*l1)->d + l2->d) % n == 0)
{
p = *l1;
*l1 = (*l1)->next;
free(p);
}
while((*l1 != NULL) && ((*l1)->d + l2->d) % n == 0)
{
p = *l1;
*l1 = (*l1)->next;
free(p);
}
if (*l1 != NULL)
{
head_1 = *l1;
head_2 = l2;
while(head_1->next != NULL)
{
if (((head_1->next->d + head_2->next->d) % n) == 0)
{
p = head_1->next;
head_1->next = head_1->next->next;
free(p);
}
else
{
head_1 = head_1->next;
head_2 = head_2->next;
}
}
}
}
Example:
L1: 4->4->11->3->4->8->7->NULL
L2: 5->1->5->1->5
OUTPUT(L1): 4->4->4->7->NULL
You have a problem of logic with the consecutive loops :
while((*l1 != NULL && l2 != NULL)&&((*l1)->d + l2->d) % n == 0) {
...
}
while((*l1 != NULL) && ((*l1)->d + l2->d) % n == 0){
...
}
if the sum of the elements are not a multiple of n you need to move to the next element, but you do not do
Out of that to hide a pointer with a typedef like you do with typedef Nodo *LIST; is dangerous and is a good way to introduce problem, I recommend you to never do that.
You can do that :
void removeIf(Nodo ** l1, Nodo * l2, int n)
{
while ((*l1 != NULL) && (l2 != NULL)) {
if ((((*l1)->d + l2->d) % n) == 0) {
/* cell must be removed */
Nodo * rm = *l1;
*l1 = (*l1)->next;
free(rm);
}
else {
/* cell not removed */
l1 = &(*l1)->next;
}
l2 = l2->next;
}
// case where l2 is shorter than l1
while (*l1 != NULL) {
if (((*l1)->d % n) == 0) {
/* cell must be removed */
Nodo * rm = *l1;
*l1 = (*l1)->next;
free(rm);
}
else {
/* cell not removed */
l1 = &(*l1)->next;
}
}
}
Making a full program for
L1: 4->4->11->3->4->8->7
L2: 5->1->5->1->5
N : 2
#include <stdio.h>
#include <stdlib.h>
struct data {
int d;
struct data *next;
};
typedef struct data Nodo;
void removeIf(Nodo ** l1, Nodo * l2, int n)
{
while ((*l1 != NULL) && (l2 != NULL)) {
if ((((*l1)->d + l2->d) % n) == 0) {
/* cell must be removed */
Nodo * rm = *l1;
*l1 = (*l1)->next;
free(rm);
}
else {
/* cell not removed */
l1 = &(*l1)->next;
}
l2 = l2->next;
}
// case where l2 is shorter than l1
while (*l1 != NULL) {
if (((*l1)->d % n) == 0) {
/* cell must be removed */
Nodo * rm = *l1;
*l1 = (*l1)->next;
free(rm);
}
else {
/* cell not removed */
l1 = &(*l1)->next;
}
}
}
Nodo * make(int v, Nodo * n)
{
Nodo * r = malloc(sizeof(Nodo));
r->d = v;
r->next = n;
return r;
}
void del(Nodo ** pl)
{
while (*pl != NULL) {
Nodo * n = *pl;
*pl = (*pl)->next;
free(n);
}
}
int main()
{
Nodo * l1 = make(4, make(4, make(11, make(3, make(4, make(8, make(7, NULL)))))));
Nodo * l2 = make(5, make(1, make(5, make(1, make(5, NULL)))));
removeIf(&l1, l2, 2);
/* show result */
for (Nodo * l = l1; l != NULL; l = l->next)
printf("%d ", l->d);
putchar('\n');
/* free resources */
del(&l1);
del(&l2);
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -pedantic -Wall -Wextra ll.c
pi#raspberrypi:/tmp $ ./a.out
4 4 4 7
pi#raspberrypi:/tmp $
Execution under valgrind :
pi#raspberrypi:/tmp $ valgrind ./a.out
==3758== Memcheck, a memory error detector
==3758== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3758== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3758== Command: ./a.out
==3758==
4 4 4 7
==3758==
==3758== HEAP SUMMARY:
==3758== in use at exit: 0 bytes in 0 blocks
==3758== total heap usage: 13 allocs, 13 frees, 1,120 bytes allocated
==3758==
==3758== All heap blocks were freed -- no leaks are possible
==3758==
==3758== For counts of detected and suppressed errors, rerun with: -v
==3758== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
pi#raspberrypi:/tmp $

How to fix runtime error: load of null pointer of type 'const char

I need to write function which loads dictionary in hash table.I'm confused about error message: c:37:20 runtime error: load of null pointer of type 'const char', which runs in segmentation fault.
I've tried to change load function, but still didn`t help. And also tried to allocate memory for hashtable, as I thought problem might be in memory leaks.
` // Represents number of buckets in a hash table
#define N 26
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Represents a hash table
node *hashtable[N];
// Hashes word to a number between 0 and 25, inclusive, based on its first letter
unsigned int hash(const char *word)
{
// Allocates memory for hashtable
int *ht = malloc(26*sizeof(int));
if(!ht)
{
unload();
return false;
}
return tolower(word[0]) - 'a'; // this is error line 37:20
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
// Initialize hash table
for (int i = 0; i < N; i++)
{
hashtable[i] = NULL;
}
// Open dictionary
FILE *file = fopen(dictionary, "r");
if (file == NULL)
{
unload();
return false;
}
// Buffer for a word
char word[LENGTH + 1];
// Insert words into hash table
while (fscanf(file, "%s", word) != EOF)
{
for (int i = 0; i < N; i++ )
{
// Allocate memory for node for each new word
node *new_node = malloc(sizeof(node));
if (!new_node)
{
unload();
return false;
}
// Copies word into node
strcpy(new_node->word, word);
new_node->next = NULL;
// Hashes word
hash(new_node->word);
// Inserts word into linked list
if(hashtable[i] == 0)
{
hashtable[i] = new_node;
}
else if(hashtable[i] == new_node)
{
new_node->next = hashtable[i];
hashtable[i] = new_node;
}
}
}
// Close dictionary
fclose(file);
// Indicate success
return true;
}
The function load should retun true when dictionary is loaded. But I get segmentation fault. Does it mean I didn't get right output from load function?
In
new_node->next = NULL;
hash(new_node->word);
// Inserts word into linked list
if(hashtable[i] == 0)
{
hashtable[i] = new_node;
}
else if(hashtable[i] == new_node)
{
new_node->next = hashtable[i];
hashtable[i] = new_node;
}
you do not use the result of hash() and you use i rather than the hash result as index in hashtable, if N greater than 26 you read/write out of hashtable, in the other case you do not put the word in the right entry because the first at index 0, the next at index 1 etc whatever their first letter
Note else if(hashtable[i] == new_node) is never true and in fact never reach because if(hashtable[i] == 0) is always true because you limit the number of word to read
Must be something like that doing minimal changes
int h = hash(new_node->word);
// Inserts word into linked list
if(hashtable[h] == 0)
{
hashtable[h] = new_node;
new_node->next = NULL;
}
else
{
new_node->next = hashtable[h];
hashtable[h] = new_node;
}
but in fact can be simplified to be :
int h = hash(new_node->word);
new_node->next = hashtable[h];
hashtable[h] = new_node;
Note I suppose you do not read several times the same word (it is a dictionary)
To do
while (fscanf(file, "%s", word) != EOF)
is dangerous because there is no protection if the read word is longer than LENGTH
supposing LENGTH is 32 do ( the word can store 32 characters more the final null character) :
while (fscanf(file, "%32s", word) == 1)
There is no reason to have the loop :
for (int i = 0; i < N; i++ )
{
...
}
remove it (but not its body of course), so :
while (fscanf(file, "%32s", word) == 1)
{
// Allocate memory for node for each new word
node *new_node = malloc(sizeof(node));
if (!new_node)
{
unload();
return false;
}
// Copies word into node
strcpy(new_node->word, word);
int h = hash(new_node->word);
new_node->next = hashtable[h];
hashtable[h] = new_node;
}
tte part
// Initialize hash table
for (int i = 0; i < N; i++)
{
hashtable[i] = NULL;
}
is useless because hashtable being global is initialized with 0
If you want to reload the dictionary you need to free the linked list before to reset to NULL
memory leaks
the malloc in hash is useless and only create memory leaks, remove it :
// Hashes word to a number between 0 and 25, inclusive, based on its first letter
unsigned int hash(const char *word)
{
return tolower(word[0]) - 'a';
}
Warning if the first letter is not a-z or A-Z the return index is not a valid index for hashtable
For readability reason replace #define N 26 by #define N ('z' - 'a' + 1)
A proposal adding missing definitions :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define bool int
#define true 1
#define false 0
// Represents number of buckets in a hash table
#define N ('z' - 'a' + 1)
// Represent max word length
#define LENGTH 32
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node * next;
}
node;
// Represents a hash table
node * hashtable[N];
// Hashes word to a number between 0 and 25, inclusive, based on its first letter
unsigned int hash(const char *word)
{
return tolower(word[0]) - 'a';
}
// probable goal : empty hashtable
void unload()
{
for (size_t i = 0; i != N; ++i) {
while (hashtable[i] != NULL) {
node * next = hashtable[i]->next;
free(hashtable[i]);
hashtable[i] = next;
}
}
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
// Open dictionary
FILE * file = fopen(dictionary, "r");
if (file == NULL)
return false;
// Buffer for a word
char word[LENGTH + 1];
// Insert words into hash table
while (fscanf(file, "%32s", word) == 1)
{
if (isalpha(word[0])) {
// Allocate memory for node for each new word
node * new_node = malloc(sizeof(node));
if (!new_node)
{
unload();
return false;
}
// Copies word into node
strcpy(new_node->word, word);
int h = hash(new_node->word);
new_node->next = hashtable[h];
hashtable[h] = new_node;
}
}
// Close dictionary
fclose(file);
// Indicate success
return true;
}
int main(int argc, char ** argv)
{
if (argc != 2)
printf("Usage : %s <dictionary>\n", *argv);
else if (!load(argv[1]))
fprintf(stderr, "Error when loading '%s'\n", argv[1]);
else {
puts("dictionary content");
for (size_t i = 0; i != N; ++i) {
node * n = hashtable[i];
if (n != NULL) {
printf("%c :", i + 'a');
do {
printf(" %s", n->word);
n = n->next;
} while (n != NULL);
putchar('\n');
}
}
unload();
}
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall d.c
pi#raspberrypi:/tmp $ cat d
alternate
bellow and
Below
dictionary
Hash main zombie
test
Zorro
pi#raspberrypi:/tmp $ ./a.out
Usage : ./a.out <dictionary>
pi#raspberrypi:/tmp $ ./a.out d
dictionary content
a : and alternate
b : Below bellow
d : dictionary
h : Hash
m : main
t : test
z : Zorro zombie
Execution under valgrind :
pi#raspberrypi:/tmp $ valgrind ./a.out d
==2370== Memcheck, a memory error detector
==2370== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2370== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2370== Command: ./a.out d
==2370==
dictionary content
a : and alternate
b : Below bellow
d : dictionary
h : Hash
m : main
t : test
z : Zorro zombie
==2370==
==2370== HEAP SUMMARY:
==2370== in use at exit: 0 bytes in 0 blocks
==2370== total heap usage: 13 allocs, 13 frees, 5,872 bytes allocated
==2370==
==2370== All heap blocks were freed -- no leaks are possible
==2370==
==2370== For counts of detected and suppressed errors, rerun with: -v
==2370== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

Deleting node from linked list recursively in C

I'm new to C and I'm still having a hard time understanding how pointers and liked lists work, thus I'm having some issues with all of this.
I'm trying to delete a node from a linked list and I'm using the example on this link, but I can't get it to work.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct voos
{
int numeroVoo;
char ciaAerea[20];
char modeloAeronave[20];
char origem[20];
char destino[20];
int qtdeTotalAssentos;
int qtdeAssentosOcupados;
struct voos *proximo;
} *cadastroVoo;
int cont = 0; //Contador temporario para contar numero de assentos ocupados
void addVoo (cadastroVoo *local) //Add item to list
{
cadastroVoo novo;
novo = (cadastroVoo) malloc(sizeof(struct voos));
char temp[20];
if (novo != NULL)
{
printf("Informe o numero do voo: \n");
scanf("%d", &novo->numeroVoo);
printf("Informe a cia aerea: \n");
fflush(stdin);
gets(temp);
strcpy(novo->ciaAerea, temp);
printf("Informe o modelo da aeronave: \n");
fflush(stdin);
gets(temp);
strcpy(novo->modeloAeronave, temp);
printf("Informe a origem do voo: \n");
fflush(stdin);
gets(temp);
strcpy(novo->origem, temp);
printf("Informe o destino do voo: \n");
fflush(stdin);
gets(temp);
strcpy(novo->destino, temp);
cont++;
novo->qtdeAssentosOcupados = cont;
novo->qtdeTotalAssentos = 50;
novo->proximo = *local;
*local = novo;
}
}
void listarVoos(cadastroVoo local) //prints list
{
printf("Imprimindo lista atualizada: \n\n\n");
while (local != NULL)
{
printf("Numero voo: %d\n", local->numeroVoo);
printf("Cia Aerea: %s\n", local->ciaAerea);
printf("Modelo aeronave: %s\n", local->modeloAeronave);
printf("Origem: %s\n", local->origem);
printf("Destino: %s\n", local->destino);
printf("Quantidade total de assentos: %d\n", local->qtdeTotalAssentos);
printf("Quantidade de assentos ocupados: %d\n", local->qtdeAssentosOcupados);
printf("\n");
local = local->proximo;
}
}
cadastroVoo *cancelarPassagem(cadastroVoo *local, int numVoo) //deletes item from list
{
// See if we are at end of list.
if (local == NULL) return NULL;
// Check to see if current node is one to be deleted.
if (local->numeroVoo == numVoo)
{
cadastroVoo *tempNextP;
tempNextP = local->proximo;
free(local);
return tempNextP;
}
// Check the rest of the list, fixing the next pointer in case the next node is the one removed.
local->proximo = cancelarPassagem(local->proximo, numVoo);
//Return the pointer to where we were called from. Since we did not remove this node it will be the same.
return local;
}
int main()
{
cadastroVoo cadastro = NULL;
char op;
while(op != 'f')
{
printf("Escolha a opcao:\n");
printf("a - Incluir voos:\n");
printf("b - Listar voos:\n");
printf("c - Reservar assento em um voo:\n");
printf("d - Cancelar voo:\n");
printf("e - Cancelar passagem:\n");
printf("f - Sair:\n");
op = getche();
printf("\n");
switch(op)
{
case 'a':
{
printf("Incluir voo. \n");
addVoo(&cadastro);
printf("Voo incluso.\n");
break;
}
case 'b':
{
listarVoos(cadastro);
break;
}
case 'c':
{
printf("Reservar assento em um voo. \n");
addVoo(&cadastro);
printf("Assento reservado.\n");
break;
}
case 'd':
{
/**
*while (cancelarVoo != NULL) cancelarVoo()
*/
break;
}
case 'e':
{
int numVoo;
printf("Informe o numero do voo que deseja cancelar a passagem: \n");
scanf("%d", &numVoo);
cancelarPassagem(&cadastro, numVoo);
printf("Passagem cancelada");
break;
}
case 'f': break;
default:
{
printf("Opcao invalida.");
break;
}
}
}
return 0;
}
In the method declaration, if I pass:
cadastroVoo *cancelarPassagem(cadastroVoo *local, int numVoo)
I get the error: request for member 'numeroVoo' in something not a structure or union
But if I pass
cadastroVoo *cancelarPassagem(cadastroVoo local, int numVoo)
It runs, but then when I choose the option that calls this method, I'll get the message on windows that it stopped working.
Does anyone have any idea what could be going wrong?
Thanks in advance.
Probably you are not passing a pointer to the function. I tried your code here and the logic is working fine.
#include <stdio.h>
typedef struct cadastroVoo {
struct cadastroVoo *proximo;
int numero;
} CadastroVoo;
CadastroVoo *cancelarPassagem(CadastroVoo *local, int num);
void inserir(CadastroVoo *cabeca, int num) {
CadastroVoo *p = (CadastroVoo *) malloc(sizeof(CadastroVoo));
p->proximo = cabeca->proximo;
p->numero = num;
cabeca->proximo = p;
}
CadastroVoo *cancelarPassagem(CadastroVoo *local, int num) {
if (local == NULL) return NULL;
printf("> %d\n", local->numero);
printf("> %p\n", local->proximo);
if (local->numero == num) {
CadastroVoo *proximo = local->proximo;
free(local);
return proximo;
}
local->proximo = cancelarPassagem(local->proximo, num);
return local;
}
int main() {
CadastroVoo *cabeca = (CadastroVoo *) malloc(sizeof(CadastroVoo));
cabeca->proximo = NULL;
inserir(cabeca, 10);
inserir(cabeca, 20);
inserir(cabeca, 30);
inserir(cabeca, 40);
inserir(cabeca, 50);
cancelarPassagem(cabeca->proximo, 20);
CadastroVoo *p = cabeca->proximo;
while (p != NULL) {
printf("%d\n", p->numero);
p = p->proximo;
}
}
It is a bad idea to give references instead of the actual code in your question.
Nevertheless here is a simplified demonstrative program that uses recursive methods with a singly linked list. I am sure it does what you need. Investigate it and change your project accordingly.
#include <stdio.h>
#include <stdlib.h>
typedef struct List
{
int data;
struct List *next;
} List;
List * add_node( List *head, int data )
{
if ( head == NULL )
{
head = malloc( sizeof( List ) );
head->data = data;
head->next = NULL;
}
else
{
head->next = add_node( head->next, data );
}
return head;
}
List * remove_node( List *head, int data )
{
if ( head != NULL )
{
if ( head->data == data )
{
List *tmp = head;
head = head->next;
free( tmp );
}
else
{
head->next = remove_node( head->next, data );
}
}
return head;
}
void display_list( List *head )
{
if ( head != NULL )
{
printf( "%d ", head->data );
display_list( head->next );
}
}
int main(void)
{
const int N = 10;
List *head = NULL;
for ( int i = 0; i < N; i++ )
{
head = add_node( head, i );
display_list( head );
printf( "\n" );
}
for ( int i = N; i != 0; i-- )
{
head = remove_node( head, i - 1 );
display_list( head );
printf( "\n" );
}
return 0;
}
The program output is
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
0 1 2 3 4 5
0 1 2 3 4 5 6
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6
0 1 2 3 4 5
0 1 2 3 4
0 1 2 3
0 1 2
0 1
0

Resources