I've tried to look up the solution to this problem through various other threads but my search was unsuccessful. I'm new to C and also new to this site so I apologize in advance if I'm incorrect in phrasing this question. I kinda have an idea of what's going on, but at the same time I might be entirely wrong. I have a linked list and I'm trying to insert at the end of the list. But when Xcode gets to the statement while(ptr->next!=NULL) it throws the error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x800000012)
I read somewhere before that it was because I'm accessing something that doesn't exist or I'm failing to initialize node->next to NULL but I did in the previous "if statement". I'm pretty new at coding with pointers and linked lists and again I apologize for any weird stuff that might be in my code ):
////LIST AND NODE STRUCTURES
//data nodes
typedef struct node{
int data;
int ID;
struct node* prev;
struct node* next;
} node;
typedef struct ListInfo{
int count; //numnodes
struct node *list; //list of nodes
} ListInfo;
////INSERT FUNCITON
void insert(ListInfo *H, node *n){
if(n == NULL)
return;
node* ptr = H->list;
if(H==NULL){
ptr = n;
ptr->next = NULL;
}
else{
while(ptr->next!=NULL){ //Thread 1: EXC_BAD_ACCESS (code=1, address=0x800000012)
ptr = ptr->next;
}
ptr = n;
ptr->next = NULL;
}
// End of function
return;
}
////MAIN
int main(){ // No Edititng is needed for the main function.
ListInfo H;
H.count =0;
node *n;
int Data = 0,ID =0 ;
do{
printf("Enter an ID and a Value to add to the list, Enter -1 to stop: ");
//Get value from user to store in the new linked list node later.
scanf("%d %d",&ID,&Data);
// Check if the user entered "-1", if so exit the loop.
if(Data == -1||ID == -1)
return 0;
// Allocate memory for a new Node to be added to the Linked List.
n = malloc(sizeof(node));
// Put the Data from the user into the linked list node.
n->data = Data;
n->ID = ID;
//Increment the number of nodes in the list Header.
// If the current node count is zero, this means that this node is the first node
// in this list.
if(H.count++ == 0)
H.list = n;
// Otherwise, just use the insert function to add node to the list.
else insert(&H,n);
}while(Data != -1);
// Display all nodes in the list.
DisplayList(&H);
//Remove a node from the list, and display the list each time.
while(H.count != 0){
Delete(&H,H.list->data);
DisplayList(&H);
}
// Display the list, this should be empty if everything was correct.
DisplayList(&H);
}
When you allocate n you never set n->next. When you pass it to insert() you try to access the bad pointer and crash. When you set n->ID you should set n->next to NULL.
Related
I'm working on code that using structures and Linked list.
Please help me to understand how can I print any added point that is not in the head of the list created.
Any attempt was a failure.
*Issue on the second print call.
Is my only option is to do head = head->next in order to get the next variables?
Structures:
typedef struct
{
int x;
int y;
}point;
typedef struct {
point *p;
struct Item *next;
}Item;
Main:
void main()
{
Item *head = (Item*)malloc(sizeof(Item)); //head of co-list
if (!head) { //allocation check
printf("Allocation failed (head)\n");
exit(1);
}
head = addBegin(head);
printf("head point: (%d,%d)\n",head->p->x,head->p->y);
system("pause");
head = addBegin(head);
**printf("head second point: (%d,%d)\n",head->next->p->x,head->next->p->y);**
system("pause");
free(head->p);
free(head);
}
The function:
Item * addBegin(Item *head)
{
Item *tmp = (Item*)
malloc(sizeof(Item));
if (tmp) {
tmp->p = (point*)malloc(sizeof(point));
printf("Enter x's point: ");
scanf(" %d", &tmp->p->x);
printf("Enter y's point: ");
scanf(" %d", &tmp->p->y);
tmp->next = head;
return tmp;
}
else{ //memory allocation failed
printf("allocation failed (new head)\n");
exit(2);
return head;
}
You would want to walk the list, with code similar to:
for ( Item* current = &head;
current != NULL;
current = current->next ) {
do_stuff_with(current->p);
}
This stops when you reach the end of the list: that is, when you have processed the last node containing data, whose next pointer is NULL, and updated current to NULL.
On a side note, you want to tweak the definition of Item slightly, to:
typedef struct Item {
point *p;
struct Item *next;
} Item;
Some compilers, including GCC, will realize that Item.next has the same type, and stop giving you spurious warnings about anonymous structs and incomplete types.
it might also pay to decide whether you want to use Item and Point, or item and point. Inconsistent capitalization is confusing.
I'm trying to append a node to a linked list however, when I use a while loop to check if the "link" is set to NULL, the loop is being executed when it shouldn't.
It is as if the "cursor->link" was not set to NULL and the code inside the while loop is being executed, I put the print statement there just to test it and it is being executed even though "cursor->link" is set to NULL. The create function returns a "node*".
EDIT - I apologize guys, I posted this question late at night and I guess I might not have been in the best shape to express myself properly. Plus I'm still a bit confused about how to handle and work with Linked Listing (as my code probably shows). I've been given a template to work with (as in the functions append and display were preset and I've to work with them as is). The compiler did not set off any warnings with the code as is. However the program still crashes in the append function around the While loop.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node {
int data;
struct node * link;
} node;
node* create(int data,node* link) {
node* newNode = (node*)malloc(sizeof(node));
newNode->data = data;
newNode->link = link;
return newNode;
}
void append ( node **, int ) ;
void display ( node * ) ;
int main() {
node *p ;
p=NULL;
int n;
char ch[10];
do {
printf("Enter the value\n");
scanf("%d",&n);
append(&p,n);
printf("Do you want to add another node? Type Yes/No\n");
scanf("%s",ch);
}while(!strcmp(ch,"Yes"));
printf("The elements in the linked list are");
display(p);
printf("\n");
return 0;
}
/* adds a node at the end of a linked list */
void append ( node **q, int num ){
node *cursor;
if (*q == NULL) {
*q = create(num, NULL);
node *cursor = *q;
}
while(cursor->link != NULL) {
printf("1\n");
cursor = cursor->link;
}
node* newNode = create(num, NULL);
cursor->link = newNode;
}
void display ( node *q ){
node *cursor = q;
while(cursor->link != NULL) {
printf(" %d", q->data);
cursor = cursor->link;
}
printf(" %d", cursor->data);
}
As Ry mentioned, problem is with the cursor you are using in while loop, it's never initialized. Instead you are creating a new variable with the same name when *q is null. I see one more problem in your code, when list is empty you are adding new node twice. First in null check condition and then after while loop.
To fix move this line
"node *cursor = *q"
outside if condition and add a return instead. Also remove this line
"node *cursor"
Note:: I am assuming your create method has no issue.
I'm pretty new to C programming.
I have an assignment in which we are supposed to create a doubly linked list of integers, and write some functions to manipulate them. We are being asked to prevent memory leaks, but I'm not really sure how to do that.
I have to malloc a bunch of times in order to create and store nodes when making the linked list, and I'm pretty sure it's not a good idea to malloc enough space for a node and then free the pointer to it in the same place.
Therefore, my best guess is that I should free all nodes in the main function, when I will have printed their contents to the screen and they are no longer needed. I tried to implement a kill function that takes as input a reference head to the first node in the list, and which iterates over the nodes, freeing them as they go.
I went as far as installing valgrind to try and see if there were any memory leaks, and it looks like there are still some. I have no idea where they are coming from or how to fix the issue.
Here is the whole code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Node{
int data;
struct Node *next;
struct Node *previous;
}Node;
void print_dll(Node *head){
Node *curr = head;
while(curr != NULL){
printf("%d\t", curr->data);
curr = curr->next;
}
puts(" ");
}
Node* create_dll_from_array(int array [], int arrSize){
//this is a function that creates a doubly linked list
//with the contents of the array
Node* current = (Node *) malloc (sizeof(Node * ));
current->data = array[arrSize-1];
current -> next = NULL;
for(int i = 2; i <= arrSize; i++){
//create a new node
Node * temp = (Node*)malloc(sizeof(Node*));
//I would like the dll to be in the same order as the array, I guess it isn't strictly necessary
temp ->data = array[arrSize-i];
temp -> next = current;
current-> previous = temp;
//now make temp the current
current = temp;
}
current-> previous = NULL;
return current;
}
void insert_after(Node* head, int valueToInsertAfter, int valueToInsert ){
if(head != NULL){
Node * current = head;
while(current-> data != valueToInsertAfter){
//this while loop brings 'current' to the end of the list if
//the searched value is not there
if(current-> next != NULL){
current = current->next;
}else{
break;
}
}
//after exiting this loop, the current pointer is pointing
//either to the last element of the dll or to the element
//we need to insert after
Node *new = (Node *) malloc (sizeof(Node *));
new->data = valueToInsert;
new->next = current->next;
new->previous = current;
if(current->next != NULL){
(current->next)->previous = new;
}
current->next = new;
}
}
void delete_element(Node* head, int valueToBeDeleted){
//work in progress
}
void kill(Node *head){
//this is my attempt at freeing all the nodes in the doubly linked list
Node *current;
while(head!=NULL){
current = head;
head = head->next;
free(head);
}
}
int main(){
int array [5] = {11, 2, 7, 22, 4};
Node *head;
/*Question 1*/
//creates a doubly linked list from the array below
head = create_dll_from_array(array, 5); ///size of the array is 5
/* Question 2 */
// print_dll(head);
/*Question 3*/
// to insert 13 after the first appearance of 7
insert_after(head, 7, 13);
print_dll(head);
//to insert 29 after first appearance of 21
insert_after(head, 21, 29);
print_dll(head);
/*Question 6*/
//create a function to free the whole list
kill(head);
return 0;
}
The main function here is given to us by the prof, we have to build out function around it.
I don't know why this is still appearing to lead to memory leaks, and if I', being honest, I don't really know where else they could occur. As far as I know, I need to keep all the memory until almost the last minute.
Please help, I'm pretty lost here.
Thank you!
There are two problems:
Need to change all malloc (sizeof(Node*)) to malloc (sizeof(Node))
Need to change free(header) to free(current) in the kill function.
The modified code is as follows
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
struct Node *previous;
} Node;
void print_dll(Node *head)
{
Node *curr = head;
while(curr != NULL) {
printf("%d\t", curr->data);
curr = curr->next;
}
puts(" ");
}
Node *create_dll_from_array(int array [], int arrSize)
{
//this is a function that creates a doubly linked list
//with the contents of the array
Node *current = (Node *) malloc (sizeof(Node));
current->data = array[arrSize - 1];
current -> next = NULL;
for(int i = 2; i <= arrSize; i++) {
//create a new node
Node *temp = (Node *)malloc(sizeof(Node));
//I would like the dll to be in the same order as the array, I guess it isn't strictly necessary
temp ->data = array[arrSize - i];
temp -> next = current;
current-> previous = temp;
//now make temp the current
current = temp;
}
current-> previous = NULL;
return current;
}
void insert_after(Node *head, int valueToInsertAfter, int valueToInsert )
{
if(head != NULL) {
Node *current = head;
while(current-> data != valueToInsertAfter) {
//this while loop brings 'current' to the end of the list if
//the searched value is not there
if(current-> next != NULL) {
current = current->next;
} else {
break;
}
}
//after exiting this loop, the current pointer is pointing
//either to the last element of the dll or to the element
//we need to insert after
Node *new = (Node *) malloc (sizeof(Node));
new->data = valueToInsert;
new->next = current->next;
new->previous = current;
if(current->next != NULL) {
(current->next)->previous = new;
}
current->next = new;
}
}
void delete_element(Node *head, int valueToBeDeleted)
{
//work in progress
}
void kill(Node *head)
{
//this is my attempt at freeing all the nodes in the doubly linked list
Node *current;
while(head != NULL) {
current = head;
head = head->next;
free(current);
}
}
int main()
{
int array [5] = {11, 2, 7, 22, 4};
Node *head;
/*Question 1*/
//creates a doubly linked list from the array below
head = create_dll_from_array(array, 5); ///size of the array is 5
/* Question 2 */
// print_dll(head);
/*Question 3*/
// to insert 13 after the first appearance of 7
insert_after(head, 7, 13);
print_dll(head);
//to insert 29 after first appearance of 21
insert_after(head, 21, 29);
print_dll(head);
/*Question 6*/
//create a function to free the whole list
kill(head);
return 0;
}
Change sizeof(Node * ) to sizeof(Node) due to malloc reserving you memory for which the pointer points to and it needs the correct amount of needed memory (which is not a pointer but the object itself).
i <= arrSize might be an overflow, since the size usually is given as amount of memory cells. So you might consider using i < arrSize
The first while loop in the insert_after might point to invalid memory after the array
Node *new = is ugly syntax, since new is a keyword in C++. Please never do that, since that will break any code, which is being used in C++.
You dont need a temporary element in kill(). You can instead going until head points to NULL.
delete_element needs the same array checks as insert_after
Probably you need to debug the whole thing pasting one function after the other to get it properly working. No guarantee for correctness, since that was abit hard to read without comments and all.
The best way to find memory leaks is using valgrind (or a similar tool) in run time.
Valgrind will identify any memory leak or violation you ran through.
to run valgrind in linux environment, all you need to do is:
# valgrind --leak-check=full ./my_program
In you case it gave mainy theses errors:
==28583== Invalid read of size 8
==28583== at 0x400871: kill (aaa.c:77)
==28583== by 0x40092D: main (aaa.c:103)
==28583== Address 0x5204188 is 0 bytes after a block of size 8 alloc'd
==28583== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28583== by 0x40073A: create_dll_from_array (aaa.c:29)
==28583== by 0x4008D9: main (aaa.c:87)
this error means the allocation size was too small. as mentioned in another answers it is because you allocate enough memory for a pointer and not for the struct.
So I'm trying to do a method to clear a doubly linked list for school where the doubly linked list and nodes are defined as:
struct word_entry
{
char *unique_word ;
int word_count ;
} ;
struct node
{
struct word_entry one_word ;
struct node *p_previous ;
struct node *p_next ;
} ;
struct linked_list
{
struct node *p_head ;
struct node *p_tail ;
struct node *p_current ;
} ;
I have a method to clear a linked list by doing
int clear_linked_list( struct linked_list *p_list ) //return how many nodes were cleared
{
if (p_list->p_head == NULL) {
return 0;
}
else {
int count = 0;
struct node *curr = p_list->p_head;
while (curr != NULL) {
struct node *next = curr->p_next;
free(curr->one_word.unique_word);
free(curr);
curr = next;
count++;
}
return count;
}
}
I do a free() on curr->one_word.unique_word because it's a malloc'd char array. I was taught to free when I use malloc, so that's there.
The issue I run into is I get a "bogus pointer (double free?)" and a core dump when I run the test file provided by my professor. I've worked on this for a few hours and can't seem to find out where (or how) I'm calling free twice.
When you loop through the list, you should constantly change the position of the head, so that even if you repeat clear_linked_list, you will not get an error.
int clear_linked_list(struct linked_list* p_list) // return how many nodes were cleared
{
if (p_list->p_head == NULL) {
return 0;
} else {
int count = 0;
while (p_list->p_head != NULL) {
struct node* curr = p_list->p_head;
p_list->p_head = p_list->p_head->p_next;
free(curr->one_word.unique_word);
free(curr);
count++;
}
return count;
}
}
When freeing memory it is a good practice to set NULL to pointers that were freed to avoid this kind of problems.
So you should do:
free(curr->one_word.unique_word);
curr->one_word.unique_word=NULL;
//if that one_word.unique_word was shared between multiples nodes that free could cause problems if you dont set it to NULL afterwards
free(curr);
curr=NULL; //or curr=next...
Also. Check that when you create the nodes that:
*p_next is NULL on the last node of the double linked list
*p_previous is NULL on the first node of the list
You don't null out p_head before you leave the clear function.
So, if you called it twice, you'd have problems (i.e. p_head would point to an already freed node). Likewise for p_tail.
Also, if you tried to add to the list again, you'd have similar problems.
Otherwise, your clear code is just fine.
So, can you prove that the list is constructed correctly (e.g. before you free, add a printf that prints out all the node's pointers before you free anything).
hey guys this is my first time doing double linked list so I'm not very sure what I'm doing here ,need some help to check the code,thanks, here is what I have done with comments included.
The functions I have done here are print,print reverse,count elements in the linked list,and search function to determine whether this node exist
void printListfow() //print the list in forward manner
{
CLR;
struct node *tmpval; //declare a temp storage
if(start==NULL) //if 1st node = null,then nth is inside,nth to print
{
printf("List is empty\n");
return;
}
tmpval=start; //assign the head/start to temp storage to retrieve data in 1st node
printf("List of customer details: \n");
while(tmpval!=NULL) //keep doing till it is NULL/the end
{
printf("%d ", tmpval->detail); //print the 'detail' which is in the node temp is pointing at
tmpval=tmpval->next; //assign next node to the temp storage so that it can be printed again
}
}
void printListrev() //print in reverse manner
{
CLR;
struct node *tmpval; //temp storage
if(start==NULL) //
{
printf("List is empty\n");
return;
}
tmpval=start; //assign start to tmpval to retrieve value
printf("List of customer details: \n");
tmpval=tmpval->prev //move backward and assign the data to tmpval
printf("%d",tmpval->detail) //print it
}
void count() //count total number of records
{ struct node *x;
x=start; //assign value of start to temp storage
int ctr=0; //initialize counter
while(x!=NULL)
{
x=x->next; //keep going to next node and then increase the counter
ctr++;
}
printf("Number of customer records are %d\n",ctr);
}
int getNode(node *tmp ,int cust) //when user wants to delete a customer ID and its details, this will search through the list,then if found,pass the value to another function for deletion
{
tmp=tmp->cust;
while(tmp!=NULL)
{
if(tmp->detail == cust) //check if detail[ID stored] is same as requested[cust]
{
return 1;
}tmp=tmp->next; //if not same,then move to next one
}return 0;
}
thanks!
In context to printListrev():
Unless this is a circular doubly linked list, in which case last element is preceded by the first, start would have previous element NULL. So, there is no point in accessing the previous field of start, as you do here:
tmpval=start;
...
tmpval=tmpval->prev;
You can keep another pointer to end of the list for this purpose.
Other alternatives include:
recursive function:
void printrev(struct node *s)
{
if (s == NULL)
return;
printrev(s->next);
printf("%d ", s->detail);
}
iterative function:
void printrev()
{
struct node *end;
for (end = start; end->next != NULL; end = end->next)
;
for (; end != NULL; end = end->prev)
printf("%d ", end->detail);
}
Your getNode is of limited use. Suppose, if you want to delete element, your getnode would only return whether, element is present or not. Say it is present, your deleteNode function would still have to iterate to the appropriate element in the list before deleting it.
This could be solved by getNode returning pointer to the node:
node *getNode(int x)
{
node *t;
for (t = start; t != NULL; t = t->next)
if (t->detail == x)
return t;
return t;
}
Now, you can code delete as follows:
void delNode(node *n)
{
n->prev->next = n->next;
n->next->prev = n->prev;
free(n);
}
And call as follows:
node *n;
if ((n = getNode(x)) != NULL)
delNode(n);
I've assumed that you struct is:
struct node {
int detail;
struct node *next;
struct node *right;
};
typedef struct node * node;
In printListrev() you are printing only one node not going reverse.
One major problem you are doing is in getNode() ,you are changing the address of a local pointer but the original pointer still points where it previously.
If so then how you are going to delete that node ,as you can't know the node address after this function returns.
Are you going to call the getNode() for all the node ,if so that is not a good if you have many nodes.