inserting node (Binary search tree) C - c

I'm trying to insert a node in a binary search tree and I'm getting a little problem.
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
typedef struct Node{
char name[100];
struct Node *pGauche;
struct Node *pDroit;
}Node;
void getName(char[]);
void copy(Node **, Node *,char[]);
void menu(Node **);
void add(Node **);
void search(char[],Node**, Node **,Node **);
void print(Node **);
void inOrder(Node *);
void main(void)
{
Node *root = NULL;
menu(&root);
system("pause");
}
void menu(Node **root)
{
for (int i=0;i<10;i++)
{
add(root);
}
print(root);
}
void add(Node **root)
{
char name[100];
getName(name);
Node *p = NULL;
Node *savep = NULL;
search(name,root,&p,&savep);
copy(root,savep,name);
}
void search(char name[],Node **root, Node **p, Node **savep)
{
*p = *root;
while ((p == NULL) && (strcmp((*p)->name,name) != 0))
{
*savep = *p;
if (strcmp(name,(*p)->name) < 0)
*p = (*p)->pGauche;
else
*p = (*p)->pDroit;
}
}
void getName(char name[])
{
printf("What name do you want to add\n");
scanf("%s",name);
fflush(stdin);
}
void copy(Node **root, Node *savep, char name[])
{
Node *newp = (Node *) malloc(sizeof(Node*));
newp->pDroit = NULL;
newp->pGauche = NULL;
strcpy(newp->name,name);
printf("%s",newp->name);
if (*root == NULL)
*root = newp;
else
{
if (strcmp(name,savep->name) < 0)
savep->pGauche = newp;
else
savep->pDroit = newp;
}
free(newp);
}
void print(Node ** root)
{
Node *p = *root;
inOrder(p);
}
void inOrder(Node *p)
{
if (p != NULL)
{
inOrder(p->pGauche);
printf("%s\n",p->name);
inOrder(p->pDroit);
}
}
I know there are some really odd function and useless functions, but this just a "test" for a slightly bigger school project so it will get useful in time, right now I would just like to get the binary tree working !
So basically the problem is that I'm getting a "Access violation reading location" after I type in the second name... I'm guessing when doing the strcmp, but I'm really not sure :/
I'd really be glad if someone could help me getting this running :)

A couple of things to get you started. I haven't looked into it too deeply, so you will probably have to continue to drill down into more issues, but fix these things just to get you started:
In this code in search():
while ((p == NULL) && (strcmp((*p)->name,name) != 0))
The p parameter will never be NULL. So, the while loop is never entered. This means that savep would not get set to any value, and is NULL when you call copy() in your add() function. The copy() function then dereferences the invalid pointer reference, which caused the problem you observed.
You actually want to test to see if *p is NOT NULL. This allows you to legally dereference it.
while ((*p != NULL) && (strcmp((*p)->name,name) != 0))
Secondly, as hmjd identified, you do not allocate enough memory for your node inside copy().
Node *newp = (Node *) malloc(sizeof(Node*));
You are only allocating enough memory for one pointer, not for an entire node. Also, you should not cast the return value of malloc() when coding in C (it will hide a bug that can lead to a crash in the worst case).
Node *newp = malloc(sizeof(Node));
Thirdly, you need to retain the memory you allocate for your nodes rather than freeing them immediately after inserting it at the end of copy():
// I need this memory for my tree!
//free(newp);
If you call free() like you did, then your tree will be pointing into freed memory, and to access them would cause undefined behavior.
One minor thing: You shouldn't do fflush(stdin), as fflush() is only for output streams.

This is incorrect:
while ((p == NULL) && (strcmp((*p)->name,name) != 0))
and will result in a NULL pointer being dereferenced, which is undefined behaviour. Change to:
while (*p && strcmp((*p)->name,name) != 0)
This is incorrect:
Node *newp = (Node *) malloc(sizeof(Node*));
as it is only allocating enough for a Node*, when it needs to be allocating a Node. Change to:
Node *newp = malloc(sizeof(*newp));
and don't free() it in the same function as it is required later. free()ing the Node means the list has dangling pointers and dereferencing one is undefined behaviour, and a probable cause of the access violation.
Note:
fflush(stdin);
is undefined behaviour. From the fflush() reference page:
Causes the output file stream to be synchronized with the actual contents of the file. If the given stream is of the input type, then the behavior of the function is undefined.

Related

Segmentation Fault when checking if a node is empty in C

I have a function called isNull(), it checks whether the given node is SYSNULL, SYSNULL is essentially a pointer to null, not exactly important. When I call this function in a while loop from another function, I get a seg fault. The reason that I was told when asked was that I haven't dereferenced the pointer, node_ptr, yet. How do I dereference the pointer? And if that's not the issue, then how do I fix it? I've provided the code for the 2 functions, everything compiles without warning/error. Help would be greatly appreciated.
isNull:
int isNull(struct system *system, int *node_ptr) {
if(*node_ptr == SYSNULL) {
return 1;
}
else {
return 0;
}
}
appendItem:
void appendItem(struct system *system, struct List *list, void *src) {
int i;
int svoid = isEmpty(system, list);
while(svoid != 1) {
next(system, &i); //Calls a function that goes to next node.
i++;
}
}
next:
int next(struct system *system, int *node_ptr) {
struct Node *head = malloc(sizeof(struct Node));
struct Node *newNode = malloc(sizeof(struct Node));
if(head == NULL) {
printf("List is empty");
exit(0);
}
else {
newNode->next = *node_ptr;
return newNode->next;
}
free(head);
free(newNode);
}
The *node_ptr you are comparing to SYSNULL is an int, not a pointer.
The pointer would be node_ptr, if that is NULL, then dereferencing it as you do could explain the segfault.
Quoting John Bollingers comment (assuming it is OK):
And if you turn up your compiler's warning level, yet it still fails to at least emit a warning about this, then you should find a better compiler.

Does a node's behaviour change when it is a member of a struct?

I'm trying to learn how to use linked lists, so I've written myself a function to recursively go through a linked list and print a word stored in each node, but it's only printing the penultimate item and then repeating indefinitely. I've debugged this and I can see it's because the last node will satisfy n.next != NULL, so I wanted to change the condition to n != NULL to avoid this, but I get the error message: error: invalid operands to binary expression ('node' (aka 'struct node') and 'void *'). I've tried to search the error message on Google and SO but I can't explain why n.next != NULL compiles nicely but n != NULL doesn't. To me, I'd say n and n.next are both type node, but presumably my intuition is deceiving me somehow. Is it because n.next is a struct member that it's behavior changes, or am I on the wrong track?
I include the code below (function in question is at the bottom):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
char word[20];
struct node *next;
}
node;
void print (node n);
node *table[1];
int main(void)
{
// TODO
char word[20];
FILE *file = fopen("list", "r");
node *first = malloc(sizeof(node));
table[0] = first;
if (file != NULL)
{
while (fscanf(file, "%s", word) != EOF)
{
node *entry = malloc(sizeof(node));
if (entry != NULL)
{
strcpy (entry->word, word);
entry->next = first->next;
first->next = entry;
}
}
}
print(*first);
}
void print (node n)
{
while(n != NULL)
{
printf("%s\n", n.word);
print(*n.next);
}
}
To me, I'd say n and n.next are both type node
Not so; n is a node, but n.next is type node *, i.e. a pointer to a node. Pointers can be null but structs cannot.
Thus the object passed to print is guaranteed valid. (If first were a null pointer then print(*first) would already have crashed, or "caused undefined behavior", before you even entered print.)
It's also not necessary to have a loop in print, since the recursion handles the list traversal. Indeed, if you try to keep the loop as it is, it's an infinite loop, because nothing in the body modifies the value of n.
I would write:
void print (node n)
{
printf("%s\n", n.word);
if (n.next != NULL)
print(*n.next);
}
However this approach is not really idiomatic, and it's also not very efficient, since passing structs by value tends to involve unnecessary copying and stack usage. It'd be more common, as dbush suggests, to have a version that takes pointers:
void print(const node *np)
{
if (np)
{
printf("%s\n", np->word);
print(np->next);
}
}
which you then call as print(first);.
A next good exercise would be to try to write a version of print that doesn't use recursion, since that will allow you to handle very long lists that might exceed your stack size.
there are mainly to problems:
don't forget to initialize the value after malloc, or they can be anything, especially the next will not be NULL as you expected.
node *first = (node*)malloc(sizeof(node));
first->word[0] = '\0';
first->next = NULL;
node *entry = (node*) malloc(sizeof(node));
entry->word[0] = '\0';
entry->next = NULL;
I prefer to use calloc than malloc
node* first = (node*)calloc(1, sizeof(node));
assert(first);
node* entry = (node*)calloc(1, sizeof(node));
assert(entry);
in the function of print
void print (node* n)
{
if(n != NULL)
{
printf("%s\n", n->word);
print(n->next);
}
}
since you call print recursively, if should be used rather than while

runtime error: null pointer passed as argument 1, which is declared to never be null

I wrote a program that creates Linkedlists with two values.
It worked when I just had int values in it but now that I added char* this error messages shows
runtime error: null pointer passed as argument 1, which is declared to never be null
As mentioned before this worked fine until I added char* to the constructor and the struct. Not sure where it goes wrong as the error seems to come from different lines in the code everytime I run it... So what do i need to change ?
#include <stdio.h>
#include <cs50.h>
#include <string.h>
typedef struct node {
int val;
char* name;
struct node *next;
} node_t;
void addFirst(int value, char* word, node_t** nd) {
//initialize new node, allocate space, set value
node_t * tmp;
tmp = malloc(sizeof(node_t));
tmp->val = value;
strcpy(tmp->name, word);
//let the new nodes next pointer point to the old head
tmp->next = *nd;
//Make tmp the head node
*nd = tmp;
}
int findItem(int value,char* word, node_t *nd) {
if(nd->val == value)
return 0;
while(nd->next != NULL) {
if(nd->val == value && strcmp(word, nd->name) == 0)
return 0;
if(nd->next != NULL)
nd = nd->next;
}
return -1;
}
int main (void) {
node_t *head = malloc(sizeof(node_t));
head->val = 0;
strcpy(head->name, "");
head->next = NULL;
addFirst(15, "word", &head);
addFirst(14,"word2", &head);
printf("%i \n", findItem(15, "word", head));
}
The problem is in strcpy(head->name, "");. Here, you;re trying to use the memory location pointer to by head->name, but you never assigned a valid memory to it.
You need to make sure that the pointer points to a valid memory location, before you write to / read from that memory location. Attempt to access invalid memory invokes undefined behavior.
This is applicable for other uninitialized instances of name, too.
If you can live with POSIX standard, instead of strcpy(), you can make use of strdup()

Why is my linked list only printing last entry?

I'm trying to read specific lines from a file and add it to a linked list and then print it out.
Code below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list {
int uid;
char* uname;
struct list* next;
}node;
void push(node ** head, int uid ,char* uname) {
node * new_node;
new_node = malloc(sizeof(node));
new_node->uid = uid ;
new_node->uname=uname;;
new_node->next = *head;
*head = new_node;
}
void print_list(node *head) {
node * current = head;
while (current != NULL) {
printf("%u:%s\n", current->uid,current->uname);
current = current->next;
}
}
int main(int argc, char **argv){
node *current=NULL;
FILE *fp=fopen(argv[1],"r" );
if (fp==NULL){
perror("Failed to open file");
exit(EXIT_FAILURE);
}
char s[1024];
const char token[2]=":";
char *stoken;
while(!feof(fp)){
int count=0;
int tempint;
char* tempchar=malloc(sizeof(char));
fgets(s, 1024, fp);
stoken = strtok(s,token);
current=malloc(sizeof(node));
while(stoken != NULL){
if (count==0){
tempchar=stoken;
}
if (count==2){
sscanf(stoken,"%d",&tempint);
}
count++;
stoken=strtok(NULL,token);
}
push(&current,tempint,tempchar);
}
fclose(fp);
print_list(current);
}
My problem is when print_list is ran the only thing who gets printed is the last entry.
For this input :
hello:asd:123:foo:ar
hi:proto:124:oo:br
hey:qwe:321:fo:bar
the only thing which gets printed is
321:hey
is it my push which is wrong or my print_list?
The problem is the way you are treating the result of strtok: you are setting its value right into the node, instead of copying it.
Make a copy of name when adding a node:
void push(node ** head, int uid ,char* uname) {
node * new_node;
new_node = malloc(sizeof(node));
new_node->uid = uid;
new_node->uname=malloc(strlen(uname)+1);
strcpy(new_node->uname, uname);
new_node->next = *head;
*head = new_node;
}
You should also look at the way that you are using tempchar in the main function. You allocate a space for a single character to it, which gets written over with the result of strtok, leaking the malloc-ed memory.
It's because you always overwrite head in the push() function, you should make it NULL initially and then check if it's NULL the first time and assign to it the first node, and then don't reassing anything to it, your program has a memory leak because of this too.
Also you are malloc()ing the node outside the function and then inside the function again,which causes another memory leak.
You should also check if malloc() returns NULL which indicates an error like when the system runs out of memory, dereferencing a NULL pointer is undefined behavior.
And a final note, you must check the return value of scanf() before accessing the target variables, or that would again cause undefined behavior.
change like as follows
char* tempchar;//=malloc(sizeof(char));
fgets(s, 1024, fp);
stoken = strtok(s,token);
//current=malloc(sizeof(node));//don't update like this
while(stoken != NULL){
if (count==0){
tempchar=strdup(stoken);//malloc and strcpy

Freeing a pointer (to a void*) inside of a struct

C newbie here, and I can't seem to figure this one out. So I'm starting to implement a linked-list (just something basic so I can wrap my head around it) and I've hit a snag. The program runs fine, but I can't free() the data stored in my struct.
Here's the source:
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node* next;
void* data;
size_t data_size;
};
typedef struct node node;
node* create_node(void* data, size_t size)
{
node* new_node = (node*)malloc(sizeof(node));
new_node->data = (void*)malloc(size);
new_node->data = data;
new_node->next = NULL;
return new_node;
}
void destroy_node(node** node)
{
if(node != NULL)
{
free((*node)->next);
//this line here causes the error
free((*node)->data);
free(*node);
*node = NULL;
printf("%s\n", "Node destroyed!");
}
}
int main(int argc, char const *argv[])
{
float f = 4.325;
node *n;
n = create_node(&f, sizeof(f));
printf("%f\n", *((float*)n->data));
if (n->next == NULL)
printf("%s\n", "No next!");
destroy_node(&n);
return 0;
}
I get this message in the program output:
malloc: *** error for object 0x7fff5b4b1cac: pointer being freed was not allocated
I'm not entirely keen on how this can be dealt with.
This is because when you do:
new_node->data = data;
you replaces the value put by malloc just the line before.
What you need is to copy the data, see the function memcpy
node* create_node(void* data, size_t size)
...
new_node->data = (void*)malloc(size);
new_node->data = data;
Here, (1) you are losing memory given by malloc because the second assignment replaces the address (2) storing a pointer of unknown origin.
Number two is important because you can't guarantee that the memory pointed to by data was actually malloced. This causes problems when freeing the data member in destroy_node. (In the given example, an address from the stack is being freed)
To fix it replace the second assignment with
memcpy (new_node->data, data, size);
You also have a potential double free in the destroy_node function because the next member is also being freed.
In a linked list, usually a node is freed after being unlinked from the list, thus the next node shouldn't be freed because it's still reachable from the predecessor of the node being unlinked.
While you got an answer for the immediate problem, there are numerous other issues with the code.
struct node {
struct node* next;
void* data;
What's up with putting * next to type name? You are using it inconsistently anyway as in main you got node *n.
size_t data_size;
};
typedef struct node node;
node* create_node(void* data, size_t size)
{
node* new_node = (node*)malloc(sizeof(node));
What are you casting malloc for? It is actively harmful. You should have used sizeof(*new_node). How about checking for NULL?
new_node->data = (void*)malloc(size);
This is even more unnecessary since malloc returns void * so no casts are necessary.
new_node->data = data;
The bug already mentioned.
new_node->next = NULL;
return new_node;
}
void destroy_node(node** node)
{
if(node != NULL)
{
How about:
if (node == NULL)
return;
And suddenly you get rid of indenation for the entire function.
free((*node)->next);
//this line here causes the error
free((*node)->data);
free(*node);
*node = NULL;
printf("%s\n", "Node destroyed!");
What's up with %s instead of mere printf("Node destroyed!\n")? This message is bad anyway since it does not even print an address of aforementioned node.

Resources