I want to make a function that can add new elements to double linked list in C, but I couldn't do it. Here is code.
New element should have name, group etc. Just explain me how to make name and rest of it I will do by myself.
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>
#include <string.h>
typedef struct inform
{
char name[20];
char group[20];
char form[20];
int day;
int month;
int year;
int srok;
} INF_BLOK;
typedef struct list_elem
{
INF_BLOK inf;
struct list_elem *next, *prev;
} APTEKA;
APTEKA *head, *tail;
int InputData(INF_BLOK* inf);
int main()
{
return 0;
}
I tried to implement a function that inserts an element based on an given index. Note, that i changed your list_item struct a bit so that it contains a pointer to your data-elements.
Here is the implementation:
/**************************************************************
* Function: insert_index
* Parameters: APTEKA* head, INF_BLOK* data, int index
* Return value: Returns NULL on failure, a pointer to the head
* on success
* Description: Inserts a APTEKA* element based on an given
* index
***************************************************************/
APTEKA* insert_index(APTEKA* head, INF_BLOK* data, int index) {
// Local variable for index
int ind = 1;
APTEKA* new_node = (APTEKA*)malloc(sizeof(APTEKA));
new_node->inf = data;
// Check if head exists, the malloc call was successfull and the index is
// in allowed range
// NOTE: Index for head starts at position 1
if(head && new_node && index) {
// If index is one, set a new head
if(index == 1) {
// The previous node is of course NULL
new_node->prev = NULL;
new_node->next = head->next;
if(head->next)
head->next->prev = new_node;
head->next = new_node;
// In a full implementation you need to free the memory for head and the data field in the
// structure. free(...)
// Return a pointer to the new head of the list
return new_node;
} else {
APTEKA* current_node = head->next;
// Loop through all positions before the desired index
for(; ind < (index - 1); ++ind)
current_node = current_node->next;
new_node->prev = current_node;
new_node->next = current_node->next;
if(current_node->next)
current_node->next->prev = new_node;
current_node->next = new_node;
}
}
else {
// Return NULL on failure
return NULL;
}
// Return an pointer to the head
return head;
}
Explanation:
First the function creates a new node named new_node and sets the pointer of the inf data field to the given parameter. Before actually inserting i basically check for that everything is right.
I then divide into two cases: first one to replace the head (index == 1) and second one is for any other index.
If the head should be replaced i change the dependecies and return a pointer to the newly created node. For any other case i iterate to the element before the index and then try to insert it.
When i tested it with this main function, it seemed to work:
int main()
{
/* Only used for testing purposes */
APTEKA* head = (APTEKA*)malloc(sizeof(APTEKA));
APTEKA* first = (APTEKA*)malloc(sizeof(APTEKA));
APTEKA* tail = (APTEKA*)malloc(sizeof(APTEKA));
head->next = first, head->prev = NULL;
first->next = tail, first->prev = head;
tail->next = NULL, tail->prev = first;
/* Information for head node */
INF_BLOK* block_head = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_head->name, "Head", 5);
/* Information for tail node */
INF_BLOK* block_tail = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_tail->name, "Tail", 5);
/* Information for first block */
INF_BLOK* block_first = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_first->name, "First", 6);
/* Information for block to add */
INF_BLOK* block_sec = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_sec->name, "Second", 7);
head->inf = block_head, first->inf = block_first, tail->inf = block_tail;
if(!insert_index(head, block_sec, 2))
fprintf(stderr, "Error inserting element\n");
APTEKA* element = head;
/* Print out name-data of nodes */
while(element) {
puts(element->inf->name);
element = element->next;
}
element = head;
// Freeing everything
while (element) {
APTEKA* next = element->next;
free(element->inf), free(element);
element = next;
}
return 0;
}
Hopefully, my answer gives you the desired insights. If i did something wrong, please correct me :)
NOTE: For this answer i only used the name attribute of your data-item structure. For storing the group, form, etc. you will need another procedure setting those values.
Related
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.
-If A list has integer data such as: 1->2->3->4->5->6
-And pos_list has integer data such as: 4->0->5
-Then this function should return a New List hat contains the values that appear in list A at positions given in pos_list
such that New List= 5->1->6
I am implementing deep copy to make new List.
I am trying to use a loop that iterates according to the data of pos_list. Inside this loop, node of A will move to position of pos_list data. In this time i will copy the node A in new list to make another list.
Say for first case, pos_list has data 4, so the loop will run 4 times until the node of list A points to its fourth position. Inside this loop i will copy the data of list A in a new loop.
I need a guidance to solve this problem.
struct node * sublist(struct node * A, struct node * pos_list) {
struct node* newList=NULL;
struct node * curr;
int i=0;
for (i = 0, curr = pos_list->next; (curr != NULL); curr = curr->next) { //pos_list->data has a dummy node so loop until the end of pos_list->data.
struct node* newList = (struct node *) malloc(sizeof (struct node));
for(int i=0;i<=pos_list->data;i++){ //counter for pos_list as it will be (3 then 0,6 and 4)
if(i==pos_list->data){ //At the time when i == pos_list->data(3 or 0 or 6..)
newList->data = A->data; //Putting value of list A data in new list.
newList = newList->next; //Linking
printf("%d\t", newList->data); //Just for log
}
A=A->next; //Going to next position on A
}
pos_list=pos_list->next; //Going to next position on B
}
return newList ;
}
If A list is : 1->2->3->4->5->6
And pos_list is: 4->0->5
I expect the output is new list as 5->1->6
Your code has several problems:
You should start your traversal with pos_list, not with pos_list->next. The node pointed to by the head pointer is part of the list. Further, if pos_list == NULL, pos_list->next will lead to undefined behaviour.
The outer definition of int i isn't useful. Delete it.
Don't iterate through A by means of the position. If the position isn't valid, you will walk beyond the end of the list, get null pointers and invoke undefined behaviour. Lists should be iterated by list nodes accessed from the previous nodes' next pointers. (It is, of course, the caller's resposibility to provide valid positions, but your program should handle invalid input gracefully.)
Create the new node only when you have found a valid position. Otherwise you create a node that is never inserted and thus leak memory.
Here: newList = newList->next, newList->next isn't initialized. Remember that malloc gives you a chunk of uninitialized data.
You try to make newList point to the end of the newly created list, so that appending new nodes ist fast. That's a good idea, but if you return that pointer, you'll get a list that consists only of one element. (You'll also no loger be able to access any previously created nodes in that list.)
Here's an implementation that should work:
struct node *sublist(struct node *A, struct node *pos_list)
{
struct node *newHead = NULL;
struct node *newTail = NULL;
struct node *pos = pos_list;
while (pos) {
struct node *a = A;
int i = 0;
while (a) {
if (i == pos->data) {
struct node *node = malloc(sizeof(*node));
if (newHead == NULL) newHead = node;
if (newTail) newTail->next = node;
node->data = a->data;
node->next = NULL;
newTail = node;
break;
}
a = a->next;
i++;
}
pos = pos->next;
}
return newHead;
}
The question does not condone using a "struct" to implement the solution.
If it does, I am mistaken but if it does not, isn't it an overkill, when something akin to the following can be implemented....
#include <stdio.h>
#define CREATE_ARRAY(n) int result[n]
void main() {
int data[] = {1,2,3,4,5,6};
int pos[] = {4,0,5};
int i;
CREATE_ARRAY(sizeof(pos)/sizeof(int));
for(i = 0; i < sizeof(pos)/sizeof(int);++i)
result[i] = data[pos[i]];
/*
To print the values stored in result
for(i = 0;i < sizeof(result)/sizeof(int); ++i)
printf("%d ",result[i]);
putchar('\n');
}
*/
For starters the function sublist should be declared like
struct node * sublist( const struct node *A, const struct node *pos_list );
because neither the list A nor the list pos_list are changed in the function. Otherwise the declaration of the function confuses readers of the code.
It is a bad idea that the list pos_list contains a dummy node as it is wrote in the comment to this statement
for (i = 0, curr = pos_list->next; (curr != NULL); curr = curr->next) { //pos_list->data has a dummy node so loop until the end of pos_list->data
Neither dummy node should be in the list.
In this inner loop
for(int i=0;i<=pos_list->data;i++){
there is not used the dummy node of the list. Moreover the pos_list is traversed in the two loops: the outer loop and the inner loop
for (i = 0, curr = pos_list->next; (curr != NULL); curr = curr->next) { //pos_list->data has a dummy node so loop until the end of pos_list->data.
struct node* newList = (struct node *) malloc(sizeof (struct node));
for(int i=0;i<=pos_list->data;i++){
Within the loops the value of the variable newList is changed
newList = newList->next;
So as a result the function always returns some indeterminate value instead of the head of the newly created list. The value is indeterminate because the data member next of a new created node is not initialized.
newList->data = A->data; //Putting value of list A data in new list.
newList = newList->next;
The function can be defined the following way
struct node * sublist( const struct node *A, const struct node *pos_list )
{
struct node *newList = NULL;
struct node **current = &newList;
for ( ; pos_list != NULL; pos_list = pos_list->next )
{
const struct node *target = A;
for ( int index = pos_list->data; index != 0 && target != NULL; --index )
{
target = target->next;
}
if ( target != NULL )
{
*current = malloc( sizeof( struct node ) );
( *current )->data = target->data;
( *current )->next = NULL;
current = &( *current )->next;
}
}
return newList;
}
Here is my implementation of a hashmap in c and its initialization and insert code.
In the hashmap_t structure, I use an array of pointers (table) to nodes which contain the key/value pairs. In hashmap_init, I allocate the desired amount of nodes and loop through the array setting each pointer to NULL.
What I'm confused about is in the hashmap_put function. I find the index of which list the key should be inserted in and that first pointer is referenced by hm->table[i]. For clarity, I want to make sure it's obvious that hm->table[i] is the start of the list so I assign it to hashnode_t *head.
So when inserting the first node (head == NULL), I originally used head = new_node, but none of my inserts worked. It only works when I use hm->table[i] = new_node.
I don't understand why that's the case. head points to the same thing so why does setting head equal to the new_node not work? I'm also confused later in the function when last->next = new_node does work. Last is a pointer just like head but it works there.
Thanks for any clarification.
typedef struct hashnode {
char key[128];
char val[128];
struct hashnode *next;
} hashnode_t;
typedef struct {
int item_count;
int table_size;
hashnode_t **table;
} hashmap_t;
void hashmap_init(hashmap_t *hm, int table_size) {
hm->table_size = table_size;
hm->item_count = 0;
hm->table = malloc(table_size * sizeof(hashnode_t));
for (int i = 0; i < table_size; i++) { // loop through array of pointers to nodes
hm->table[i] = NULL;
}
}
int hashmap_put(hashmap_t *hm, char key[], char val[]) {
hashnode_t *new_node = malloc(sizeof(hashnode_t)); // allocate new node
strcpy(new_node->key, key);
strcpy(new_node->val, val);
new_node->next = NULL;
int i = hashcode(key) % hm->table_size; // index of list hashed to
hashnode_t *head = hm->table[i];
hashnode_t *cur = head;
hashnode_t *last;
if (!head) { // list is empty
new_node->next = head;
hm->table[i] = new_node;
//why does head = new_node not work?
hm->item_count += 1;
return 1;
}
while (cur) { // loop through nodes
if (strcmp(cur->key, key) == 0) {
strcpy(cur->val, val);
free(new_node);
return 0;
}
last = cur; // save pointer to node that points to NULL
cur = cur->next;
}
last->next = new_node;
//why does it work here?
hm->item_count += 1;
return 1;
}
'head' is pointing to a hashnode_t and so is 'hm->table[i]'. So, they are both pointing to the same object. Changing 'head' just makes 'head' point elsewhere. You have not actually assigned a pointer in the hashmap_t to the 'new_node'.
The reason that 'last' works is that you are changing a member variable to a new value. And, since 'last' is pointing to an object already in the hashmap_t, the assignment updates the object pointed to in the hastmap_t. So, an update to 'last->next = new_node' is the same as 'hm->table[x]->next = new_node' ('x' is some arbitrary index).
I'm missing with linked-list and trying to make a function which gonna take of all the odd numbers out of the link and make a new linked-list with them.
The point is that I dont understand how to update the original list by pointer to the function, actually what I made so far is making a new list with the odd numbers but I dont really understand how to "delete" them from the original list and link all the rest togther, then send it back to the main.
Node *build_odd_list(Node *oldlst, Node *newlst) {
Node *temp, *curheadNew;
temp = (Node*)malloc(sizeof(Node));
if (oldlst->value % 2 != 0) {
temp->next = NULL;
temp->value = oldlst->value;
newlst = temp;
curheadNew = newlst;
oldlst = oldlst->next;
printf("Passed %d\n", curheadNew->value);
}
else {
oldlst = oldlst->next;
}
while (oldlst) {
if (oldlst->value % 2 != 0) {
temp = (Node*)malloc(sizeof(Node));
temp->value = oldlst->value;
temp->next = NULL;
curheadNew->next = temp;
curheadNew = curheadNew->next;
oldlst = oldlst->next;
printf("Passed %d\n", curheadNew->value);
}
else {
oldlst = oldlst->next;
}
}
return newlst;
}
Thanks a lot!
Since you need to return a new list containing the odd numbers, and modify the original list due to removal of the odd numbers, you need to pass two values back to the caller: a pointer to the first element of the updated original list, and a pointer to the first element of the "odd numbers" list.
Since you need to pass the original list to the function anyway, the simplest option for the function is to:
pass a pointer to a pointer to the first element of the original list;
modify the original list via the pointer;
return a pointer to the first element of the "odd numbers" list extracted from the original list.
There is no need to allocate any new elements for the "odd numbers" list as the odd number elements can be moved from one list to the other.
It is worth learning the "pointer to a pointer" trick as it is a common way of manipulating list pointers.
Here is an example program to illustrate the above method. Pay particular attention to the extract_odd_list() function and the call to that function from main().
#include <stdio.h>
#include <stdlib.h>
typedef struct _Node {
int value;
struct _Node *next;
} Node;
/* Move odd numbers in *list to returned list. */
Node *extract_odd_list(Node **list) {
Node *oddstart = NULL; /* start of returned list */
Node **oddend = &oddstart; /* pointer to final link of returned list */
while (*list) {
if ((*list)->value % 2 != 0) {
/* Current element of original *list is odd. */
/* Move original *list element to end of returned list. */
*oddend = *list;
/* Bypass moved element in original list. */
*list = (*list)->next;
/* Update pointer to final link of returned list. */
oddend = &(*oddend)->next;
}
else {
/* Current element of original *list is even. */
/* Skip to next element of original *list. */
list = &(*list)->next;
}
}
/* Terminate the returned list. */
*oddend = NULL;
/* And return it. */
return oddstart;
}
void *printlist(Node *list) {
while (list) {
printf(" %d", list->value);
list = list->next;
}
}
int main(void) {
int i;
Node *list = NULL;
Node *end = NULL;
Node *oddlist;
Node *temp;
/* Construct a list containing odd and even numbers. */
for (i = 1; i <= 10; i++) {
temp = malloc(sizeof(*temp));
temp->value = i;
if (end == NULL) {
list = temp;
}
else {
end->next = temp;
}
end = temp;
}
end->next = NULL;
printf("Original list:");
printlist(list);
printf("\n");
/* Move the "odd number" elements from the original list to a new list. */
oddlist = extract_odd_list(&list);
printf("Updated list:");
printlist(list);
printf("\n");
printf("Odd list:");
printlist(oddlist);
printf("\n");
return 0;
}
Why are the split lists always empty in this program? (It is derived from the code on the Wikipedia page on Linked Lists.)
/*
Example program from wikipedia linked list article
Modified to find nth node and to split the list
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct ns
{
int data;
struct ns *next; /* pointer to next element in list */
} node;
node *list_add(node **p, int i)
{
node *n = (node *)malloc(sizeof(node));
if (n == NULL)
return NULL;
n->next = *p; //* the previous element (*p) now becomes the "next" element */
*p = n; //* add new empty element to the front (head) of the list */
n->data = i;
return *p;
}
void list_print(node *n)
{
int i=0;
if (n == NULL)
{
printf("list is empty\n");
}
while (n != NULL)
{
printf("Value at node #%d = %d\n", i, n->data);
n = n->next;
i++;
}
}
node *list_nth(node *head, int index) {
node *current = head;
node *temp=NULL;
int count = 0; // the index of the node we're currently looking at
while (current != NULL) {
if (count == index)
temp = current;
count++;
current = current->next;
}
return temp;
}
/*
This function is to split a linked list:
Return a list with nodes starting from index 'int ind' and
step the index by 'int step' until the end of list.
*/
node *list_split(node *head, int ind, int step) {
node *current = head;
node *temp=NULL;
int count = ind; // the index of the node we're currently looking at
temp = list_nth(current, ind);
while (current != NULL) {
count = count+step;
temp->next = list_nth(head, count);
current = current->next;
}
return temp; /* return the final stepped list */
}
int main(void)
{
node *n = NULL, *list1=NULL, *list2=NULL, *list3=NULL, *list4=NULL;
int i;
/* List with 30 nodes */
for(i=0;i<=30;i++){
list_add(&n, i);
}
list_print(n);
/* Get 1th, 5th, 9th, 13th, 18th ... nodes of n etc */
list1 = list_split(n, 1, 4);
list_print(list1);
list2 = list_split(n, 2, 4); /* 2, 6, 10, 14 etc */
list_print(list2);
list3 = list_split(n, 3, 4); /* 3, 7, 11, 15 etc */
list_print(list3);
list3 = list_split(n, 4, 4); /* 4, 8, 12, 16 etc */
list_print(list4);
getch();
return 0;
}
temp = list_nth(current, ind);
while (current != NULL) {
count = count+step;
temp->next = list_nth(head, count);
current = current->next;
}
You are finding the correct item to begin the split at, but look at what happens to temp from then on ... you only ever assign to temp->next.
You need to keep track of both the head of your split list and the tail where you are inserting new items.
The program, actually, has more than one problem.
Indexes are not a native way to address linked list content. Normally, pointers to nodes or iterators (which are disguised pointers to nodes) are used. With indexes, accessing a node has linear complexity (O(n)) instead of constant O(1).
Note that list_nth returns a pointer to a "live" node within a list, not a copy. By assigning to temp->next in list_split, you are rewiring the original list instead of creating a new one (but maybe it's intentional?)
Within list_split, temp is never advanced, so the loop just keeps attaching nodes to the head instead of to the tail.
Due to use of list_nth for finding nodes by iterating through the whole list from the beginning, list_split has quadratic time (O(n**2)) instead of linear time. It's better to rewrite the function to iterate through the list once and copy (or re-attach) required nodes as it passes them, instead of calling list_nth. Or, you can write current = list_nth(current, step).
[EDIT] Forgot to mention. Since you are rewiring the original list, writing list_nth(head, count) is incorrect: it will be travelling the "short-cirquited" list, not the unmodified one.
I also notice that it looks like you are skipping the first record in the list when you are calculating list_nth. Remember is C we normally start counting at zero.
Draw out a Linked List diagram and follow your logic:
[0]->[1]->[2]->[3]->[4]->[5]->[6]->[7]->[8]->[9]->...->[10]->[NULL]
Your description of what list_split is supposed to return is pretty clear, but it's not clear what is supposed to happen, if anything, to the original list. Assuming it's not supposed to change:
node *list_split(node *head, int ind, int step) {
node *current = head;
node *newlist=NULL;
node **end = &newlist;
node *temp = list_nth(current, ind);
while (temp != NULL) {
*end = (node *)malloc(sizeof(node));
if (*end == NULL) return NULL;
(*end)->data = temp->data;
end = &((*end)->next);
temp = list_nth(temp, step);
}
return newlist; /* return the final stepped list */
}
(You probably want to factor a list_insert routine out of that that inserts a new
node at a given location. list_add isn't very useful since it always adds to the
beginning of the list.)