Related
I am tasked with removing a node from a singly linked list and setting the structure that the node's dataPtr points to, to a new value. I create a structure pointer to hold the data of the popped node. There are 2 cases I want to catch 1) in which this new pointer is null, I want to set it to the popped node 2) if the pointer is not null, I want to do some operations on it.
NODE* printer;
printer = (NODE*) malloc(sizeof (NODE)); //dynamically allocate
if(printer==NULL){ //if it has no data
printer= deleteNode(sList); //call deleteNode function which returns popped node from the passed singly linked list
} else if (printer!=NULL && sList->count!=0) { //if it has data
(((PRINTJOB *) printer->dataPtr)->pageNums) -= PAGESPERMINUTE; //decrement the pageNums field by 1 (PAGESPERMINUTE)
if ((((PRINTJOB *) printer->dataPtr)->pageNums) <= 0) { //if the field is less than 0
printer = NULL; //set pointer back to null
}
printf("printers pageNum is: %d\n", ((PRINTJOB *) printer->dataPtr)->pageNums);
}
My compiler is giving me an error on 4th line: The value is never used.
It is also giving me an error in my else if statement: first condition is always true.
When I run this code block as well, it crashes my program.
My deleteNode function is:
#include "headers.h"
void* deleteNode(LIST* list){
NODE *toDelete;
toDelete = list->head;
list->head = toDelete->next;
return toDelete;
}
my NODE structure is:
typedef struct node{
void* dataPtr;
struct node* next;
} NODE;
I am tasked with removing a node from a singly linked list and setting the structure that the node's dataPtr points to, to a new value.
But you remove the node only conditionally (and on a condition that is unlikely to actually occur). If, as stated, the first step is to remove a node then Remove. That. Node.
I create a structure pointer to hold the data of the popped node.
But you shouldn't. If there is any data available to receive then that's because a node containing it already exists, and your deleteNode() function will return a pointer to it (provided that function is in fact called).
There are 2 cases I want to catch 1) in which this new pointer is null, I want to set it to the popped node
That makes no sense, because it makes no sense to create a new, separate node in the first place. What would make sense would be to check whether deleteNode returns a null pointer, which one imagines it might do if the list were empty (but see below).
if the pointer is not null, I want to do some operations on it.
That could make sense, but not in this context. According to your description, you want to perform operations on the node that was removed from the list (provided that one in fact was removed), but instead you are working on the newly-allocated, uninitialized node.
Based only on your description of the task itself, it sounds like you want something more like this:
NODE* printer = deleteNode(sList);
if (printer != NULL) {
(((PRINTJOB *) printer->dataPtr)->pageNums) -= PAGESPERMINUTE;
if ((((PRINTJOB *) printer->dataPtr)->pageNums) <= 0) {
printer = NULL; //set pointer back to null (?)
}
printf("printers pageNum is: %d\n", ((PRINTJOB *) printer->dataPtr)->pageNums);
} // else nothing to do
But there are other possibilities, depending on how the list is structured and used.
Note that the printer = NULL; line that I copied from your original code is questionable. It may make sense if later code performs a null check on printer before doing yet more processing, and you want to circumvent that. Beware, however, that failing to first free() the node might constitute a memory leak. It looks suspicious in that way, but it is possible that the node really shouldn't be freed there.
Note also, however, that your deleteNode() function appears to be likely to break when it operates on an empty list. In that event, it seems like the only sensible thing it could return is a null pointer. It might well be that list->head is in fact such a pointer in that case, but then
NODE *toDelete;
toDelete = list->head;
list->head = toDelete->next;
will attempt to dereference that null pointer when it evaluates toDelete->next, thus reaping undefined behavior. If in fact you can rely on list->head to be null when the list is empty, then you would want to modify the above something like this:
NODE *toDelete;
toDelete = list->head;
if (toDelete != NULL) {
list->head = toDelete->next;
} // else list->head is already NULL
Again, there are other possibilities depending on how the list is structured and used, but I think the above is probably what you want.
Since the code was cryptic I decided to reformulate it.
This code is trying to remove the second element from a linked list (the node with number 2 on "int data"). The first parameter of remove_node is the address of the first pointer of the list, so if I have to remove the first pointer of the list I am able to start the list from the next pointer.
The problem is inside the second while loop, inside the if clause, more specifically with the free(previous->next) function, it is changing the address pointed by address_of_ptr (aka *address_of_ptr) and I can't understand why this is happening. Could someone enlighten me?
#include <stdlib.h>
typedef struct node
{
struct node *next;
int data;
} node;
void remove_node(node **address_of_ptr, int int_to_remove)
{
node *previous;
while (*address_of_ptr != NULL && (*address_of_ptr)->data == int_to_remove)
{
previous = *address_of_ptr;
*address_of_ptr = (*address_of_ptr)->next;
free(previous);
}
previous = *address_of_ptr;
address_of_ptr = &((*address_of_ptr)->next);
while (*address_of_ptr != NULL)
{
if ((*address_of_ptr)->data == int_to_remove)
{
address_of_ptr = &((*address_of_ptr)->next);
free(previous->next);
previous->next = *address_of_ptr;
/*or
previous->next = (*address_of_pointer)->next;
free(*address_of_pointer);
address_of_pointer = &previous->next;
*/
}
else
{
previous = *address_of_ptr;
address_of_ptr = &((*address_of_ptr)->next);
}
}
}
int main(void)
{
node *head = malloc(sizeof(node));
node *a = malloc(sizeof(node));
node *b = malloc(sizeof(node));
head->next = a;
a->next = b;
b->next = NULL;
head->data = 1;
a->data = 2;
b->data = 1;
remove_node(&head, 2);
return 0;
}
I figured it out using pythontutor.com.
Here is an image of the execution about to replace address_of_ptr with the address of the next pointer in the list:
about to replace address_of_ptr
In my mind what would happen is that address_of_ptr would move from head to a:
like this
But what actually happens is this:
address_of_ptr move from head to the first node's next variable
Which is also the address of the next node (such as a).
Inside the if clause:
address_of_ptr is set to the second node's next variable
What I was expecting was it being set to b:
Like this
Since it becomes equivalent to previous->next, it causes program to free address_of_ptr.
I would like to thank everyone who helped me sorting this issue, I truly appreciate your effort in making the explanation clear as possible. After a lot of thinking a solution that I believe is much simpler than my first code come up. #David C. Rankin mentioned "Linus on Understanding Pointers", and I think "I might have grasped" what Linus was referring to:
void remove_node(node **address_of_ptr, int int_to_remove)
{
node *to_remove;
while (*address_of_ptr != NULL)
{
if ((*address_of_ptr)->data == int_to_remove)
{
to_remove = *address_of_ptr;
*address_of_ptr = (*address_of_ptr)->next;
free(to_remove);
}
else
{
address_of_ptr = &(*address_of_ptr)->next;
}
}
}
First of all, if the first while loop stops due to *address_of_ptr == NULL, then the line
address_of_ptr = &((*address_of_ptr)->next);
will cause undefined behavior, due to deferencing a NULL pointer. However, this will not happen with the sample input provided by the function main, so it is not the cause of your problem.
Your problem is the following:
When first executing inside the if block of the second while loop (which will be in the first iteration of the second while loop with your sample input), address_of_ptr will point to the next member of the first node in the linked list, so the pointer will have the value of &head->next. This is because you have the line
address_of_ptr = &((*address_of_ptr)->next);
in several places in your program, and it will execute one of these lines exactly once by the time you enter the if block.
The first line of that if block is also the line
address_of_ptr = &((*address_of_ptr)->next);
so that after executing that line, address_of_ptr will point to the next member of the second node in the linked list, so the pointer will have the value of &a->next.
At that time, the value of previous will be head, because at the time
previous = *address_of_ptr;
was executed, address_of_ptr had the value of &head.
Therefore, when the next line
free(previous->next);
is executed, previous->next will have the value of a, which ends the lifetime of that node. As already stated, at this time address_of_ptr will have the value &a->next, which means that address_of_ptr is now a dangling pointer, because it is now pointing to a freed memory location. Therefore, it is not surprising that *address_of_ptr changes after the free statement, because freed memory can change at any time.
Note that the function remove_node can be implemented in a much simpler way:
void remove_node( node **pp_head, int int_to_remove )
{
node **pp = pp_head, *p;
//process one node per loop iteration
while ( (p = *pp) != NULL )
{
//check if node should be removed
if ( p->data == int_to_remove )
{
//unlink the node from the linked list
*pp = p->next;
//free the unlinked node
free( p );
}
else
{
//go to next node in the list
pp = &p->next;
}
}
}
This line:
begin_list = &previous->next;
You might be mis-thinking how pointers to pointers work. Since begin_list is a t_list **, you generally want to assign to *begin_list. Also, since previous->next is already an address, you don't want to assign the address to *begin_list, just the value, so this should work instead:
*begin_list = previous->next;
Same for the similar line below it.
I prepared an answer last night several minutes after you asked the question at first, and put a lot of thought into it, but didn't come back until just now. I'd let my version go, but it's a more detailed look into the problem anyway, so I thought I'd include it for posterity.
The problem lay on line 36:
begin_list = &(*begin_list)->next;
In the first while loop in the function ft_list_remove_if, I can see that you wanted to change the beginning of the list to point to some list item potentially later in the list; so for example, if you wanted to remove all items in the list which contained the string "a", this function should indeed change the value of list1 in the main function; this way the new start of the list would actually be list2.
However, by the time the second while loop is entered, there's no need to change the pointer to the start of the list anymore; that was taken care of in the first while loop. As such, begin_list should really not be used anymore; it is a pointer to a pointer to a list item, so it references the variable which points to a list item. This is not desirable. Let's step through the program line-by-line and I'll show you what I mean.
Upon entering the function ft_list_remove_if, we run past the first while loop since the first element of the list does not contain the data "b":
while (*begin_list != 0 && (*cmp)((*begin_list)->data, data_ref) == 0)
{
[...]
}
We're still on the first list item when we enter the second while loop, and the first item does not match. We therefore go to the else branch of the if statement on line 25:
if ((*cmp)((*begin_list)->data, data_ref) == 0)
{
[...]
}
else
{
previous = *begin_list;
begin_list = &(*begin_list)->next;
}
In the else branch, previous is set to the first item in the linked list. Fair enough. Then begin_list is set to the address of the next member of the first list item. This means that when the first list item's next member changes, so does the value of *begin_list. Let that point sink in.
Now we go on to the next iteration of the while loop. This time *begin_list points to the second list item, which does indeed match the search criteria, so we enter the main if branch instead of the else:
if ((*cmp)((*begin_list)->data, data_ref) == 0)
{
previous->next = (*begin_list)->next;
free(*begin_list);
begin_list = &previous->next;
}
OK. So let's remember here: previous is set to the first item in the linked list. *begin_list is set to the second item in the linked list. But what is begin_list set to? In short, the address of previous->next. Remember the following from the last cycle of the loop?
previous = *begin_list;
begin_list = &(*begin_list)->next;
So now when previous->next is changed on line 28 to the third item in the list, *begin_list is also changed to the third item in the list! That means that line 29 frees the memory allocated to the third item in the list, while the second item no longer referenced by any pointers! By sheer luck, the program might continue to look like it functions properly for the next few steps, but it doesn't; the third element has been freed, and the contents of the third element get scrambled up a little bit and the third element's next and data members are filled with invalid data, resulting in the segfault.
However, the procedure worked when you copied *begin_list to to_remove first, and then freed the data pointed to by to_remove:
to_remove = *begin_list;
previous->next = (*begin_list)->next;
free(to_remove);
begin_list = &previous->next;
This is because to_remove continues to point to the second element, even after *begin_list has been changed by the previous->next = (*begin_list)->next; statement; thus the second element is freed as it should be, and on line 31 begin_list is set to the address of the third element, just like it should be.
That doesn't mean that the latter is a good solution. Really, I think begin_list shouldn't be used at all beyond the first while loop, since it doesn't have to be. My suggestion is to use another pointer named current with which you can step through the list:
#include <stdlib.h>
#include <stdio.h>
typedef struct s_list
{
struct s_list *next;
void *data;
} t_list;
void ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)())
{
t_list *previous;
t_list *current;
if (begin_list == 0)
return;
while (*begin_list != 0 && (*cmp)((*begin_list)->data, data_ref) == 0)
{
previous = *begin_list;
*begin_list = (*begin_list)->next;
free(previous);
}
current = *begin_list;
while (current != 0)
{
if ((*cmp)(current->data, data_ref) == 0)
{
previous->next = current->next;
free(current);
current = previous->next;
}
else
{
previous = current;
current = current->next;
}
}
}
int ft_strcmp(char *s1, char *s2)
{
int i;
i = 0;
while (s1[i] == s2[i] && s1[i] != '\0')
++i;
return (s1[i] - s2[i]);
}
int main(void)
{
t_list *list1 = malloc(sizeof(*list1));
t_list *list2 = malloc(sizeof(*list2));
t_list *list3 = malloc(sizeof(*list3));
list1->data = "a";
list2->data = "b";
list3->data = "a";
list1->next = list2;
list2->next = list3;
list3->next = 0;
ft_list_remove_if(&list1, "b", &ft_strcmp);
return (0);
}
I was trying to reverse a linked list, however whenever I execute the following function, I get only the last element. For example, if the list contained 11,12,13 earlier. After executing the function, it contains only 13. Kindly point out the bug in my code
void reverselist() {
struct node *a, *b, *c;
a = NULL;
b = c = start;
while (c != NULL) {
c = b->next;
b->next = a;
a = b;
b = c;
}
start = c;
}
Doesn't your loop guard insure that start is null?
If you aren't using start to identify the first element of the list, then the variable you ARE using is still pointing to what WAS the first element, which is now the last.
c is a helper pointer.
void reverselist()
{
struct node *a, *b, *c;
a=NULL;
b=start;
while(b!=NULL)
{
c=b->next
b->next=a;
a=b
b=c
}
start=a;
}
// You should assume that Node has a Node* called next that
// points to the next item in a list
// Returns the head of the reversed list if successful, else NULL / 0
Node *reverse( Node *head )
{
Node *prev = NULL;
while( head != NULL )
{
// Save next since we will destroy it
Node *next = head->next;
// next and previous are now reversed
head->next = prev;
// Advance through the list
prev = head;
head = next;
}
return previous;
}
I would have made a prepend function, and done the following:
struct node* prepend(struct node* root, int value)
{
struct node* new_root = malloc(sizeof(struct node));
new_root->next = root;
return new_root;
}
struct node* reverselist(struct node* inlist)
{
struct node* outlist = NULL;
while(inlist != NULL) {
struct node* new_root = prepend(outlist, inlist->value);
outlist = new_root;
inlist = inlist->next;
}
return outlist;
}
Have not tested this, but guess you grasp the idea of it. Might be just your variable names, which don't describe anything, but I think this approach is cleaner, and easier to understand what actually happens.
EDIT:
Got a question why I don't do it inplace, so I'll answer it here:
Can you do it inplace? Are you sure you don't wish to keep the
original list?
Do you need to do it inplace? Is the malloc to time consuming/is this a performance critical part of your code? Remember: premature optimization is the root of all evil.
Thing is, this is a first implementation. It should work, and not be optimized. It should also have a test written before this implementation is even thought of, and you should keep this slow, un-optimized implementation until the test passes, and you have proved that it's to slow for your use!
When you have a passing unit test, and proven the implementation to be to slow, you should optimize the code, and make sure it still passes the test, without changing the test.
Also, is it necessary inplace operations which is the answer? What about allocating the memory before reverting it, this way you only have one allocation call, and should hopefully get a nice performance boost.
This way everyone is happy, you have a cleaner code and avoid the risk of having Uncle Bob showing up at your door with a shotgun.
I'm new to C so be patient with me if you see some really newbie error in my code!
As part of a homework, I need to create an ordered list in order to store some data. What I've done so far is to create the struct which will represent each node of the list (firstNode is a global variable that points to the first node of the list):
typedef struct Node {
struct Node *next;
int id;
int value;
}Node;
Node *firstNode = NULL;
After that I created a function that inserts a new node into the list by checking the values of the nodes. Nodes with smaller values should be before others. So what I did was this:
void addNewNode(int nodeId, int nodeValue) {
Node *newNode = (Node*) malloc(sizeof(Node));
Node *temp, *tempPrev;
newNode->id = nodeId;
newNode->value = nodeValue;
if(firstNode == NULL) {
newNode->next = firstNode;
firstNode = newNode;
}
temp = firstNode;
tempPrev = NULL;
while(temp->value < newNode->value) {
tempPrev = temp;
temp = temp->next;
}
if(tempPrev == NULL) {
newNode->next = firstNode;
firstNode = newNode;
}
else {
tempPrev->next = newNode;
newNode->next = temp;
}
}
The problem with the code above is that sometimes the program crashes, but I can't find the error!
Also, what I'm trying to do next is, if some nodes have the same value, then they are ordered according to their id (nodes with smaller IDs come first). How can I do this? I'm really confused!
The program crashes because in the while loop condition, you don't check whether the temp equals to NULL. In other words, if you try to insert a new node with a greater value than all the others already inside the list, temp reaches to the end of the list (so temp equals to NULL) and you try to get the value of that node! So a fix would be:
while(temp!=NULL && temp->value>newNode->value)
{
....
}
As for the id of the nodes, you could extend your while loop condition like this:
while(temp!=NULL && (temp->value<newNode->value || (temp->value==newNode->value && temp->id<newNode->id))
{
....
}
Also, the first if-statement, where you check whether firstNode is NULL, is not necessary in your case. If it's NULL, the program will not get into the while-loop and will go directly to the first if-statement after the while-loop.
By the way, nice code for a new programmer in C :-)
1.
if(firstNode == NULL) {
newNode->next = firstNode;
firstNode = newNode;
return; // done with inserting the first node...need not continue.
}
2.
// ensure temp is not null only then access its value.
while(temp && (temp->value < nodeId->value)) {
tempPrev = temp;
temp = temp->next;
}
for one thing, you have nodeID -> value in there. NodeID is an int, so this won't work.
As a method of debugging, I would create a simple test harness. In other words, a test program you write that runs through all the common scenarios you can think of (aka unit testing). Each unit test checks to ensure that it runs properly and generates the expected output. This way, you can be confident that if everything checks ok, you're good to go. If a unit test fails, you know exactly what's broken.
I would suggest constructing a couple of test cases that check your boundary conditions (e.g. add an element to an empty list; add an element that should end up at the front of an existing list; add an element that shold end up at the end of an existing list; add an element that should end up somewhere in the middle of an existing list). Make a "print" function that will print the elements in the list to the console for debug. That will at least help you narrow down what the context of your crash is. One possibility (I don't know how many adds you're doing) is that the program runs out of memory and malloc fails. You can check for that because I think malloc returns NULL if it fails to allocate the requisite memory.
Node *newNode = (Node*) malloc(sizeof(Node));
if(newNode == NULL)
{
printf("Out of Memory!");
return;
}
I was at an interview for a C position in which they presented me with an idiom that I haven't previously encountered. This is a trick that simplifies implementation of various algorithms involving linked lists and I'm wondering if anybody else has encountered this.
Say we have a linked list record defined so:
typedef struct _record
{
char* value;
struct _record* next;
} record;
We need a function that inserts a new record so that the entire list remains sorted with respect to the value's in the records. The following implementation is simpler than anything I would have used, albeit less readable.
void insert_sorted(record** r, const char* value)
{
record* newrec = NULL;
while(*r && strcmp(value, (*r)->value) > 0)
r = &((*r)->next); /* move r to point to the next field of the record */
newrec = malloc(sizeof(record));
newrec->value = strdup(value);
newrec->next = *r;
*r = newrec;
}
When the function is called, r points to the head pointer of the list. During the while loop, r is updated to point to the next field of the record that comes just before the point where we want to put the new record in. The last line of the function either updates the head pointer of the list (if the insertion happens at the beginning) or the next field of the previous record, which is quite cool.
A couple of questions:
Does this idiom have a name or is it mentioned in any literature?
Are there others like it in the C language?
I thought I knew C pretty well and had pointers and indirection pretty well figured out, but this one took me a while to fully understand.
I've used similar to this to insert into a binary tree. Because when iterating the tree, you usually stop when your pointer becomes NULL (you ran off the tree).
So to insert, you have 3 options,
1: use a variable which tracks the previous value of your iterating pointer.
2: stop when the pointer you would follow is NULL before you follow it, works but slightly less elegant in my opinion.
3: or a more elegant solution is simply use a pointer to a pointer, so you can just do: *it = new_node(); and it'll add it where the NULL used to be in your tree.
For a linked list, while this code works nicely, I usually just use a doubly linked list which makes it trivial to insert at any location.
I'd say the idiom is "the kind of code which gave 'c' a bad name"
Unwarrantedly clever
Unwarrantedly compact
Surprising side effects on caller
No error handling on malloc
Only works for US English strings
I don't see anything I'd call an idiom per se. It looks like standard coding for when you deal with datastructures in C.
My only complaint would be that the callers pointer (*r) is modified. Depending on the use of the function, I'd expect thats an unexpected side effect. Besides removing the unexpected side effect, using a local variable to play the role of *r would make the code more readable.
What would be the idiom here? Surely not the implementation of a linked list.
The usage of a pointer to pointer construct?
The compact loop?
Personally I'd use a pointer return value instead of operating on an input value.
Because seeing this input data type would ring a bell, which makes me copy my value before handing it to your function.
This is a well known thing - double pointer iteration (that's my name for it, I don't know the official name). The goal is to be able to locate a position in single linked list, and then insert before that position (inserting after it is trivial). Implemented naively, this requires two pointers (current and prev) and special code for beginning of the list (when prev == NULL).
The code the way I usually write it is something along the lines of
void insertIntoSorted(Element *&head, Element *newOne)
{
Element **pp = &head;
Element *curr;
while ((curr = *pp) != NULL && less(curr, newOne)) {
pp = &(pp->next);
}
newOne->next = *pp;
*pp = newOne;
}
Update:
I've forgot theother purpose for this trick - a more important one. It's used to delete elements from single linked lists:
// returns deleted element or NULL when key not found
Element *deleteFromList(Element *&head, const ElementKey &key)
{
Element **pp = &head;
Element *curr;
while ((curr = *pp) != NULL && !keyMatches(curr, key)) {
pp = &(pp->next);
}
if (curr == NULL) return NULL;
*pp = (*pp)->next; // here is the actual delete
return curr;
}
I don't know if this has a name or even if it's some special idiom but, since memory is relatively plentiful nowadays, my linked lists (where the language libraries don't make them available) are a special variant which simplifies the code greatly.
For a start, they're always doubly-linked since this makes traversal in both directions easier, for both processing and insert/delete operations.
An 'empty' list actually consists of two nodes, the head and the tail. By doing this, inserts and deletes do not need to worry about whether the node they're deleting is the head or tail, they can just assume it's a middle node.
Insertion of a new node y before node x then become a simple:
x -> prev -> next = y
y -> next = x
y -> prev = x -> prev
x -> prev = y
Deletion of node x is a simple:
x -> prev -> next = x -> next
x -> next -> prev = x -> prev
free x
Traversal is adjusted to ignore the extraneous head and tail:
n = head -> next
while n != tail
process n
n = n -> next
This all serves to make the code a lot easier to understand without all the special handling of the edge cases, at the cost of a couple of nodes of memory.
Instead of returning the value of the new node as an in/out parameter, you are better off having that be the return value of the function. This simplifies both the calling code, and the code inside the function (you can get rid of all those ugly double indirections).
record* insert_sorted(const record* head, const char* value)
You are missing error handling for the malloc/strdup failing case btw.
This idiom is given in the Chapter 12 of "Pointers on C".This is used to insert a node into a linked list without list head.
To answer the original question, this is known as a pointer centric approach instead of the naive node centric approach. Chapter 3 of "Advanced Programming Techniques" by Rex Barzee available at amazon.com includes a much better example implementation of the pointer centric approach.
I have also come up with this use of a double pointer, I have used it, but I don't really like it. The code that I came up with has this kernel to search for certain objects and remove them from the list:
Element** previous = &firstElement, *current;
while((current = *previous)) {
if(shouldRemove(current)) {
*previous = current->next; //delete
} else {
previous = ¤t->next; //point to next
}
}
The reason I don't like my code is the subtle difference between the two if clauses: the syntax is almost identical, but the effect is entirely different. I do not think, we should write code as subtle as this, but doing it differently makes the code really lengthy. So, either way is bad - you might go for brevity or for readability, it's your choice.
despite of the tricks, isn't the role of variable "r" changed? how does the caller tell what "*r" is for after calling? or after execution, what is the header of the list?
I could not believe this can be exemplified (even in some book?!).
Did I miss anything?
If you do not return any pointer (like the others suggested), then I would suggest following changes to keep the role of the input.
void insert_sorted(record** head, const char* value)
{
record** r = head;
bool isSameHead = false;
record* newrec = NULL;
while(*r && strcmp(value, (*r)->value) > 0) {
r = &((*r)->next); isSameHead = true; }
newrec = malloc(sizeof(record));
newrec->value = strdup(value);
newrec->next = *r;
*r = newrec;
if (!isSameHead) *head = newrec;
}
actually, probably another better way to do it is using the "dummy head node", which links its next to the beginning of the list.
void insert_sorted(record** head, const char* value)
{
record dummyHead;
dummyHead.next = *head;
record* r = &dummyHead;
while(r->next) {
if(strcmp(value, r->next->value) < 0)
break;
r = r->next;}
newrec = malloc(sizeof(record));
newrec->value = strdup(value);
newrec->next = r->next;
r->next = newrec;
*head = dummyHead.next;
}