#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef struct _listnode
{
int item;
struct _listnode *next;
} ListNode;
int search(ListNode *head, int value);
void printList(ListNode *head);
int main()
{
ListNode *head = NULL, *temp = NULL;
int i = 0;
int value = 0;
while (1)
{
printf("Enter a integer: ");
scanf("%d", &i);
if (i == -1)
break;
if (head == NULL)
{
head = malloc(sizeof(ListNode));
temp = head;
}
else
{
temp->next = malloc(sizeof(ListNode));
temp = temp->next;
}
temp->item = i;
}
printList(head);
printf("Enter the value to search for: ");
scanf("%d", &value);
printf("Value of %d found in index %d",value,search(&head, value));
return 0;
}
void printList(ListNode *head)
{
while (head != NULL)
{
printf("%d ", head->item);
head = head->next;
}
printf("\n");
}
int search(ListNode *head, int value)
{
if (head == NULL)
return NULL;
if (head->item != value)
{
head = head->next;
}
return value;
}
I am trying to search a value inside a LinkedList and print out the index of the node when the value is found. But after my printlist, my program just shut down, I did not even reach to the part that require me to enter the value I want to search. Is there something wrong with my printList?
First of all, you should check the return value of scanf() - it returns the number of items successfully matched and assigned. Only after checking the return value can you be sure that the values you use are valid.
The problem, however, is that you never terminate the list properly, that is, you never set the last node's next to NULL. Try to add this after the while:
temp->next = NULL;
Personally, though, I'd advice against doing so. In general, it is more elegant if the list itself is in a consistent state after each iteration of the loop. So, this is what I suggest instead:
while (1)
{
printf("Enter a integer: ");
if (scanf("%d", &i) != 1) {
/* Deal with invalid input... */
}
if (i == -1)
break;
ListNode *new_node;
if ((new_node = malloc(sizeof(*new_node))) == NULL) {
/* Deal with memory exhaustion */
}
new_node->item = i;
new_node->next = NULL;
if (head == NULL)
head = new_node;
else
temp->next = new_node;
temp = new_node;
}
That makes temp work as a pointer to the previous node, so you might want to rename it to prev. Note the check for the return value of scanf() and malloc(), as well as the operand to sizeof: it is a good idea not to hardcode the type when using sizeof for maintenance reasons. Finally, notice, if you will, that there is now a single call to malloc(). This is conceptually easier to understand, since a new node is allocated in the same place in the code, regardless of head being valid or not.
Also, your search() function is broken. It assumes that if value is not the first node's value, then it is the second - not what you want. Also, you are not returning the index of the node, instead, you are returning the value itself. In fact, there's a situation where you return NULL (?!). I doubt that this compiles without warnings.
You need something like this instead:
int search(ListNode *head, int value)
{
int res = 0;
for (; head != NULL && head->item != value; head = head->next, res++)
; /* Intentionally left blank */
if (head == NULL)
return -1;
else
return res;
}
You don't put temp->next to NULL after this line temp = temp->next; in the list creation so it can be NULL or at any other value. When you iterate the list in printList() you reach this random value pointer and you have a segfault.
Related
I am currently working on a program based on linked-list. But my delete function causes crashes on my program. I want to allow users to delete a flight by it's fligt number. But I don't know what causes crash. How to fix this? Thanks
struct flight {
int number;
char source[20];
char destination[20];
struct flight* next;
};
void enter();
void display();
void delete();
int count();
typedef struct flight NODE;
NODE* head_node, * first_node, * temp_node = 0, * prev_node, next_node;
int data;
char data2[20], data3[20];
void delete()
{
temp_node = (NODE*)malloc(sizeof(NODE));
temp_node = first_node;
int counter, flightno, j;
temp_node->number = data;
counter = count();
printf("\nEnter flight number to delete: \n");
scanf("%d", &flightno);
for (j = 0; j <= counter; j++)
{
if (flightno == data) {
temp_node = temp_node->next;
first_node = temp_node;
printf("\nFlight log deleted.\n");
}
else
{
printf("Flight number not found.");
}
}
}
int count()
{
int count = 0;
temp_node = first_node;
while (temp_node != 0) {
count++;
temp_node = temp_node->next;
}
return count;
}
Short answer: Avoid global variables!
In your delete function you set the value of the global variable temp_node.
Then you call the function count. In count you also use the global variable temp_node. You change it until it has the value NULL.
Then back in the delete function, you do:
temp_node = temp_node->next;
Dereference of a NULL pointer! That is real bad and crashes your program.
So to start with: Get rid of all global variables
As an example, your count function should be:
int count(NODE* p)
{
int count = 0;
while (p != NULL) {
count++;
p = p->next;
}
return count;
}
and call it like: counter = count(first_node);
And your delete function could look like:
NODE* delete(NODE* first_node) { ... }
That said ...
The principle in your delete function is wrong. You don't need to count the number of nodes. Simply iterate until you reach the end, i.e. next is NULL.
Further - why do you malloc memory in the delete function? And why do you overwrite the pointer just after malloc? Then you have a memory leak.
temp_node = (NODE*)malloc(sizeof(NODE)); // WHY??
temp_node = first_node; // UPS... temp_node assigned new value.
// So malloc'ed memory is lost.
Now - what happens when you find the matching node:
if (flightno == data) {
temp_node = temp_node->next;
first_node = temp_node; // UPS.. first_node changed
printf("\nFlight log deleted.\n");
}
Then you change first_node. So all nodes before the current node is lost! That's not what you want. You only want to change first_node when the match is on the very first node in the linked list.
Then: for (j = 0; j <= counter; j++) --> for (j = 0; j < counter; j++) But as I said before... don't use this kind of loop.
Use something like:
while (temp_node != NULL)
{
...
temp_node = temp_node->next;
}
BTW: Why do you do a print out in every loop? Move the negative print out outside the loop.
A delete function can be implemented in many ways. The below example is not the most compact implementation but it's pretty simple to understand.
NODE* delete(NODE* head, int value_to_match)
{
NODE* p = head;
if (p == NULL) return NULL;
// Check first node
if (p->data == value_to_match)
{
// Delete first node
head = head->next; // Update head to point to next node
free(p); // Free (aka delete) the node
return head; // Return the new head
}
NODE* prev = p; // prev is a pointer to the node before
p = p->next; // the node that p points to
// Check remaining nodes
while(p != NULL)
{
if (p->data == value_to_match)
{
prev->next = p->next; // Take the node that p points to out
// of the list, i.e. make the node before
// point to the node after
free(p); // Free (aka delete) the node
return head; // Return head (unchanged)
}
prev = p; // Move prev and p forward
p = p->next; // in the list
};
return head; // Return head (unchanged)
}
and call it like:
head = delete(head, SOME_VALUE);
You are probably making an extra loop in your delete function. You should check if you are deleting an node which isn't part of your linked list.
Here's my program for searching an element in a linked list. I am being told there is an infinite loop in my code. I don't know where. The program works on my end and it doesn't keep looping for me. I really can't figure it out. If anyone has any suggestions or ideas on what part of my code I should look at to fix the issue please let me know. I'm truly stumped.
struct node
{
int a;
struct node *next;
};
void generate(struct node **head, int num)
{
int i;
struct node *temp;
for (i = 0; i < num; i++)
{
temp = (struct node *)malloc(sizeof(struct node));
temp->a = rand() % num;
if (*head == NULL)
{
*head = temp;
temp->next = NULL;
}
else
{
temp->next = *head;
*head = temp;
}
printf("%d ", temp->a);
}
}
void search(struct node *head, int key, int index)
{
while (head != NULL)
{
if (head->a == key)
{
printf("Key found at Position: %d\n", index);
}
search(head->next, key, index - 1);
}
}
void delete(struct node **head)
{
struct node *temp;
while (*head != NULL)
{
temp = *head;
*head = (*head)->next;
free(temp);
}
}
int main()
{
struct node *head = NULL;
int key, num;
printf("Enter the number of nodes: ");
scanf("%d", &num);
generate(&head, num);
printf("\nEnter key to search: ");
scanf("%d", &key);
search(head, key, num);
delete(&head);
}
Look at your search function:
void search(struct node *head, int key, int index)
{
while (head != NULL)
{
if (head->a == key)
{
printf("Key found at Position: %d\n", index);
}
search(head->next, key, index - 1);
}
}
Now, for the time being, ignore the two 'actions' that occur in the while loop and just think about what stops the loop executing. Assuming (on the very first call to the function), that the value of head is not NULL, when will the loop stop? Of course, when head becomes NULL - but you never change the value of head in that loop! And the recursive call to search doesn't change it in the function that is currently running! So it's an infinite loop.
What you need to do is assign head->next to head inside the loop, like this:
void search(struct node *head, int key, int index)
{
while (head != NULL)
{
if (head->a == key)
{
printf("Key found at Position: %d\n", index);
}
head = head->next; // If list is properly formed, this will get to NULL
search(head, key, index - 1); // Now we don't need to use the ->next here
}
}
Also, if you only want to find the first occurrence of the key, you could add a return statement after printf; as it stands, you will print all matches - but this could be want you want.
As mentioned in another answer the problem is because you loop while head is not a null pointer, but you never modify head so it will never become a null pointer.
But there's another problem with the search function: You need to decide if you want to iterate over the list using loops, or using recursion. You should not use both.
Either use loops
while (head != NULL)
{
if (head->a == key)
{
printf("Key found at Position: %d\n", index--);
}
head = head->next;
}
Or use recursion
if (head != NULL)
{
if (head->a == key)
{
printf("Key found at Position: %d\n", index);
}
search(head->next, key, index - 1);
}
I'm guessing that you really meant to do the last alternative, but by mistake used while instead of if.
Below I have made a simple Linked List in C. The code is currently producing a segmentation fault which I find odd because I was copying an example from our current book. The only thing I did to the code was put the code into the method "addToList". I'm aware the segmentation fault is coming from the method addToList but I do not know where I made a mistake.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
} Node;
void addToList(Node *, int);
void printList(Node *);
void main() {
int x;
Node *head = malloc(sizeof(Node));
for (x = 1; x < 4); x++) {
printf("Enter an integer: ");
x = scanf("%d");
addToList(head, x);
}
printList(head);
}
void addToList(Node *head, int val) {
Node *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof(Node));
current->next->val = val;
current->next->next = NULL;
}
void printList(Node *head) {
Node *current = head;
while (current != NULL) {
printf("%d->", current->val);
current = current->next;
}
printf("\n");
}
Any help with telling me what is wrong or where I'm making the mistake would be greatly appreciated.
Look carefully at your code:
int main(void) {
int x;
Node *head = malloc(sizeof(Node));
for (x = 1; x < 4); x++) {
...
addToList(head, x);
}
...
}
You are not initializing the memory, so head->val and head->next are not
initialized. Because of that
while (current->next != NULL) {
current = current->next;
}
will loop an undefined amount of times. The first current->next is most
probably not NULL, so current = current->next get executed. At that point current is pointing to nowhere, hence the undefined behaviour which in your case leads to a segfault.
You have to initialized the memory like this:
Node *head = malloc(sizeof *head);
if(head == NULL)
// error handling
head->next = NULL;
But you could also use calloc, which also sets the memory to 0, thus you don't have to initialize the values (in this case):
Node *head = calloc(1, sizeof *head);
if(head == NULL)
// error handling
You should always check for the return value of malloc/calloc/realloc.
Also note that the signature of the main function can be one of these:
int main(void);
int main(int argc, char **argv);
int main(int argc, char *argv[]);
edit
Another error I've noticed right now:
x = scanf("%d");
That's not how scanf works. You have to pass a pointer, scanf saves the
scanned value through the passed pointer. scanf returns the number of matched
values on success, in this case, success would be 1:
int num;
int ret = scanf("%d", &num);
if(ret != 1)
{
fprintf(stderr, "Could not read value from the user\n");
continue; // to contiune looping
// you could also do a break; and stop the looping, or
// exit(1), etc.
}
// error with scanf
Also don't use the same variable x for the loop iteration and user input,
otherwise you are messing with the loop.
edit
User user3629249 wrote in the comment
good information, however the result will be the first entry in the linked list will contain garbage.
Better to declare head via: Node *head = NULL; and the function addToList() check for NULL and proceed accordingly.
That's right, the head element doesn't save any number in this way.
Option 1: double pointer
Here addToList receives a double pointer. The initialization of head occurs
when *head points to NULL. The function allocates memory for it, initializes
the memory, saves the value and returns. In the concurrent calls of addToList
*head won't be NULL, so addToList looks for the end of the list.
I've made small changes in the way you do malloc and realloc. Also I added
an implementation of freeList which should be used to free the memory:
void addToList(Node **head, int val) {
if(head == NULL)
{
fprintf(stderr, "head cannot be NULL\n");
return;
}
if(*head == NULL)
{
*head = calloc(1, sizeof **head);
head[0]->val = val;
head[0]->next = NULL;
return;
}
Node *current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof *current->next);
if(current->next == NULL)
return;
current->next->val = val;
current->next->next = NULL;
}
int main(void)
{
int x;
Node *head = NULL;
for (x = 1; x < 4; x++)
{
int val;
printf("Enter an integer: ");
if(scanf("%d", &val) != 1)
{
fprintf(stderr, "Could not read from user. Skipping entry\n");
continue;
}
addToList(&head, val);
}
printList(head);
freeList(head);
return 0;
}
void freeList(Node *head)
{
if(head == NULL)
return;
Node *current = head;
Node *next;
while(next = current->next)
{
free(current);
current = next;
}
free(current); // the last one
free(head);
}
Option 2: addToList returns a pointer to the head
Here addToList takes a pointer to the head. If it's NULL, it allocates
memory and initializes like in the shown above. If head is not NULL, the
functions looks for the last element and the returns the head. On error the
function returns NULL.
Node *addToList(Node *head, int val) {
if(head == NULL)
{
head = calloc(1, sizeof **head);
head->val = val;
head->next = NULL;
return head;
}
Node *current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof *current->next);
if(current->next == NULL)
return NULL;
current->next->val = val;
current->next->next = NULL;
return head;
}
int main(void)
{
int x;
Node *head = NULL, *tmp;
for (x = 1; x < 4; x++)
{
int val;
printf("Enter an integer: ");
if(scanf("%d", &val) != 1)
{
fprintf(stderr, "Could not read from user. Skipping entry\n");
continue;
}
tmp = addToList(head, val);
if(tmp == NULL)
{
fprintf(stderr, "Not enough memory\n");
freeList(head);
return 1;
}
head = tmp;
}
printList(head);
freeList(head);
return 0;
}
I'm creating a linked list with some insert functions.
This method work fine :
void insert_before(){
struct node *new_node, *ptr, *preptr;
int pivot;
new_node = (struct node*)malloc(sizeof(struct node));
ptr = link;
preptr = link;
printf("\n Enter the data : ");
scanf("%d", &new_node->data);
printf("\n Enter the value before which the data has to be inserted : ");
scanf("%d", &pivot);
while(ptr->data != pivot){
preptr = ptr;
ptr = ptr->next;
}
preptr->next = new_node;
new_node->next = ptr;
}
However, I got Cannot access memory at address 0x8 in this method :
void insert_after(){
struct node *new_node, *ptr, *preptr;
int pivot;
new_node = (struct node*)malloc(sizeof(struct node));
ptr = link;
preptr = link;
printf("\n Enter the data : ");
scanf("%d", &new_node->data);
printf("\n Enter the value after which the data has to be inserted : ");
scanf("%d", &pivot);
while(preptr->data != pivot){
preptr = ptr;
ptr = ptr->next;
}
preptr->next = new_node;
new_node->next = ptr;
}
Note that both of the method use the same struct* link, and the only difference is on the looping while(preptr->data != pivot).
Why does the first code working fine, but the second one broken?
Thanks for your help
PS : This is my whole project (very short), in case you need it : https://pastebin.com/wsMEicGv
I don't think that even the first method works correctly (simple proof: the code never changes the value of link, hence an insert before the first node cannot work).
Anyway, your code will produce the mentioned error message in both functions when you enter a value for pivot which does not match any data or which matches the last node in the list:
while(preptr->data != pivot){
preptr = ptr;
ptr = ptr->next;
}
The reason is that the loop above will reach the end of the list (having preptr = NULL), when condition preptr->data still accesses this null-pointer. I suppose that member data is the second one in your struct (the first one is next), right? Then you access actually (NULL + sizeof(node*)) which is (NULL + 8) which is 0x08.
You have a lot of bad practice:
You use global without reason!
You use global without reason!!
You use global without reason!!!
You cast malloc() without reason.
You don't check return value of function like scanf() or malloc().
You code several time the same feature.
fflush(stdin); is undefined behavior.
You don't initialize your variable when you could.
You declare all your variable at the beginning of the function.
For example, display() could look like this:
void display(struct node *head) { // no global it's better, isn't it ?
printf("List:");
while (head != NULL) {
printf(" %d", head->data);
head = head->next;
}
printf("\n");
}
More, in your create_ll() function, why don't you use insert beginning and reverse the list after ?
int create_ll(struct node **head) {
*head = NULL;
while (insert_beginning(head) != ERROR) {
}
return reverse_ll(head);
}
Use example:
int main(void) {
struct node *head;
if (create_ll(&head) == ERROR) {
return 1;
}
display(head);
free_ll(head);
}
For the problem of your both function, read the answer of stephan-lechner. But I make you an example:
int insert_after(struct node **head) {
printf("\n Enter the data : ");
int data;
if (scanf("%d", &data) != 1) { // If the input has no been parse.
// data is invalid here
return ERROR;
}
// data is valid here
printf("\n Enter the value after which the data has to be inserted : ");
int pivot;
if (scanf("%d", &pivot) != 1) {
return ERROR;
}
for (struct node *node = *head; node != NULL; node = node->next) {
if (node->data == pivot) {
struct node *new_node = malloc(sizeof *new_node);
if (new_node == NULL) {
return ERROR;
}
new_node->data = data;
new_node->next = node->next;
node->next = new_node;
return OK;
}
}
return ERROR;
}
Be aware that: If you use global your list functions will be:
Not thread safe.
Only usable for one list.
More info here.
I have written some code to create a singly linked list of integers and print out the items. After printing out all the items in the list, I printed out "head->item" and got the value of the integer in the first node.
I am quite puzzled as to why I can do that, because in the print() function, I wrote "head = head->next", so that means that head is changed right?
main()
int n;
int value;
ListNode *head = NULL;
ListNode *temp = NULL;
printf("Enter a value: ");
scanf("%d", &n);
while (n != -1)
{
if (head == NULL)
{
head = malloc(sizeof(ListNode));//create the head first
temp = head;//get temp to have the same value as head, so we do not accidently edit head
}
else
{
temp->next = malloc(sizeof(ListNode));//allocate space for the next node
temp = temp->next;//let temp be the next node
}
temp->item = n;//allocate a value for the node
temp->next = NULL;//specify a NULL value for the next node so as to be able to allocate space
scanf("%d", &n);
}
print(head);
printf("%d\n", head->item);//why can I still get the integer in the first node
while (head != NULL)
{
temp = head;
head = head->next;
free(temp);
}
head = NULL;
return 0;
}
void print(ListNode *head)
{
if (head == NULL)
{
return;
}
while (head != NULL)
{
printf("%i\n", head->item);
head = head->next;
}
}
head could be seen as a "reference" to a list, but it's actually a number (the address of the first node).
So a call to a function with head as a parameter just copy this "number" (the address) to the stack, and creates a new variable (which is also named head) initiated with the same address.
Since the head inside the function is a different variable, changing it doesn't change the original head.
Consider this situation:
void func(int x)
{
x=1;
}
...
int x=0;
func(x);
printf("%d",x); //Prints '0'
...
Make sure you understand why in this simple example the value of x isn't changed. It's true that pointers seem to change the behavior of parameter passing, but it doesn't mean that suddenly everything is passed "by reference".
Remember this rule: in order to modify the value of a variable in a function, you need to send a pointer to the variable. So what happens when you want to change a pointer to a variable? Well, according to the rule, you'll have to pass a pointer to the pointer.
So if you'd like to modify head (which you probably don't), refactor it like this:
void print(ListNode **head)
{
if (*head == NULL)
{
return;
}
while (*head != NULL)
{
printf("%i\n", *head->item);
*head = *head->next;
}
}
And the actual call is now print(&head).