I wrote a piece of code that recursively finds the smallest string in a tree and deletes it. However, printing the tree after deleting the node returns (null).
static char* findMinimum(TreeNodePtr treePtr){
if(treePtr->left == NULL){
printf("Minimum node is %s\n", treePtr->item);
char * temp = treePtr->item;
(treePtr)->item = NULL;
return(temp);
}
else{
findMinimum(treePtr->left);
}
}
I THINK this function works since it deletes the minimum value even using different strings. Should I write a condition to make sure NULL pointers won't get printed? Just in case, here's the print function as well:
static void printTree(TreeNodePtr treePtr) {
if (treePtr != NULL) {
level++;
printTree(treePtr->left);
printf(">%*s%s\n", level*5, "", treePtr->item);
printTree(treePtr->right);
level--;
}
}
I see couple of problems in your findMinimum function:
1) What do you return in else-case in findMinimum? I guess you forgot to add return:
static char* findMinimum(TreeNodePtr treePtr){
if(treePtr->left == NULL){
printf("Minimum node is %s\n", treePtr->item);
char * temp = treePtr->item;
(treePtr)->item = NULL;
free(treePtr->item);
return(temp);
}
else{
return findMinimum(treePtr->left); // added return
}
}
2) Is your tree a binary search tree? Consider what happens in this case:
root-node
/ \
smallest largest
\
not-smallest
You should rehang not-smallest node instead of smallest.
3) Why do you free NULL?
(treePtr)->item = NULL;
free(treePtr->item);
You're deleting the smallest node without changing the child of its parent. If you delete a node, you should also change its parent to point to NULL. Note that setting treePtr->item to NULL doesn't accomplish this as treePtr->left points to a TreeNodePtr, not to its item member.
This function
static char* findMinimum(TreeNodePtr treePtr){
if(treePtr->left == NULL){
printf("Minimum node is %s\n", treePtr->item);
char * temp = treePtr->item;
(treePtr)->item = NULL;
free(treePtr->item);
return(temp);
}
else{
findMinimum(treePtr->left);
}
}
does not make sense.
For starters this part or the code
else{
findMinimum(treePtr->left);
}
returns nothing. So the function already have undefined behavior.
Also consider these statements
(treePtr)->item = NULL;
free(treePtr->item);
The call of free does nothing.
Otherwise if you will exchange the statements when the function returns a pointer to already deleted string. And again the progarm will have undefined behavior.
Also it is unclear how the function will behave when it will be called the second time when the smallest string was already deleted.
And you have to dynamically create a copy of the smallest string that will be returned from the function.
I would suggest the following function implementation (without testing).
static char * findMinimum( TreeNodePtr treePtr )
{
if ( treePtr == NULL || treePtr->item == NULL ) return NULL;
if ( treePtr->left == NULL || treePtr->left->item == NULL )
{
char *s = malloc( strlen( treePtr->item ) + 1 );
strcpy( s, treePtr->item );
free( treePtr->item );
treePtr->item = NULL;
return s;
}
else
{
return findMinimum( treePtr->left );
}
}
Related
I'm trying to do a project to check if the word in a list is repeated, but it seens AuxLista allways returns temp-palavra as null?
void AuxLista(Lista *L, char tmp_word) {
if (!L) return;
Lista *temp = L;
printf("\n");
while (temp != NULL)
{
if(temp->palavra == tmp_word){
printf("%s Está repetida. ", temp->palavra);
}
printf("TESTE %s", temp->palavra);
temp = temp->prox;
}
}
Lista *criarLista(char *word){
Lista *result = malloc(sizeof(Lista));
AuxLista(result, word);
result->palavra = word;
result->prox = NULL;
if (result->NOCORRENCIAS == NULL) result->NOCORRENCIAS = 1;
else result->NOCORRENCIAS = result->NOCORRENCIAS + 1;
return result;
}
List item
Your AuxLista function is void -- it doesn't return anything.
Also, be aware that the result of malloc() is uninitialized memory. If you don't set each byte to a value, then you must assume that the byte has the worst possible value it could have. You might consider using calloc or passing the memory to memset to initialize everything to 0.
And you should check that malloc didn't return NULL, which it will do if you aren't looking.
Finally, don't use NULL to mean 0. Your NOCORRENCIAS appears to be an integer (because you set it to 1) which means you would normally be checking it against 0 rather than NULL. But that whole if/else appears to be wasted -- you could probably just do result->NOCORRENCIAS += 1 and handle the zero/non-zero cases the same.
I have the task of going through a binary search tree and collecting the keys in every node and storing them in an array. After this, I have to set the last element of this array as NULL. This is all done inside a function, which then returns this array of *char.
I believe the part about collecting the keys and storing them in the array is working well, as I've tested that enough. However, I'm not able to define the last element of the array as NULL correctly. I thought it should be done like this:
list_keys[tree_size(tree)] = NULL;
However, after some printf's, I realized that this was cleaning my tree. When I print tree_size(tree) before this line, it gives me the size of the tree correctly. However, when I do it after that line, it gives me 0. I don't believe that the problem is in the function tree_size() because when I attempt to access an element of the tree before that line, it works well, but after the line, I get a Segmentation fault (core dumped) error, probably due to trying access something that doesn't exist anymore.
I have no idea what's wrong, so any help is appreciated. Thanks in advance.
EDIT:
The tree is of the type tree_t and it's defined as:
struct tree_t {
struct entry_t *entry;
struct tree_t *right_child;
struct tree_t *left_child;
};
The tree_size() is defined as:
int tree_size(struct tree_t *tree) {
if (tree->entry != NULL) {
//if two children exist
if (tree->left_child != NULL && tree->right_child != NULL) {
return 1 + tree_size(tree->left_child) + tree_size(tree->right_child);
}
//there's a right child and there isnt a left child
if (tree->right_child != NULL && tree->left_child == NULL) {
return 1 + tree_size(tree->right_child);
}
//there's a left child and there isnt a right child
if (tree->left_child != NULL && tree->right_child == NULL) {
return 1 + tree_size(tree->left_child);
}
//there are no children
if (tree->left_child == NULL && tree->right_child == NULL) {
return 1;
}
}
//if the entry is empty
return 0;
}
Basically, what I'm doing right now is:
First, I define list_keys and allocate memory:
char **list_keys;
list_keys = (char *)malloc((tree_size(tree)+1)*sizeof(char));
Then, I call an auxiliary function tree_get_keys_aux(tree, list_keys, 0) that will do the initial part I mentioned. It is defined as:
void tree_get_keys_aux(struct tree_t *tree, char **list_keys, int index) {
//N
list_keys[index] = (char *)malloc((strlen(tree->entry->key))*sizeof(char)); //allocating memory for each string that I want to add to the list
strcpy(list_keys[index],tree->entry->key); //copying the content
index = index + 1;
//L
if (tree->left_child != NULL) {
tree_get_keys_aux(tree->left_child, list_keys, index);
}
//R
if (tree->right_child != NULL) {
tree_get_keys_aux(tree->right_child, list_keys, index);
}
return;
}
Then, I do the line that's bringing me problems,
list_keys[tree_size(tree)] = NULL;
And lastly,
return list_keys;
Firstly,
list_keys = (char *)malloc((tree_size(tree)+1)*sizeof(char));
is wrong. The elements are char*, so you have to allocate for that or you will cause out-of-range access.
It should be:
list_keys = malloc((tree_size(tree)+1)*sizeof(char*));
or
list_keys = malloc((tree_size(tree)+1)*sizeof(*list_keys));
See also: c - Do I cast the result of malloc? - Stack Overflow
Secondly,
list_keys[index] = (char *)malloc((strlen(tree->entry->key))*sizeof(char)); //allocating memory for each string that I want to add to the list
strcpy(list_keys[index],tree->entry->key); //copying the content
is wrong. You have to allocate one more element for terminating null-character.
It should be:
list_keys[index] = malloc((strlen(tree->entry->key) + 1)*sizeof(char)); //allocating memory for each string that I want to add to the list
strcpy(list_keys[index],tree->entry->key); //copying the content
Thirdly, tree_get_keys_aux is not recoginizing number of elements in left child and data from left child will be overwritten by data from right child.
To avoid this overwriting, you can use tree_size to determint the tree size and advance index according to that.
//L
if (tree->left_child != NULL) {
tree_get_keys_aux(tree->left_child, list_keys, index);
index += tree_size(tree->left_child); // add this
}
//R
if (tree->right_child != NULL) {
tree_get_keys_aux(tree->right_child, list_keys, index);
}
I'm reading and saving strings from a formatted file and for some reason I found out sscanf() changes testa_e->ident contents.
I have put some printf around and I found that the problem occurs right after sscanf(); I have also checked addresses of temp2, temp5 and testa_e by printing them but they are different.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define string 30
#define line 100
typedef const char *identifier;
struct nodo_id {
identifier ident;
struct nodo_id *next;
};
typedef struct nodo_id nodo_id;
nodo_id *testa_e = NULL;
void addent(const char *id_ent) {
if (testa_e == NULL) {
testa_e = malloc(sizeof(nodo_id));
testa_e->ident = id_ent;
testa_e->next = NULL;
} else {
nodo_id *curs = testa_e;
while (curs != NULL) {
curs = curs->next;
}
curs = malloc(sizeof(nodo_id));
curs->ident = id_ent;
curs->next = NULL;
}
}
int main() {
char temp[line];
char temp2[string];
char temp5[string];
fgets(temp, line, stdin);
while (strncmp(temp, "end", 3) != 0) {
if (strncmp(temp, "addent", 6) == 0) {
if (testa_e != NULL)
printf("\nbefore sscanf: %s\n", testa_e->ident);
sscanf(temp, "%s %s", temp5, temp2);
if (testa_e != NULL)
printf("\nafter sscanf: %s\n", testa_e->ident);
addent(temp2);
}
fgets(temp, line, stdin);
}
}
This code here reproduces the exact same problem; after launch write addent firstword and addent secondwordon terminal and right around sscanf it should show you that testa_e->ident content has changed, I'd like to know why and how to fix this, because I seriously have no idea...
In the function addent this loop
while(curs!=NULL){
curs=curs->next;
}
iterates until curs is equal to NULL.
Then you are changing the pointer
curs=malloc(sizeof(nodo_id));
curs->ident=id_ent;
curs->next=NULL;
The list itself was not changed. You changed only the local variable curs.
Change the loop the following way
while ( curs->next != NULL ){
curs = curs->next;
}
and then
curs->next = malloc( sizeof( nodo_id ) );
curs->next->ident = id_ent;
curs->next->next = NULL;
The other problem is that you are using pointers to a local array
char temp2[string];
//...
addent(temp2);
So the last that will be stored in the array will be pointed to by all nodes. You need to allocate dynamically memory for each string that will be stored in the list and assign the address to the data member ident. In this case you have to remove the qualifier const from its declaration.
Take into account that it is a bad idea to make a function depends on a global variable,
A better definition of the function addent can look the following way
struct nodo_id{
char *ident;
struct nodo_id* next;
};
typedef struct nodo_id nodo_id;
int addent( nodo_id **head, const char *id_ent )
{
nodo_id *new_nodo_id = malloc( sizeof( nodo_id ) );
int success = new_nodo_id != NULL;
if ( success )
{
new_nodo_id->ident = malloc( strlen( id_ent ) + sizeof( ( char )'\0' ) );
success = new_nodo_id->ident != NULL;
if ( ! success )
{
free( new_nodo_id );
}
else
{
strcpy( new_nodo_id->ident, id_ent );
new_nodo_id->next = NULL;
while ( *head != NULL ) head = &( *head )->next;
*head = new_nodo_id;
}
}
return success;
}
And the function can be called like
addent( &testa_e, temo2 );
Why in the function there is used the pointer to pointer to the head?
First of all if we want to change the original head we need to pass it by reference. Secondly in the loop
while ( *head != NULL ) head = &( *head )->next;
again the data member next of the last node is pointed to by the pointer. So we are changing not the local variable curs as in your implementation of the function but the data member next of the last node. So we are changing the list itself.
Pay attention to that defining such a typedef as
typedef const char* identifier;
is a bad practice.
The main problem is (besides the one #VladFromMoscow addressed in his answer), that in addent() you only store the pointer id_ent in your struct:
curs->ident=id_ent;
But that is nothing else but the address of temp2, so if you copy something else into temp2 by calling sscanf() you'll see the new value in testa_e->ident too.
Change the line form above to
curs->ident=strdup(id_ent);
to create a copy.
And don't forget to call free(curs->ident) when before you are freeing curs
I don't know why I can read the Linked list without problems in LABEL : 1 ; but the program just crashes and print grabage in the LABEL : 0 ;
In other terms, why the linked list works fine inside the lecture function , but not outside it ?
Here is my code :
/* including libraries */
#define V 20
typedef struct DATA{
char* NomP;char* NomA;
struct DATA *Next;
}DATA;
// Prototypes .
int main(void)
{
char FileName[V];
puts("Data file ? : ");gets(FileName);
FILE* fs = fopen(FileName,"r"); // Check if fs is NULL
DATA *HEAD = MALLOC(sizeof (DATA)); int len = lecture_data(fs,HEAD);
print_data(HEAD,len); //LABEL : 0
return 0;
}
int lecture_data(FILE *fs,DATA *ROOT)
{
char cNom[V],cArticle[V];
int eofs=0;int i=0;
while(!eofs)
{
DATA *Data = MALLOC(sizeof (DATA));
fscanf(fs,"%s %s",cNom,cArticle);
Data->NomA = MALLOC(strlen(cArticle)+1);
Data->NomP = MALLOC(strlen(cNom)+1);
strcpy(Data->NomA,cArticle);
strcpy(Data->NomP,cNom);
if( i==0 )
{
Data -> Next = NULL ;
ROOT = Data ;
}
else
{
DATA* Ptr = ROOT ;
while( (Ptr->Next) != NULL )
{
Ptr = (Ptr -> Next);
}
Data -> Next = NULL ;
Ptr -> Next = Data ;
}
i++;
eofs = feof(fs) ;
// check ferror(fs) here
}
puts("Start of reading :");
print_data(ROOT,len); // LABEL : 1
puts("End Of Reading ");
fclose(fs);
return i;
}
Here is the printing function :
void print_data(DATA *L_ROOT,int len)
{
int i = 0 ;
DATA* LINK;
LINK = L_ROOT;
while( LINK != NULL )
{
printf("%d : DATA->NomA : %s\n",i,LINK->NomA);
printf("%d : DATA->NomP : %s\n",i,LINK->NomP);
LINK = LINK -> Next ;
i++;
}
}
You're allocating data for the root of the list in the main function, and pass that to the function so that it may populate the list, but the first time you allocate an element you overwrite the ROOT pointer value.
this makes you lose the only connection between the function and the outside world (since the return value is just a number), so the HEAD value in main() is left pointing at nothing meaningful (because your function never uses it), while the list remains allocated in some memory location that no one outside is pointing to, which means it's lost. Running valgrind would have been able to identify this.
You can fix that by changing the (i==0) case from -
ROOT = Data ;
into
ROOT->next = Data ;
but make sure you're ignoring the data of the root node later on.
p.s. - using capitalized variables and types is not considered a good idea (it's mostly reserved for macros). It also makes your code look like you're shouting :)
The (main) problem is that lecture_data doesn't use it's input parameter (ROOT) for storage of the linked list, nor does it return the internal generated list. The correct way to handle this is to have ROOT reference the calling scope's parameter so that it can update it's reference as necessary.
int main(void)
{
char FileName[V];
puts("Data file ? : ");gets(FileName);
FILE* fs = fopen(FileName,"r"); // Check if fs is NULL
DATA *HEAD = NULL;
int len = lecture_data(fs, &HEAD);
print_data(HEAD); //LABEL : 0
return 0;
}
int lecture_data(FILE *fs,DATA **ROOT)
{
char cNom[V],cArticle[V];
int i=0;
DATA *current = *ROOT; // grab the passed in reference
while(!feof(fs))
{
if(fscanf(fs,"%s %s",cNom,cArticle) <= 0) // This call is only successful if the return value is > 0
{
// check ferror(fs) here
continue; // Can also "break;" here, essentially, it's eof already
}
DATA *Data = MALLOC(sizeof (DATA));
Data->NomA = MALLOC(strlen(cArticle)+1);
Data->NomP = MALLOC(strlen(cNom)+1);
strcpy(Data->NomA,cArticle);
strcpy(Data->NomP,cNom);
if(NULL == current) // ROOT was uninitialized before the call
{
Data -> Next = NULL;
*ROOT = Data;
}
else
{ // We don't need to iterate the list in every step.
Data->Next = current->Next; // This part allows the function to insert nodes in the middle / end of an existing list
current->Next = Data;
current = Data;
}
i++;
}
puts("Start of reading :");
print_data(ROOT); // LABEL : 1
puts("End Of Reading ");
fclose(fs);
return i;
}
Note: print_data didn't do anything with the len parameter, so no need passing it in at all.
This solution is not wasteful in terms of "empty" nodes in the list (as opposed to having an empty head to ignore), and is suitable both for initializing the list from scratch AND for cases where you need to append / insert into an existing list.
I have 2 files: dictionary and sample.
void print_table (Table);
void print_stats (Table);
Several problems:
- You are always returning false from find Fixed by user
- You are always adding a print out of 'not found' whenever the root of the search isn't a match.
else if(key<head->element)
{ printf("not found");
return search(key, head->left);
And the bigger two problems
You are in C language and key and head->element are both const char* or char*; you can't use the == operator on them. That will only work if the pointers point to the same address. You want to use strcmp instead.
You don't want to compare key to head->left; you probably mean to compare to head->left->element. Otherwise you are comparing a char* to a node*. But again strcmp simplifies all of this, as you actually don't need to and shouldn't do this check here; particularly as head->left might itself be NULL.
As in below:
struct node *search( Key_Type key, struct node *head )
{
if ( head != NULL)
{
//note change to strcmp
int res = strcmp( key, head->element );
if ( !res )
{
printf("found");
return head;
}
else if( res < 0 ) //note change to strcmp.
{
printf( "not found" );
return search( key, head->left );
}
else
{
printf( "found3" );
return search( key, head->right );
}
}
else
return FALSE;
}