Creating a sublist of the original list? - c

I'm trying to make a function that takes two parameters positions to take from list and original list and then copy indexed numbers to a list. Also i included the Struct for the list and the head. I get the EXC_BAD_ACCESS Error i commented the line.
code:
struct node_struct {
Item item;
link next;
};
struct list_struct {
link first;
int length;
};
list sublist(list A, list pos_list) {
int index = 0;
link tempForindex = malloc(sizeof *tempForindex);
link temp2 = malloc(sizeof *temp2);
list finale = malloc(sizeof *finale);
link temp3 = malloc(sizeof *temp3);
tempForindex = pos_list->first;
temp2 = A->first;
temp3 = finale->first;
int counter = 0;
while(tempForindex->next != NULL)
{
index = tempForindex->item;//EXC_BAD_ACCESS code1
counter = 0;
while(temp2->next != NULL)
{
if (counter == index)
{
temp3->item = temp2->item;
temp2 = A->first;
temp3 = temp3->next;
break;
}
temp2 = temp2->next;
counter++;
}
tempForindex = tempForindex->next;
}
return finale;
}

It all hopelessly flawed.
You need to get patterns going with linked lists. The structures are fine, but the fact that the code is crashing in the position indicated suggests to me that pos_list has not been set up correctly.
iterate through a list using this pattern
list mylist;
link ptr;
for(ptr = mylist->first; ptr != NULL; ptr = ptr->next)
{
/* loop body */
}
now write a test function to print out both arguments and ascertain that they are valid.

Related

Why aren't new elements being added to my linked list?

This is just a snippet of the code, but I checked and know for a fact that all the strings save nicely into the "new" element (in function SortedInsert), but then the "new" doesn't link to the head?
I've tried everything I could think, hopefully I'm just missing something obvious.
typedef struct _Info* Position;
typedef struct _Info{
char name[MAX];
char surname[MAX];
Position next;
} Info;
(declaration inside main function:
Info headInfo = {.name = {0}, .surname {0}, .next = NULL};
Position head = &headInfo;
)
int SortedInsert(Position head, char name[], char surname[]){
Position prev = NULL, temp = NULL, new = NULL;
prev = head;
temp = head->next;
new = (Position)malloc(sizeof(Info));
if(!new){
return EXIT_FAILURE;
}
strcpy(new->name, name);
strcpy(new->surname, surname);
new->next = NULL;
if(head->next==NULL){
temp = new;
}
else{
// first sort, by surname
while(strcmp(temp->surname, new->surname) < 0){
prev = temp;
temp = temp->next;
}
// second sort, by name
while(strcmp(temp->name, new->name) < 0){
prev = temp;
temp = temp->next;
}
new->next = prev->next;
prev->next = new;
}
return EXIT_SUCCESS;
}
int PrintList(Position head){
Position temp = NULL;
temp = head->next;
while(temp){
printf("%s ", temp->name);
printf("%s\n", temp->surname);
printf("---\n");
temp = temp->next;
}
return EXIT_SUCCESS;
}
Some issues:
temp = new does not insert anything into the list. It merely copies a reference to the new node into a local variable. The assignment should be to head->next. Moreover, there is no need to create a separate case for this. It can be handled with the code you have in the else part.
The retrieval of the insert point is not correct. If in the first loop the strcmp call returns 1 (not 0), then the second while loop should not iterate at all: it doesn't matter in that case what the first name is like. The last name of temp is already greater, so the insertion point has been found. Similarly, if the strcmp call returns 0, the second loop should keep verifying that the last name is still the same in its second iteration,...etc. Moreover, this logic can be combined in one loop.
Not a problem for the correct execution, but still:
Many consider it bad practice to typedef a pointer to a struct where you dereference the pointer regularly in your code. See the answers to Is it a good idea to typedef pointers? for some background. So I'd keep using Info *.
Create a separate function for creating and initialising a node.
The comments that say "first sort", "second sort" are misleading. There is no sorting happening in the loop that follows the comment. The list is already sorted. The process that follows just intends to find the insertion spot according to the sort order. So the comment could be improved.
Many consider it better not to cast the value returned by malloc.
Here is the correction of the SortedInsert function, together with the separated function for node creation:
Info *createNode(char name[], char surname[]) {
Info *new = malloc(sizeof(*new));
if (new != NULL) {
strcpy(new->name, name);
strcpy(new->surname, surname);
new->next = NULL;
}
return new;
}
int SortedInsert(Info *head, char name[], char surname[]){
Info *new = createNode(name, surname);
if (new == NULL) {
return EXIT_FAILURE;
}
Info *prev = head;
Info *temp = head->next;
// Find insertion spot according to sort order
while (temp != NULL) {
int cmp = strcmp(temp->surname, new->surname);
if (cmp == 0) { // It's a tie. Then use name as discriminator
cmp = strcmp(temp->name, new->name);
}
if (cmp >= 0) { // Found insertion spot
break;
}
prev = temp;
temp = temp->next;
}
new->next = prev->next;
prev->next = new;
return EXIT_SUCCESS;
}

i want to make sure that my linked list work

Is this a right way to do a linked list ? I am having a problem in a big school project and now i want to make sure that this is true.
void addnode(int a){
struct house* tmp = houses[i].next;
while (tmp != NULL) {
tmp = tmp->next;
}
tmp = (struct house*)malloc(sizeof(struct house));
tmp->id=a;
tmp->next=NULL;
}
i figured out that the error can be in other parts of the code. Now i will share the parts i suspect i hope you can help me.
houses[i] is an array of linked lists. if houses[i].id==-1 it is empty
struct house get_house_byid(int id) {
for (int i = 0; i < 1000; i++) {
if (houses[i].id != -1) {
if (houses[i].id == id) {
return houses[i];
}
if (houses[i].next != NULL) {
struct house* tmp = houses[i].next;
while (tmp != NULL) {
if (tmp->id == id) {
return *tmp;
}
tmp = tmp->next;
}
}
}
}
struct house housep;
housep.id = -1;
return housep;//if it cant find that id it returns housep
}
There may be other issues with your code that is not shown, but there are issues with addnode:
addnode does not set the head of the list (i.e. houses[i].next).
Thus, the newly added node is never connected to anything [and is a memory leak].
Ignoring the [obvious] typo/syntax error: void addnode{int a} instead of void addnode(int a).
The loop on tmp discards the pointer to the tail of the list. We need a separate variable (e.g. prev).
Note that i is global. That's fine, but the function would be cleaner if i was an argument to addnode instead.
Don't cast the return of malloc: Do I cast the result of malloc?
Here's is some refactored code. It is annotated:
void
addnode(int i,int a)
{
struct house *tmp;
struct house *prev;
// find the tail of the list
prev = NULL;
for (tmp = houses[i].next; tmp != NULL; tmp = tmp->next)
prev = tmp;
// allocate the new node
tmp = malloc(sizeof(*tmp));
tmp->id = a;
tmp->next = NULL;
// append to the tail of the [non-empty] list
if (prev != NULL)
prev->next = tmp;
// add to front of the empty list
else
houses[i].next = tmp;
}

I am implementing a doubly linked list in C, and having segmentation fault in a destroy function

I divided the code in two files, .h and .c
The definition of function names is in .h, the implementation of the function is in .c
in my main file:
struct no
{
tipo info;
struct no *ant;
struct no *nxt;
};
struct list
{
no_t *head;
no_t *tail;
int size;
};
this is in my .h file:
typedef struct no no_t;
typedef struct list list_t;
typedef int tipo;
...again in main
void list_destroy(list_t **l)
{
if ((*l) == NULL || l == NULL)
return;
if (!(*l)->head)
return;
no_t *next = (*l)->head; //create two variables for iterating through the list
no_t *aux; //set aux to free
while (next->nxt) //the pointer for next node, in the last node, is NULL
{ //by that I believe I'm able to iterate through all nodes
aux = next;
free(aux);
next = next->nxt;
}
free(*l);
(*l) = NULL;
}
is quite a simple code, but I can't see where I'm missing here
next = next->nxt;
For the compiler it makes no difference, for sure. But for someone, even you, it is hard to read this next = next->nxt stuff. Or is it is not?
A possible alternative (using your code) and a short test program
so_list.h
#include <stdio.h>
#include <stdlib.h>
typedef int Tipo;
typedef struct st_no
{
Tipo info;
struct st_no* prev;
struct st_no* next;
} Node;
typedef struct
{
Node* head;
Node* tail;
unsigned size;
} List;
List* list_create();
List* list_destroy(List*);
int list_insert(const Tipo, List*);
In the header, only typedefs and the function prototypes.
names with only the first letter in uppercase are reserved here for defined names. An useful convention.
instead of using List** is often clearer to just return the pointer to the list. In this way it is easier for example to invalidate the pointer and to create the linked lists as in
List* my_list = list_create();
my_list = list_destroy(my_list);
and there is no need to test the two levels of indirection as you need when ** is used
main.c: a minimalist test set
#include "so-list.h"
int main(void)
{
List* my_list = list_create();
my_list = list_destroy(my_list);
my_list = list_create();
for (int i = 1; i <= 5; i += 1)
printf("insert(%d,list) returned %d\n",
i, list_insert(i,my_list)
);
my_list = list_destroy(my_list);
my_list = list_create();
for (int i = 11; i <= 15; i += 1)
printf("insert(%d,list) returned %d\n",
i, list_insert(i, my_list)
);
my_list = list_destroy(my_list);
return 0;
}
A list is created, then destroyed
using the same pointer, a list is created, values 1 to 5 are inserted ant then the list is deleted.
using the same pointer, a list is created, values 11 to 15 are inserted ant then the list is again deleted.
the output
List created!
List deleted!
List created!
insert(1,list) returned 1
insert(2,list) returned 2
insert(3,list) returned 3
insert(4,list) returned 4
insert(5,list) returned 5
1 deleted
2 deleted
3 deleted
4 deleted
5 deleted
List deleted!
List created!
insert(11,list) returned 1
insert(12,list) returned 2
insert(13,list) returned 3
insert(14,list) returned 4
insert(15,list) returned 5
11 deleted
12 deleted
13 deleted
14 deleted
15 deleted
List deleted!
code for destroy_list()
List* list_destroy(List* l)
{
if (l == NULL) return NULL;
// delete the ´size´ nodes, 1 by 1
Node* p = NULL;
for (unsigned i = 0; i < l->size; i += 1)
{
p = l->head->next; // save pointer
printf("%d deleted\n", l->head->info); // just for the demo
free(l->head); // free head
l->head = p; // advance head
}
free(l); // free list
printf("List deleted!\n\n"); // just for the demo
return NULL;
}
This function always return NULL as just a way to invalidade the pointer in the caller in the same expression as in pList = destroy_list(pList);
This is somewhat different than the code you wrote. We just delete the elements one by one as we know the list has size elements. A local pointer is used in the loop to save the address of the next element. It seems to be easier to read.
The complete code for so-list.c
#include "so-list.h"
List* list_create()
{
List* one = (List*)malloc(sizeof(List));
one->head = NULL;
one->tail = NULL;
one->size = 0;
printf("List created!\n");
return one;
}
List* list_destroy(List* l)
{
if (l == NULL) return NULL;
// delete the ´size´ nodes, 1 by 1
Node* p = NULL;
for (unsigned i = 0; i < l->size; i += 1)
{
p = l->head->next; // save pointer
printf("%d deleted\n", l->head->info);
free(l->head); // free head
l->head = p; // advance head
}
free(l); // free list
printf("List deleted!\n\n");
return NULL;
}
// just for test, insert ´info´ at the end, returns size
int list_insert(const Tipo info, List* l)
{
// insert node at the end, just for test
Node* one = (Node*)malloc(sizeof(Node));
one->info = info;
one->next = NULL;
one->prev = l->tail;
if (l->size == 0)
l->head = one; // 1st node
else
l->tail->next = one;
l->tail = one;
l->size += 1;
return l->size;
};
about your version of list_destroy()
The logic there is a bit wrong but the error is well described in another answer. I recommend not to use ** in this situations. But it can be done for sure.
so-list.c
This is just a minimum to have a running test
#include "so-list.h"
List* list_create()
{
List* one = (List*)malloc(sizeof(List));
one->head = NULL;
one->tail = NULL;
one->size = 0;
printf("List created!\n");
return one;
}
List* list_destroy(List* l)
{
if (l == NULL) return NULL;
// delete the ´size´ nodes, 1 by 1
Node* p = NULL;
for (unsigned i = 0; i < l->size; i += 1)
{
p = l->head->next; // save pointer
printf("%d deleted\n", l->head->info);
free(l->head); // free head
l->head = p; // advance head
}
free(l); // free list
printf("List deleted!\n\n");
return NULL;
}
// just for test, insert ´info´ at the end, returns size
int list_insert(const Tipo info, List* l)
{
// insert node at the end, just for test
Node* one = (Node*)malloc(sizeof(Node));
one->info = info;
one->next = NULL;
one->prev = l->tail;
if (l->size == 0)
l->head = one; // 1st node
else
l->tail->next = one;
l->tail = one;
l->size += 1;
return l->size;
};
This has an issue
no_t *next = (*l)->head;
no_t *aux;
while (next->nxt)
{
aux = next; // aux point to the same object as next
free(aux); // free aux, which is the same as next
next = next->nxt; // deference next, which just got free'd. OOPS!
}
You invoke free on aux, which is also aliasing next. Then you try to deference next->nxt. Well, next just got released in the previous statement. Also, as I called out in the comment, you are leaking the last element in the list.
Fixed:
no_t* aux = (*l)->head;
while (aux)
{
no_t* next = aux->nxt;
free(aux);
aux = next;
}
You should look to your "free" and your "next->nxt" statements. May it can help you solve it.

A flexible list with indefinite number of nodes

I am supposed to make a linked list that takes in strings and prints them out in the reverse order. Normally I'd ask the number of nodes that need to be created, and then ask for the data in a for loop until we're done.
typedef struct word_st {
string word; // string is meant to be a pointer to a struct
word_st *next;
}
But the problem is, the number of nodes isn't known until runtime. So I have to keep asking for data until the user is done. I'm not really sure where to start/how to do that and can't seem to find anything on the internet either. So a hint would be very helpful.
I have my insert function and the print function looks fairly simple too.
word_t *insert_2(word_t* head, string text) {
word_t * p = NULL;
word_t * temp = (word_t*) malloc(sizeof(word_t));
temp -> word = text;
temp -> next = NULL;
if(head == NULL) {
head = temp;
} else {
p = head;
} while(p -> next != NULL) {
p = p -> next;
}
p -> next = temp;
return head;
}
In reverse, replace next by prev:
typedef struct word_st {
string word; // string is meant to be a pointer to a struct
word_st * prev;
}
And the function:
word_t *insert_2(word_t* head, string text) {
word_t * nextHead = (word_t*) malloc(sizeof(word_t));
nextHead -> word = text;
nextHead -> prev = NULL;
// Check first element of LIFO
if( head == NULL ) {
return nextHead;
}
nextHead -> prev = head;
return nextHead;
}
I hope It compiles and work.
Note:
for(word_t * head = last ; head->prev != NULL ; head = head->prev )
{
// Do the job
;
}

Returning head of linked list from a function

The function that I have created takes the heads of two linked lists of structs and uses them to update a member of the struct in the first linked list. Once my while loop has finished I wish to return the head of the struct 'a' however currently when I return it it has a value of NULL because of the while loop. How would I return the head of 'a' once it has been updated? I know that I have to use a temporary struct but how would I implement it?
struct artist *update_counts(struct artist *a, struct play *p)
{
struct artist *tmp = a;
int count = 0;
while (a != NULL)
{
while (a->artist_id == p->artist_id)
{
count += p->playcount;
p = p->next;
}
a->playcount = count;
a = a->next;
count = 0;
}
return a;
}
Generally, to visit the linked list, we can use a head pointer to keep its original linked list head like head_p = ...inputed head node..., and then use a visitor pointer to visit linked list like visitor_p = visitor_p->next. Here in your code, tmp is that head pointer.
struct artist *update_counts(struct artist *a, struct play *p)
{
struct artist *tmp_head = a;//tmp is the head of inputed linked list a
int count = 0;
while (a != NULL)
{
while (a->artist_id == p->artist_id)
{
count += p->playcount;
p = p->next;
}
a->playcount = count;
a = a->next;
count = 0;
}
return tmp_head;//just return the head of a
}

Resources