I've read half a dozen answers with regards to this here and am relatively loathe to ask such a question, but I'm attempting to create a linked list using a struct in C, and was having some issues in passing pointers to the linked list. I think it's mostly sorted, but honestly am having acute issues trying to get the linked list working.
#include <stdio.h>
#include <stdlib.h>
typedef struct cell
{
int value;
struct cell *next;
} cell;
int inputplace = 0;
cell * createlist()
{
cell curElement = (cell *) malloc(sizeof(cell));
cell *head = &curElement;
cell *curEl = &curElement;
curEl->value = 900;
FILE *fp;
char *mode = "r";
fp = fopen("input",mode);
if(fp==NULL)
{
fprintf(stderr, "Unable to open input file 'input'");
exit(1);
}
int val;
int tempplace = 0;
while(tempplace < inputplace)
{
if(fscanf(fp, "%d", &val) != EOF)
{
tempplace++;
printf("%d", &val);
}
else
break;
}
while(fscanf(fp, "%d", &val)!=EOF)
{
inputplace++;
printf("%d\n", curEl);
if(val < 0)
{
curEl->value = -1;
curEl->next = -1;
break;
}
printf("%d\n", val);
curEl->value = val;
curEl->next = malloc(sizeof(struct cell));
curEl= curEl->next;
}
return head;
}
cell* reverse(cell* p)
{
cell * prev = -1;
cell * current = p;
cell * next;
while(current->value != -1)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
}
return prev;
}
cell* append(cell* p, cell* q)
{
cell * current = p;
cell * r = p;
while(1)
{
if(current->value == -1)
{
current->value = q->value;
current->next = q->next;
}
}
return r;
}
int last(cell *p)
{
cell q = *p;
int last = -1;
while(1)
{
if(q.value == -1)
{
return last;
}
else
{
last = q.value;
q = *q.next;
}
}
}
cell * delete(int n, cell *p)
{
cell * head = p;
cell * prev = -1;
cell * current = p;
if(current-> value == n)
{
return current->next;
}
else
{
while(current->value != -1)
{
if(current->value==n)
{
prev->next = current->next;
break;
}
prev = current;
current = current->next;
}
}
return head;
}
int member(int n, cell *p)
{
cell q = *p;
while(1)
{
if(q.value == n)
{
return 1;
}
if(q.value == -1)
{
return 0;
}
q = *q.next;
}
}
int display(cell *p)
{
printf(" %c", '[');
cell q = *p;
while(1)
{
if(q.value == -1)
{
printf("%c ",']');
return 1;
}
if(q.next != p->next)
printf("%c ",',');
printf("%d", q.value);
q = *q.next;
}
printf("\n\n");
}
int main()
{
cell *head = createlist();
cell *headk = createlist();
cell *head3 = delete(5, head);
printf("%d, %d\n", head->value, head->next->value);
printf("Last head: %d\n", last(head));
display(headk);
display(head);
display(head3);
cell *head4 = delete(6, head);
display(head4);
cell *head5 = delete(7, head);
display(head5);
printf("Member2 6, head: %d\n", member(6,head));
printf("Member2 3, head: %d\n", member(3, head));
cell *head2 = reverse(head);
//print(head2);
printf("%d, %d\n", head2->value, head2->next->value);
}
So the input file contains numerical data with a negative one terminating the list:
Example input I'm using:
5
6
7
-1
1
2
3
-1
The issue I'm having is the second list is apparently overriding the first or some such, and my pointer-fu is weak, what do I need to do to successfully allocate the new structs?
Charles B.
You return a pointer to a local variable, and local variables goes out of scope once the function returns and that leaves you with a stray pointer. Using that stray pointer will lead to undefined behavior.
The problem starts with the declaration of curElement, and the compiler should really have screamed at you for that:
cell curElement = (cell *) malloc(sizeof(cell));
Here you declare curElement to be an actual structure, and not a pointer to the structure.
There's also the problem that you don't really have an end to the list. You allocate the next pointer of the last node you add, regardless if there's going to be a next node or not, and you don't initialize that node so the memory you allocate will be uninitialized, and trying to access it will lead to yet another undefined behavior.
I suggest something like the following abbreviated code:
cell *head = NULL;
cell *tail = NULL;
...
while (fscanf(fp, "%d", &val) == 1)
{
...
cell *current = malloc(sizeof(*current));
current->val = val;
current->next = NULL; // Very important!
// Check if this is the first node in the list
if (head == NULL)
head = tail = current;
else
{
// List is not empty, append node to end of list
tail->next = current;
tail = current;
}
}
Beside the change in how the list is handled and added to, there are also two other changes: The first is that the return value from the fscanf function is compared against 1, because fscanf (and family) will return the number of successfully parsed items, and this allows you to find format errors in the input file.
The second change is to not cast the return of malloc. In C you should never cast from or to void *, cast like that can hide subtle bugs.
Related
I am having trouble figuring out how to do this correctly. I have a linked list of nodes then those nodes have pointers put into an array contained in that node. These nodes make up a sort of one-way graph between the nodes. I must then traverse the nodes randomly until the node "Home" is reached.
The main issue I'm having is assigning the graph nodes into the list nodes. I want the function to take in the head of the list, the names of the nodes and the weight (cost to travel between nodes). I'm not sure how to do this correctly and I don't know what I did but I think there's an infinite loop somehow. Any help is greatly appreciated.
The input file is structured as such:
Applebees
GroundRound
BlueMoose
DrunkenNoodle
Home
STOP
Applebees BlueMoose 10
Applebees DrunkenNoodle 13
GroundRound Applebees 2
GroundRound DrunkenNoodle 7
GroundRound Home 52
STOP STOP 0
GroundRound
Ignore the print statements in graphInsert() those are me trying to debug the loops.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
struct graphNode {
char name[100]; // Establishment name
int arcCnt; // Number of outgoing arc from this node
int weights[10]; // Weights of each outgoing arc from this node
struct graphNode* arcs[10]; // Holds other graph nodes that are connected to this node (this node is source)
};
struct listNode {
char name[100]; // Establishment name
struct listNode* next;
struct graphNode* graph; // Pointer into graph
};
void listInsert(struct listNode **head, char name[100]) {
// setup new nodes
struct graphNode* newGraph = (struct graphNode*)malloc(sizeof(struct graphNode));
for (int i = 0; i < 100; i++) {
newGraph->name[i] = name[i];
}
for (int i = 0; i < 10; i++) {
newGraph->arcs[i] = NULL;
}
newGraph->arcCnt = 0;
struct listNode* newNode = (struct listNode*)malloc(sizeof(struct listNode));
for (int i = 0; i < 100; i++) {
newNode->name[i] = name[i];
}
newNode->next = NULL;
newNode->graph = newGraph;
// check if head is NULL
if (*head == NULL) {
*head = newNode;
return;
}
// if the list is populated then add the node to the end
struct listNode* current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
void graphInsert(struct listNode** head, char src[100], char dst[100], int weight) {
struct listNode* srcNode = *head;
printf("CALL:");
while (srcNode->next != NULL) { // loop through list to find src
printf("%s %s", srcNode->name, src);
if (strcmp(srcNode->name, src) == 0) { // when it finds the name, find the dst update the graph node data
printf("FOUND");
struct listNode* dstNode = *head;
while (dstNode->next != NULL) { // this loop is to find the pointer to the dst node
printf(" %s %s", dstNode->name, dst);
if (strcmp(dstNode->name, src) == 0) { // when it finds name finally update all the info
printf("FOUND");
// assign the new arc to the right spot based on arcCnt (how many arcs there are), then return to exit the loops
srcNode->graph->arcs[srcNode->graph->arcCnt] = dstNode->graph;
srcNode->graph->weights[srcNode->graph->arcCnt] = weight;
srcNode->graph->arcCnt++;
return;
}
dstNode = dstNode->next;
}
}
srcNode = srcNode->next;
}
}
int main(){
srand(2021);
// setup variables
struct listNode* head = NULL;
struct graphNode* sourceNode = NULL;
FILE* data = fopen("./hw10.data", "r");
int i = 0;
int section = 1; // flag to read the file correctly
// this loop reads the file
while (1) {
char name[100];
char name2[100];
int weight = 0;
if (section == 1) { // reads the first section
fscanf(data, "%100s", name);
if (strcmp(name, "STOP") == 0) { // if end of section then increment section counter
section++;
} else { // if its not the end of the section then add the name to the linked list
listInsert(&head, name);
}
} else if (section == 2) { // reads the first section and builds the graph
fscanf(data, "%100s %100s %d", name, name2, &weight);
if (strcmp(name, "STOP") == 0) { // if end of section then increment section counter
section++;
} else {
//graphInsert(&head, name, name2, weight);
}
} else if (section == 3) { // this section only reads one line and gets the
char tmp[100];
fscanf(data, "%100s", tmp);
struct listNode* current = head;
while (current->next != NULL) { // loop through to find the right node for the name
if (strcmp(current->name, tmp) == 0) { // if names are equal update the node
sourceNode = current->graph;
break;
}
current = current->next;
}
}
if (feof(data)) break;
i++;
}
// debug print data
printf("\n");
struct listNode* current = head;
while (current != NULL) {
printf("%s\n", current->name);
current = current->next;
}
printf("\n");
// starting node
printf("%s ", sourceNode->name);
// now walk through the graph from sourceNode until we reach the node "Home"
int totalWeight = 0;
i = 0;
while (i < 100) {
char* tmp = sourceNode->name;
if (strcmp(tmp, "Home") == 0) { // if were home then exit program
// ending node and cost
printf("%s %d", sourceNode->name, totalWeight);
return 0;
} else { // if were not home then keep looping
int index = (rand() % sourceNode->arcCnt); // Generates random number between 0 and sourceNode->arcCnt
sourceNode = sourceNode->arcs[index];
//printf("Going to: %s, Index: %d", sourceNode->name, totalWeight);
}
i++;
}
return 0;
}
typedef struct LinkedList LinkedList;
struct LinkedList {
LinkedList* next;
char* head;
char current;
};
LinkedList makeList()
{
char* headPointer = calloc(60, sizeof(char));
LinkedList temp = { 0xCCCCCCCC, headPointer, 0 };
return temp;
}
int addToList(LinkedList* lstPointer, char toAdd) {
if (lstPointer->head == NULL || lstPointer->head == 0xCCCCCCCC)
return -1;
if (lstPointer->current + 1 < 60) { /* enough space in the list to add */
*(lstPointer-> head + lstPointer -> current) = toAdd;
lstPointer->current = lstPointer->current + 1;
}
else /* not enough space, will create new node in the list */
{
if (lstPointer->next == 0xCCCCCCCC) {
LinkedList nextNode = makeList();
lstPointer->next = &nextNode;
}
return addToList(lstPointer->next, toAdd);
}
/*Added succsessfully*/
return 0;
}
int main(){
char chr;
LinkedList lst = makeList();
while ((chr = getchar()) != EOF) {
if (addToList(&lst, chr) == -1)
return -1;
}
return 0;
}
i am trying to use linked list but after i fill the first, i create a new one and able to add an item to it. on the second item the next list pointer get destroyed by getchar(). i have no idea why or how is it related.
In makelist you need to allocate a new list, but then instead of returning it, you copy it into a local variable, leaking the memory that you just allocated. Instead, return a pointer:
LinkedList *makeList() // Note *
{
LinkedList *temp = calloc(1, sizeof(LinkedList));
temp->head = calloc(60, sizeof(char));
temp->next = 0;
temp->current = toAdd;
return temp; // Note temp is a pointer
}
In addToList you don't need the nextNode variable:
lstPointer->next = makelist();
I think there is something wrong with my create.
void add(N *p) {
N *current, *start;
current = malloc(sizeof(p));
scanf("%d", ¤t->data);
current->next = NULL;
if (p == NULL) {
p = current;
start = current;
} else {
start->next = current;
start = current;
}
}
I think that my display() is correct.
void display(N *p) {
N *current;
current = p;
while (current != NULL) {
printf("\n%d", current->data);
current = current->next;
}
}
Your malloc(sizeof(p)) only returns enough space for a pointer. You instead want malloc(sizeof(N)).
Also, you need to return the new value of p instead of throwing it away at the end of add(). (Your start has a similar issue; pick one to be the head of your linked list.)
There are problems:
function add() does not allocate the correct amount of memory. Use this method:
current = malloc(sizeof(*current));
The way you are inserting the newly allocated object into the list does not work: you modify p, which is an argument with local scope, and you set start which also has local scope. No side effect is performed on the N pointer is the callers scope.
Your display function is correct, but I would favor adding the newline at the end of the output instead of at the beginning.
Here is an updated version with a better API:
int add(N **headp) {
N *current = calloc(sizeof(*current));
if (current == NULL) {
fprintf(stderr, "cannot allocate memory for new object\n");
return -1;
}
if (scanf("%d", ¤t->data) != 1) {
fprintf(stderr, "cannot read value for new object\n");
return -2;
}
current->next = *headp;
*headp = current;
return 0;
}
void display(const N *list) {
for (const N *p = list; p != NULL; p = p->next) {
printf("%d\n", p->data);
}
}
The add function is used this way from the caller:
#include <stdio.h>
#include <stdlib.h>
typedef struct N {
int data;
struct N *next;
} N;
int main(void) {
N *list = NULL;
for (i = 0; i < 10; i++) {
if (add(&list))
break;
}
display(list);
return 0;
}
I have the following code to delete elements from a list. When one of the elements of the struct is lower than the value I use it, I must delete the node.
The code is as follows:
void DeleteNode(frota** head, int MAX, int nSquareW){
int i, eliminate = 0;
frota* curr = *head;
frota* curr1 = curr;
if(*head != NULL)
{
while(curr1 != NULL)
{
if(curr1->bateria < MAX)
{
if( *head == curr1){
if(curr1->next != NULL){
(curr1->next)->prev = NULL;
}
*head = curr1->next;
}else if(curr1 -> next == NULL){
(curr1->prev)->next = NULL;
}else{
(curr1->next)->prev = curr1->prev;
(curr1->prev)->next = curr1->next;
}
eliminate = 1;
}
curr1 = curr1->next;
if(eliminate == 1){
eliminate = 0;
printf("entrei1");
for(i=0;i<nSquareW;i++){
free(curr->percorridos[i]);
}
free(curr->percorridos);
free(curr);
}
curr = curr1;
}
}
}
The code is working well when I try to delete the last and middle nodes (value head is equal to first node, unless there is none, then value is NULL), but when I try to delete the first node, I get the following error:
*** Error in './iClean': double free or corruption (!prev): 0x09bd4a20 ***
Someone has already told me that the problem is when deleting the node (the free() ) and that I can't do anything about that.
Any help would be appreciate.
EDIT
nSquareWidth is the width of the map.
This is the code which generates percorridos:
void faz_mapa(matriz *** mapa, int nSquareW, int nSquareH){
*mapa = malloc(nSquareW * sizeof(matriz*));
for (int i = 0; i < nSquareW; i++)
{
(*mapa)[i]= malloc( nSquareH * sizeof(matriz));
}
for (int i = 0; i < nSquareW; i++)
{
for (int j = 0; j < nSquareH; j++)
{
//inicializa divisao suja
(*mapa)[i][j].limpo = 0;
(*mapa)[i][j].ocupado = NULL;
}
}
}
And struct:
typedef struct robot {
int bateria;
char nome[STRING_SIZE];
int pos_x;
int pos_y;
int target_x;
int target_y;
int limpos;
matriz ** percorridos;
struct robot * next;
struct robot * prev;
}frota;
I haven't run your code, but it is apparent that there is only one spot where we can run into a double free.
for(i=0;i<nSquareW;i++){
free(curr->percorridos[i]);
}
free(curr->percorridos);
free(curr);
Either you have a case where curr->percorridos is the same as curr, or maybe curr->percorridos[i] is the same as curr->percorridos?
You could find this out by adding a print statement before each call to free. Then find out which is being called twice.
for(i=0;i<nSquareW;i++){
printf("Freeing curr->perrcorridos[i] at %p\n", curr->percorridos[i]);
free(curr->percorridos[i]);
}
printf("Freeing curr->perrcorridos at %p\n", curr->percorridos);
free(curr->percorridos);
printf("Freeing curr at %p\n", curr);
free(curr);
Since double linked list programming questions show up so often on Stack Overflow, my answer will showcase how to do a double linked list in a pretty safe way. It uses a top level list type definition and sentinel entries. There is still some room to mess up, but the code is pretty easy to test and debug as different aspects are treated locally by individual functions.
The delete() function in the original question has the problem that it is in charge of 2 different things: 1. handle the double linked list removal stuff 2. Do some application specific filtering.
My code also shows, that application code running on such a list can be separated from list management code.
#include <stdint.h>
#include <stdlib.h>
typedef struct NodeType_tag { int32_t value; NodeType_tag *Next; NodeType_tag *Prev; } NodeType;
typedef struct { NodeType sentinel; NodeType *head; NodeType *tail; } NodeList;
void NodeListInit(NodeList * nodeList)
{
nodeList->sentinel.Next = &nodeList->sentinel;
nodeList->sentinel.Prev = &nodeList->sentinel;
nodeList->head = &nodeList->sentinel;
nodeList->tail = &nodeList->sentinel;
}
int NodeListIsEmpty(NodeList * nodeList)
{
return nodeList->head == &nodeList->sentinel;
}
void NodeListAddFront(NodeList* nodeList, uintptr_t value)
{
NodeType *newNode = (NodeType*)malloc(sizeof(NodeType));
if (NULL != newNode)
{
newNode->value = value;
newNode->Prev = nodeList->head->Prev;
newNode->Next = nodeList->head;
nodeList->head->Prev = newNode;
nodeList->head = newNode;
if (nodeList->tail == &nodeList->sentinel)
nodeList->tail = newNode;
}
}
void NodeListAddBack(NodeList* nodeList, int32_t value)
{
NodeType *newNode = (NodeType*)malloc(sizeof(NodeType));
if (newNode != NULL)
{
newNode->value = value;
newNode->Prev = nodeList->tail;
newNode->Next = nodeList->tail->Next;
nodeList->tail->Next = newNode;
nodeList->tail = newNode;
if (nodeList->head == &nodeList->sentinel)
nodeList->head = newNode;
}
}
NodeType *NodeListHead(NodeList*nodeList)
{
if (&nodeList->sentinel != nodeList->head)
return nodeList->head;
return NULL;
}
NodeType *NodeListTail(NodeList* nodeList)
{
if (&nodeList->sentinel != nodeList->tail)
return nodeList->tail;
return NULL;
}
NodeType *NodeListNext(NodeList * nodeList, NodeType * current)
{
if (NULL != current)
{
if (current->Next != &nodeList->sentinel)
return current->Next;
}
return NULL;
}
NodeType *NodeListPrev(NodeList *nodeList, NodeType *current)
{
if (NULL != current)
{
if (current->Prev != &nodeList->sentinel)
return current->Prev;
}
return NULL;
}
NodeType* NodeListRemoveForward(NodeList* nodeList, NodeType *target)
{
NodeType* next = NULL;
if (target != NULL)
{
target->Prev->Next = target->Next;
target->Next->Prev = target->Prev;
if (target == nodeList->head)
nodeList->head = target->Next;
if (target == nodeList->tail)
nodeList->tail = target->Prev;
if (&nodeList->sentinel != target->Next)
next = target->Next;
free(target);
}
return next;
}
// return 1 if value passes filter.
// return 0 if value is not passing filter.
typedef int(*FilterFunction_t)(int32_t value);
size_t NodeListFilter(NodeList *nodeList, FilterFunction_t filter)
{
NodeType * current = NodeListHead(nodeList);
size_t removeCount = 0;
while (current != NULL)
{
if (filter(current->value))
{
// passed filter -> keep it.
current = NodeListNext(nodeList, current);
}
else
{
// did not pass filter - kill it!
current = NodeListRemoveForward(nodeList, current);
removeCount++;
}
}
return removeCount;
}
void NodeListClear(NodeList *nodeList)
{
NodeType *current = NodeListHead(nodeList);
while (current != NULL)
{
current = NodeListRemoveForward(nodeList, current);
}
}
void DumpNodeList(NodeList* nodeList)
{
NodeType * current = NodeListHead(nodeList);
size_t i;
for (i = 0; current != NULL; i++, current = NodeListNext(nodeList,current))
{
printf("%d: %d\n", i, current->value);
}
}
int FilterAllOddValues(int32_t value)
{
if (0 == value % 2)
return 1;
return 0;
}
void TestNodeList()
{
NodeList myNodeList;
NodeListInit(&myNodeList);
for (int32_t value = 0; value < 10; value++)
{
NodeListAddBack(&myNodeList, value);
}
DumpNodeList(&myNodeList);
size_t removeCount = NodeListFilter(&myNodeList, FilterAllOddValues);
printf("%d nodes removed by filter.\n", removeCount);
DumpNodeList(&myNodeList);
NodeListClear(&myNodeList);
}
One obvious aspect is, that the number of head/tail special handling if-branches is greatly reduced compared to a non-sentinel implementation.
Another obvious aspect is that I ran it with a c++ compiler and thusly added a cast to the malloc() statements. Please resist the urge to write comments like "Don't cast malloc()", all you hardcore c-programmers ;)
I did a brief smoke test with the test code given below. There still might be errors in functions not covered by the test code.
I have a Segmentation error, maybe a lot more after I run it, but I can't check anything else now because of that.
The program should work like this:
When user types in 5 numbers, they should print out in ascending order
If the user enter the number already exit, then remove the original value
If the user enter a native value, print List Backwards
This is my code so far:
#include <stdio.h>
#include <stdlib.h>
struct element {
int i;
struct element *next;
};
void insert (struct element **head, struct element *new)
{
struct element *temp;
temp = *head;
while(temp->next != NULL)
{
if((*head==NULL))
{
head = malloc(sizeof(struct element));
//temp->i = i;
temp->next = new;
new = temp;
}
else if(temp->i == new->i)
{
new = malloc(sizeof(struct element));
free(new);
//purge(&head,&new);
}
else if(temp->i < new->i)
{
temp->i = new->i;
}
else if(temp->i > new->i)
{
new = new->next;
}
}
}
void purge (struct element *current, struct element *predecessor)
{
predecessor->next = current -> next;
free(current);
}
void printList (struct element *head)
{
while(head)
{
printf("%d", head -> i);
head = head->next;
}
}
void printListBackwards (struct element *ptr)
{
if(ptr == NULL)
{
printf("list is empty \n");
return;
}
if(ptr->next != NULL)
{
printListBackwards(ptr->next);
}
printf("print %p %p %d\n", ptr, ptr->next, ptr->i);
}
int main()
{
int n = 0;
int count = 5;
printf("enter a Number: \n");
scanf("%d",&n);
struct element *new;
new = malloc(sizeof(struct element));
struct element *head = NULL;
new->i = n;
while(count!=0)
{
insert(&head,new);
printList(head);
count++;
}
}
In the main() function, you only allocate and create one element with malloc(); you then try to add it to your list 5 times. This is going to cause confusion. You should allocate a node once for each element you add to the list.
struct element *head = NULL;
while (count!=0)
{
printf("enter a Number: \n");
if (scanf("%d", &n) != 1)
break;
struct element *new = malloc(sizeof(struct element));
if (new == 0)
break;
new->i = n;
new->next = NULL;
insert(&head, new);
printList(head);
count--;
}
Note that the revised code checks the result of both scanf() and malloc(). It also sets the new element's next pointer to NULL. And it counts down rather than up; this is likely to use less memory.
I've not tested this so there could be (and very probably are) other problems, but this is likely to work better (fix some of the problems, but not all of the problems).
You do need to learn how to use a debugger, at least enough to get the stack trace so you know which line of code is causing the crash.
Do you really need a linked list? It seems the problem statement says that user can enter only 5 numbers... if so, why not just use an array of 5 elements? Following are some ideas.
enum { N = 5 };
typedef struct Element {
int number;
bool present;
} Element;
Element elements[ N ];
Init:
for( i = 0; i != N; ++i ) {
elements[i].number = 0;
elements[i].present = false;
}
Insert "inputNumber":
for( i = 0; i != N; ++i ) {
if( elements[i].present == false ) {
elements[i].number = inputNumber;
elements[i].present = true;
}
}
Remove "removeNumber":
for( i = 0; i != N; ++i ) {
if( elements[i].number == removeNumber ) {
elements[i].present = false;
}
}
Print Backwards:
for( i = N; i != 0; --i ) {
printf( "%d\n", elements[i].number );
}
In main, you should set new->next = NULL; [or somewhere in the beginning of insert]
This bit of code is just messed up:
head = malloc(sizeof(struct element));
//temp->i = i;
temp->next = new;
new = temp;
You should, probably, set
*head = new;
But you also need to set *head->next = NULL;
This bit is complete nonsense:
new = malloc(sizeof(struct element));
free(new);
//purge(&head,&new);
You would want to free new.
else if(temp->i < new->i)
{
temp->i = new->i;
}
else if(temp->i > new->i)
{
new = new->next;
}
This is also quite wrong. I think the last one should do
temp = temp->next;
Do yourself a favour, draw up on a piece of paper, boxes
HEAD
!
v
+-----+
! i=3 !
+-----+ +-----+
!------->! i=4 !
+-----+
!-------->NULL
And then walk through it and see how your code inserts, removes, etc.
[Can I also suggest that you don't use C++ reserved words in your code - new is a C++ reserved word. It means that your code CERTAINLY won't compile in a C++ compiler, which is a bad thing to prevent. Sure, there are several other things that may need changing, but a simple thing like "not calling a variable new" shouldn't be one of the things it fails on].