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.
Related
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
Im trying to create a simple programme to add a value to a linked list.
the code does compile with out errors.
Im getting a segmentation fault when trying to execute the file.
I tried to debug using printf statements, but I don't get any output anywhere.
could someone point out what im doing wrong.
typedef struct in separate .h file, include files also in separate .h file
typedef struct s_list
{
struct s_list *next;
void *data;
} t_list;
void list_push_front(t_list **begin_list, void *data)
{
t_list *l;
l = (t_list*)malloc(sizeof(t_list));
if(l == NULL){
printf("No allocation");
}
printf("%s\n", l->data);
l->data = data;
l->next = *begin_list;
*begin_list = l;
printf("%s\n", l->data);
}
int main(void)
{
t_list *k;
k = (t_list*)malloc(sizeof(t_list));
if(k == NULL){
printf("No allocation");
}
printf("allocation");
char s[] = "Woow!";
k->data = "Hello";
k->next->data = NULL;
// k->next->next->data = NULL;
list_push_front(&k, s);
return(0);
}
In the printf call
l = (t_list*)malloc(sizeof(t_list));
if(l == NULL){
printf("No allocation");
}
printf("%s\n", l->data);
you are trying to output non-initialized memory pointed to by the pointer l->data. So the function invokes undefined behavior. Remove this call of printf. It does not make sense.
Also in main this statement
k->next->data = NULL;
is incorrect and also invokes undefined behavior. It seems you mean
k->next = NULL;
As a general point, always compile with the -Wall -Werror flags and run your code frequently (every couple of lines). This should help avoid a lot of the problems here. Use valgrind, asan or gdb to detect and diagnose memory issues like the ones in this program.
k->next->data = NULL; is illegal because k->next is uninitialized.
printf("%s\n", l->data);, same problem. You must initialize a value before use.
Functions should not produce side effects like printing. It's OK for temporary debugging, but beyond that it makes for noisy programs and essentially unusable functions. If you want errors, print to stderr and exit or use return values such as an enum or NULL to indicate errors.
Always free allocated memory.
No need to cast the result of malloc.
Use consistent indentation and formatting.
A possible rewrite:
#include <stdio.h>
#include <stdlib.h>
typedef struct ListNode {
struct ListNode *next;
void *data;
} ListNode;
ListNode *list_create(void *data) {
ListNode *node = malloc(sizeof(*node));
if (!node) {
fprintf(stderr, "%s %d: malloc failed\n", __FILE__, __LINE__);
exit(1);
}
node->data = data;
node->next = NULL;
return node;
}
void list_push_front(ListNode **head, void *data) {
ListNode *node = list_create(data);
node->next = *head;
*head = node;
}
void list_free(ListNode *head) {
while (head) {
ListNode *dead = head;
head = head->next;
free(dead);
}
}
int main(void) {
ListNode *list = list_create("a");
list_push_front(&list, "b");
list_push_front(&list, "c");
for (ListNode *curr = list; curr; curr = curr->next) {
printf("%s\n", (char *)curr->data);
}
list_free(list);
return 0;
}
Why cant I assign a pointer to a double pointer's pointer? I get segmentation fault every time.
#include <stdio.h>
int main() {
int **pointer1, *pointer2, *pointer3, var;
var = 10;
pointer3 = &var;
pointer1 = &pointer3;
pointer2 = *pointer1; //correcting my mistake, so this is now correct?
return 0;
}
The code I was actually working on, practicing linked list:
#include <stdio.h>
#include <stdlib.h>
typedef struct node_t {
int num;
struct node_t *next;
} node_t;
void insert(int, node_t**);
int main(void) {
int list;
node_t **head, *temp;
*head = NULL;
while (scanf("%d", &list) != EOF) {
insert(list, head);
}
temp = *head;
/*while (temp != NULL) { //here is the problem, if I remove this
//I get segmentation fault but it runs
printf("%d ", temp->num); //runs fine when I include it
temp = temp->next;
}*/
return 0;
}
void insert(int list, node_t **head) {
node_t *temp = malloc(sizeof(node_t));
temp->next = (*head);
temp->num = list;
(*head) = temp;
}
Just like what I put in the code comment, the above version of my code gets segmentation fault when I compile it without the while loop. But weirdly enough, it works fine once I include the while loop. After fiddling around, I suspect the culprit to be the double pointer in which I tried to assign the secondary address into a regular pointer.
But this version actually runs fine:
#include <stdio.h>
#include <stdlib.h>
typedef struct node_t {
int num;
struct node_t *next;
} node_t;
void insert(int, node_t**);
int main(void) {
int list;
node_t *head, *temp;
head = NULL;
while (scanf("%d", &list) != EOF) {
insert(list, &head);
}
temp = head;
while (temp != NULL) {
printf("%d ", temp->num);
temp = temp->next;
}
return 0;
}
void insert(int list, node_t **head) {
node_t *temp = malloc(sizeof(node_t));
temp->next = (*head);
temp->num = list;
(*head) = temp;
}
Over here I passed the address into the linked list function and essentially I'm doing the same thing but without the double pointer.
On a side note, I have seen many different implementations of linked lists. Mine requires the double pointer because I'm using a void insert(int, **node_t), but there are versions which returns the address and updates the head: node_t* insert(int, *node_t) and Global linked list: void insert(int). Just wondering which versions are actually recommended, easier to debug and beginner friendly.
Your first example segfaults because *pointer1 (and pointer1 before it) isn't pointing to anything. It's an uninitialized pointer that points to random garbage data in memory.
Trying to dereference such a pointer (**pointer1 = 10;) results in a segfault.
A solution to make your first example work would be to allocate some memory for the data you're trying to store :
int **pointer1, *pointer2;
int *data = malloc(sizeof(int));
pointer1 = &data;
**pointer1 = 10;
pointer2 = *pointer1;
free(*pointer1); //or free(data)
When you do this:
**pointer1 = 10;
What this says is "take the address stored in pointer1, dereference that address, take the address stored there, dereference again, and store the value 10 at that location".
It looks something like this:
pointer1
------- ------- ------
| .--|---->| .--|--->| 10 |
------- ------- ------
You're getting a segfault because pointer1 doesn't currently point anywhere.
This could work if you do something like this:
int **pointer1, *pointer2, value;
value = 10;
pointer2 = &value;
pointer1 = &pointer2;
In the case of the two "real" code snippets, the problem with the first piece of code is that you pass head uninitialized to insert, which then subsequently dereferences head. This is the same problem as above. The same thing happens again in main because head is still uninitialized after calling list because it was passed by value. The second piece of code works because you pass the address of head to insert, so subsequently dereferenced it is valid.
I need to create the push method for a program that push an element into a stack. I have created this typedef:
typedef struct node{
int value;
struct node *next;
} Node;
With this snippet of code in my main:
Node *stackptr;
stackptr = NULL;
This is where I have a problem and am not sure exactly what is going on - In my push method im not sure if I am returning the updated pointer to the top of the stack. Im suppose to check if it is empty as well but I am going to get to that last. Here is the push() function:
void push(Node *stkptr, int i){
Node *temp;
temp = malloc(sizeof(Node));
temp->value = i;
temp->next = *stkptr;
return *stkptr = temp;
}
Hope this makes some sort of sense what I am trying to get across. Thanks for any advice you are able to give me. Hope all is well.
Last I am in need of fixing my int pop() function! I have to return the value of the node that was popped. I believe I am almost there - my compiler is still throwing errors. This is what I have so far:
int pop(Node** stkptr){
Node *temp;
temp = malloc(sizeof(Node));
if((*stkptr) == NULL){
fprintf(stderr, "The stack is empty. Pop is not allowed\n");
return 0;
}
else{
temp = *stkptr;
stkptr = *temp;
}
return stkptr;
free(temp);
}
However, the compiler is throwing the error:
incompatible types when assigning to type ‘struct Node **’ from type ‘Node’
warning: return makes integer from pointer without a cast
Can someone please help me fix my problem! Thanks!
There must be a lot of duplicates for this (for example, Implementing stack with linked list in C from the related questions section), but basically, you need to pass a pointer to a pointer into the function:
void push(Node **stkptr, int i)
{
Node *temp;
temp = malloc(sizeof(Node));
temp->value = i;
temp->next = *stkptr;
*stkptr = temp;
}
You also can't return a value from a function that returns void. You should also check that the memory allocation worked.
You'd call this from, for example, your main program:
Node *stack = NULL;
int i;
while (get_an_integer(&i) != EOF)
push(&stack, i);
where get_an_integer() is a hypothetical function that reads an integer from somewhere and assigns it to i, while returning a status (0 — got an integer; EOF — didn't get an integer).
An alternative design returns the new head of the stack from the function:
Node *push(Node *stkptr, int i)
{
Node *node;
node = malloc(sizeof(Node));
node->value = i;
node->next = stkptr;
return node;
}
with calling sequence:
Node *stack = NULL;
int i;
while (get_an_integer(&i) != EOF)
stack = push(stack, i);
A question about pop()
The pop() function appears to remove and destroy the first item on the stack, rather than returning it. However, there are a number of flaws in it, such as it allocates space, then overwrites the pointer with information from the stack, then returns before freeing the data. So, assuming that the demolition job is required, the code should be:
int pop(Node **stkptr)
{
assert(stkptr != 0);
Node *temp = *stkptr;
if (temp == NULL)
{
fprintf(stderr, "The stack is empty. Pop is not allowed\n");
return 0;
}
else
{
*stkptr = temp->next;
free(temp); // Or call the function to deallocate a Node
return 1;
}
}
This now returns 1 when successful and 0 when the stack was empty. Alternatively, if you wanted the value from the top of the stack returned rather than freed, then:
Node *pop(Node **stkptr)
{
assert(stkptr != 0);
Node *temp = *stkptr;
if (temp == NULL)
{
fprintf(stderr, "The stack is empty. Pop is not allowed\n");
return 0;
}
else
{
*stkptr = temp->next;
return temp;
}
}
Or, since you are told by the return value whether there was anything to pop, and printing in a library function can be objectionable, maybe even:
Node *pop(Node **stkptr)
{
assert(stkptr != 0);
Node *temp = *stkptr;
if (temp != NULL)
*stkptr = temp->next;
return temp;
}
Warning: none of the code has been submitted to a compiler for verification.
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.