Applying Singly Linked List in C - c

Creating a list in C implementing SLL.
struct dat
{
char fname[20];
char lname[20];
};
typedef struct node_s
{
struct dat data;
struct node_s *next;
}NODE;
NODE *list=NULL;
NODE *list_create(struct dat *data)
{
NODE *node;
if(!(node=malloc(sizeof(NODE))))
{
return NULL;
}
node->data = data;
node->next = NULL;
return node;
}
NODE *list_insert_after(NODE *node, struct dat *data)
{
NODE *newnode;
newnode = list_create(data);
newnode->next = node->next;
node->next = newnode;
return newnode;
}
I cant find any good examples using SLL.
Now i have this append function now i will apply the two SLL functions, list_create and list_insert_after.
Is this correct?
void app(struct dat x)
{
FILE *fp;
fp=fopen("database.dat","a");
if(fp==NULL)
{
printf("file error");
}
if(fp!=NULL)
{
printf("enter lname: ");
gets(x.lname);
printf("enter fname: ");
gets(x.fname);
fprintf(fp,"%s %s\n",x.lname,x.fname);
if(list == NULL)
{
list=list_create((&x));
}
else
{
next=list_insert_after(list,&x);
}
}
fclose(fp);
}

To complete your example you should decide:
a) what if the role of your file database.dat.
b) how you work with your list.
I suppose you need two pointers to operate with the list: a pointer to the first element (it is list I think) and pointer to the last element (may be it is next).
Now call such as list_insert_after(list,&x); always inserts element after the first element, so your list cannot be longer than 2.
Consider the changes in your code as follows:
if(list == NULL)
{
list = list_create((&x));
next = list; // the last is the first
}
else
{
next=list_insert_after(next,&x); // insertion after the last
}
And about the file: if you decide to store not strings in text file, but structures in the binary file, save only struct dat to file, because storing pointers has no sense.

Even if C is a low level language, it is not forbidden to structure data. The node should be an internal object of the list. How to implement it in C depends on how you want to use it. Some examples :
a FIFO stack : 2 functions push and pop, and the list only needs to retain the last added element (you won't add after but before - left as an exercise)
a LIFO queue : still only 2 functions add and take, and the list needs to retain first element (its head) because its the next that will be taken, and last one (its tail) because it is where you will add next
typedef struct list_s {
NODE *head;
NODE *tail;
int len;
} LIST;
int add(LIST *list, struct dat *data) {
list->tail = list_insert_after(list->tail, data);
list->len += 1;
return list->len;
}
struct dat * take(LIST *list) {
if (list->len == 0) return NULL;
struct dat *data = head->data;
NODE *n = head;
head = head->next;
free(n);
return data;
}
of course, you will have to initialize a list, could take its length, ...
a true list : internally the same as a LIFO, but you will have to define an iterator (only contains a NODE *), and for example a BOOL hasnext(*ITERATOR) and struct dat * next(*ITERATOR)
the remaining is only limited by your requirements
NB: I assumed NODE.data was a struct dat * not a struct dat ...

Related

Read access violation when trying to compare int?

I am getting a read access violation and I cant understand why. I though I allocated everything correctly and I shouldn't be reading past the end of anything? Any ideas or help is greatly appreciated.
I am trying to read in a file that has a single integer per line and store those into a binary tree and linked list. The tree actually holds the data and the linked list just holds pointers to the nodes in the tree.
The error happens in the insert() function when data and node->num are being compared.
The newNode() function creates both a tree node and a linked list node, it only returns the tree node because of the double pointer handling the linked list.
// Garrett Manley
// delete these when turning it in
#pragma warning(disable : 4996)
#include <stdio.h>
#include <stdlib.h>
// define structs
struct treeNode {
int num;
struct treeNode *right, *left;
};
struct listNode {
struct treeNode *tNode; // data is a pointer to the tree
struct listNode *next;
};
// creates and returns a new node with given data, also adds node to linked list
struct treeNode *newNode(int data, struct listNode *(*list)) {
// make tree node
struct treeNode *node = malloc(sizeof(struct treeNode));
node->num = data;
node->left = NULL;
node->right = NULL;
// make list node
// insert entry into linked list
struct listNode *newNode;
newNode = malloc(sizeof(struct listNode));
newNode->tNode = node;
newNode->next = *list;
*list = newNode;
return (node);
}
// inserts given node into the tree in sorted order
struct treeNode *insert(struct treeNode *node, int data, struct listNode *(*list)) {
if (node == NULL) { // if the tree is empty return new node
return (newNode(data, list));
} else { // if there is a node use recursion to get to the bottom of the tree and add a node in the right spot
if (data <= node->num) {
node->left = insert(node->left, data, list);
} else {
node->right = insert(node->right, data, list);
}
return (node); // return the (unchanged) node pointer
}
}
// print linked list by looping through list, keep looping until node.next == null
// while looping print like this node.data.data to get the tree nodes data
void printList(struct listNode *(*list)) {
struct listNode *tmp = *list;
while (tmp->next != NULL) {
tmp = tmp->next;
printf("here");
}
}
// skim through the file and find how many entries there are
int SCAN(FILE (*stream)) {
int size = 0;
char *str = malloc(100 * sizeof(char));
while (fgets(str, 100, stream) != NULL) {
size++;
}
return size;
}
// loop through the file and load the entries into the main data array
void LOAD(FILE *stream, int size, struct treeNode *(*tree), struct listNode *(*list)) {
rewind(stream);
int i;
char *tmp = malloc(100 * sizeof(char));
for (i = 0; i < size; i++) {
fgets(tmp, 100, stream);
// recursively call insert to create the list, fix
*tree = insert(*tree, atol(tmp), list);
}
}
// free up everything
void FREE(struct treeNode *BlackBox, int size) {
// free linked list first
// then free the tree nodes, do this recursively
}
int main(int argv, char *argc[]) {
FILE *file = fopen("./hw7.data", "r");
int size = SCAN(file);
struct treeNode *tree = malloc(size * sizeof(struct treeNode));
struct listNode *list = malloc(size * sizeof(struct listNode));
LOAD(file, size, &tree, &list);
// print output
// print linked list
//printList(list);
fclose(file);
return 0;
}
There is no need to allocate memory in main for the tree, nodes are allocated by insert as needed. Allocating uninitialized memory for tree and list causes undefined behavior when the members pointed to by these pointers are dereferenced.
Change the initializations to:
struct treeNode *tree = NULL;
struct listNode *list = NULL;
Also note that the parentheses in return (node); are unnecessary, it is customary to write return node; instead.
Was allocating memory twice, removed malloc() in main() and now program works.

How to modularize a Linked List?

I have the following Linked List:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data; // Linked List type of data.
struct Node *next; // Pointer to the next Node.
};
void printfList(struct Node *head)
{
while(head != NULL)
{
printf(" %d\n", head -> data);
head = head -> next;
}
}
int main()
{
struct Node *head = NULL;
struct Node *second = NULL;
struct Node *third = NULL;
head = (struct Node*) malloc(sizeof(struct Node));
second = (struct Node*) malloc(sizeof(struct Node));
third = (struct Node*) malloc(sizeof(struct Node));
head -> data = 1;
head -> next = second;
second -> data = 2;
second -> next = third;
third -> data = 3;
third -> next = NULL;
printfList(head);
return 0;
}
How can I modularize this example to get something more professional? node type and separated from the others and function separately?
I think by "modularize" here you mean more kinda professional, clean looking code, I came up with following :
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data; // Linked List type of data.
struct Node *next; // Pointer to the next Node.
};
struct Node * makeNode(int data){
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = data;
temp->next = NULL;
return temp;
}
void printfList(struct Node *head)
{
while(head != NULL)
{
printf(" %d\n", head -> data);
head = head -> next;
}
}
int main()
{
struct Node *head, *prev;
int i, n;
printf("How many values you want to insert ?");
scanf("%d", &n);
printf("\nNow enter values :\n");
for(i = 0; i < n; i++){
int val;
scanf("%d", &val);
if(i == 0){
head = makeNode(val);
prev = head;
}
else{
struct Node *temp = makeNode(val);
prev->next = temp;
prev = temp;
}
}
printfList(head);
return 0;
}
Hope it helps.
I'm not sure what you're looking to do, but I think you should start by reviewing the question: should a "node" be a property of an object (a struct data type) or should a "node" be an accessor to a data type...?
Both work and I've used both.
When I need to link existing objects together, than a node will contain a reference data type... but unlike your list, the data is always accessed using a pointer (not containing the actual data type, but only using a reference).
This allows one (object) to many (lists) relationships.
However, many times the data type itself will need to be "chained" (in a single list - one to one relationship), in which case the "node" is a property of the data type and can be re-used in many different types.
A list to link existing types
Here's an example code where I used a linked list to link existing objects using a void pointer.
I'm not sure this implementation adds anything to your initial concept, but it does show the "modularization" for a "one (objet) to many (lists)" approach.
/* *****************************************************************************
Simple List
***************************************************************************** */
typedef struct fio_ls_s {
struct fio_ls_s *prev;
struct fio_ls_s *next;
void *obj;
} fio_ls_s;
#define FIO_LS_INIT(name) \
{ .next = &(name), .prev = &(name) }
/** Adds an object to the list's head. */
static inline __attribute__((unused)) void fio_ls_push(fio_ls_s *pos,
void *obj) {
/* prepare item */
fio_ls_s *item = (fio_ls_s *)malloc(sizeof(*item));
if (!item)
perror("ERROR: fiobj list couldn't allocate memory"), exit(errno);
*item = (fio_ls_s){.prev = pos, .next = pos->next, .obj = obj};
/* inject item */
pos->next->prev = item;
pos->next = item;
}
/** Adds an object to the list's tail. */
static inline __attribute__((unused)) void fio_ls_unshift(fio_ls_s *pos,
void *obj) {
pos = pos->prev;
fio_ls_push(pos, obj);
}
/** Removes an object from the list's head. */
static inline __attribute__((unused)) void *fio_ls_pop(fio_ls_s *list) {
if (list->next == list)
return NULL;
fio_ls_s *item = list->next;
void *ret = item->obj;
list->next = item->next;
list->next->prev = list;
free(item);
return ret;
}
/** Removes an object from the list's tail. */
static inline __attribute__((unused)) void *fio_ls_shift(fio_ls_s *list) {
if (list->prev == list)
return NULL;
fio_ls_s *item = list->prev;
void *ret = item->obj;
list->prev = item->prev;
list->prev->next = list;
free(item);
return ret;
}
/** Removes an object from the containing node. */
static inline __attribute__((unused)) void *fio_ls_remove(fio_ls_s *node) {
void *ret = node->obj;
node->next->prev = node->prev->next;
node->prev->next = node->next->prev;
free(node);
return ret;
}
A list that is integrated in the data-type
Often I have objects that I know I will link together and that by nature will only belong to a single list ("one to one").
In these cases, placing the node struct data within the data-type allows better locality and improved performance through a single allocation for both the data and the node information.
A good enough example for such a situation can be examined is this SO answer.

Creating lists of lists (Structs)

I am doing a programming assignment at the moment and I dont really have a full grasp of linking as we havent covered it yet. However I feel I need it to do what I want as arrays are not sufficent
I have created a struct as follows
struct node
{
float coef;
int expo;
struct node *link;
};
from this I can create pointers to the struct each with different names, however the problem I encountered is that I want user input to determine the amount I structs. I also want the ability to add and create the different structs.
You need to create a head pointer to keep track of your list.
This might be helpful:
struct list
{
struct node *head;
int count;
};
And you need to allocate memory for each new node and move the head to the newly created one.
struct node *add_node(struct list *pList, float coef, int expo)
{
if (pList == NULL)
{
return NULL;
}
struct *node pNode = (struct node*)malloc(sizeof(struct node));
if (node == NULL)
{
return NULL;
}
pNode->coef = coef;
pNode->expo = expo;
pNode->link = pList->head;
pList->head = pNode;
pList->count++;
return pNode;
}
To delete an element you need to move the head forward and then free it previous memory.
void *delete_node(struct list *pList, float coef, int expo)
{
if (pList == NULL)
{
return NULL;
}
struct node *tmp = pList->head;
pList->head = pList->head->link;
free(tmp);
pList->count--;
}
Note:
This is not the ultimate version. I'm just pointing my fingers to what should be done.
I would try something like this as your data structure
struct node
{
float coef;
int expo;
struct node *link;
};
struct poly
{
node *value;
struct poly *link
}
Maintain a linked list of polys, each of which contains a linked list of nodes.

Linked List program isn't updating properly

I have created a program that reads in a text file containing integers. It should read these integers in and then create a linked list of them. However, the head pointer of my program continually updates even when just the tail should be. Does anyone know why this is? The input file can be integers separated by spaces or newlines. Here is my code:
#include<stdlib.h>
#include<stdio.h>
#include <string.h>
/*THIS IS THE BASIC NAME STRUCTURE. IT CONTAINS A FIRST AND LAST NAME VARIABLE*/
struct number {
int * number; //number
};
/*THIS IS THE BASIC NAME NODE STRUCTURE. IT CONTAINS A NAME STRUCT AS WELL AS STRUCT NAMENODES TO PREVIOUS AND NEXT NODES*/
struct numberNode {
struct number number; //name stuct call
struct numberNode *pNext; //pointer to next node
struct numberNode *pPrev; //pointer to previous node
};
/*THESE NAMENODES WILL BE USED THROUGHOUT THE PRGRAM AS THE HEAD AND TAIL OF THE PROGRAM*/
struct numberNode *pHead = NULL, *pTail=NULL;
/*THIS PROGRAM READS A FILE AND PLACES THE NAMES INTO LINKED LIST*/
void insert_end(int *num)
{
struct numberNode *var = NULL,*temp = NULL; //set temp nodes
var=(struct numberNode *)malloc(sizeof(struct numberNode)); //allocate memory for new node
var->number.number= num; //set number of number stored in node
if(pHead==NULL){ //check if it is the head
pHead=var; //set node to head b/c of first element
pHead->pPrev=NULL; //set node next and prev to null
pHead->pNext=NULL;
pTail=pHead; //make head and tail the same
}else{
pTail=pHead; //set tail to head
while(pTail!=NULL) //while tail is not NULL
{
temp=pTail; //set temp node to tail pointer
pTail=pTail->pNext; //traverse the linked list
}
pTail=var; //set ptail to correct node
temp->pNext=pTail; //set the temps next to tail
pTail->pPrev=temp; //set the tail's previous pointer to temp
pTail->pNext=NULL; //set tail next to NULL
}
}
/*FUNCTION FOR DISPLAYING LINKED LIST DATA*/
void display(){
struct numberNode *node;
node=pHead;
printf("Displaying Linked List \n ************************************** \n");
while(node != NULL){
printf("Number is %d\n", *node->number.number);
node = node->pNext;
}
printf("List is terminated\n ************************************* \n");
}
void displayBackwards(){
struct numberNode *node;
node=pTail;
printf("Displaying Linked List Backwards \n ************************************** \n");
while(node != NULL){
printf("Number is %d\n", *node->number.number);
node = node->pPrev;
}
printf("List is terminated\n ************************************* \n");
}
/*DELETE NODE PASSED IN ARGUEMENT*/
void deleteNode(struct numberNode *node){
if (node!= pHead){
node->pPrev->pNext=node->pNext;
node->pNext->pPrev=node->pPrev;
node->pNext = NULL;
free(node);
}else{
pHead->pNext = pHead;
free(node);
}
}
//SWITCH THE LOCATIONS OF THE TWO NODES PASSED AS ARGUEMENTS
void switchNodes(struct numberNode *leftNode, struct numberNode *rightNode){
struct numberNode temp;
temp = *leftNode;
leftNode->number=rightNode->number;
rightNode->number= temp.number;
}
/*ORGANIZE LINKED LIST IN ALPHABETICAL ORDER*/
void organizeInAscendingOrder(){
struct numberNode *node = pHead;
int length=0;
while(node != NULL){
node = node->pNext;
length ++;
}
node = pHead;
int index = 0, secondIndex = 0;
for (index=0; index<length; index++){
for (secondIndex=0; secondIndex<length-1; secondIndex++){
if(node->number.number > node->pNext->number.number){
switchNodes(node, node->pNext);
}
node=node->pNext;
}
node=pHead;
}
}
/*PUSH NODE PASSED AS ARGUEMENT TO THE BACK*/
void pushToBack(struct numberNode *node){
pTail->pNext = node;
deleteNode(node);
}
int main() {
char file[100];
printf("Enter input file ");
scanf("%s", file);
FILE *in_file = fopen(file, "r");
int number;
char *buffer;
while(fscanf(in_file,"%d", &number)!=EOF)
{
insert_end(&number);
}
display();
organizeInAscendingOrder();
display();
displayBackwards();
}
as Paul said you don't necessarily need both struct, but the real problem is that when you read an int from the file you store in the variable "int number;" and each time you call the function insert_end(&number); you send the address of the variable number but in your insert_end function you assign the value of your new number in your new node to the address of number :
var->number.number= num;. So in your list all your number element in your numberNode will point the the same address.
a quick fix would be to allocate new memory space for each integer read in the file.
ex:
int* number = (int*)malloc(sizeof(int));
while(fscanf(in_file,"%d", number)!=EOF)
{
insert_end(number);
number = (int*)malloc(sizeof(int));
}
you could also remove pointers from the struct as suggested by Paul :
struct numberNode {
int number; //number
struct numberNode *pNext; //pointer to next node
struct numberNode *pPrev; //pointer to previous node
};
hope it helps,
[EDIT] : +1 for fhsilva who propose a better way to manage the tail, the head should always refere to the first element of the list and the tail should always point to the last one. This ways you don't new to go through the list to insert at the end becaus you already have a reference to the last element.(I couldn't comment on fhsilva's answer because I just subscribed to SO and don't have enough reputation...)
James
You are in a bit of a muddle with your data structures - you can just reduce this:
struct number {
int * number; //number
};
/*THIS IS THE BASIC NAME NODE STRUCTURE. IT CONTAINS A NAME STRUCT AS WELL AS STRUCT NAMENODES TO PREVIOUS AND NEXT NODES*/
struct numberNode {
struct number number; //name stuct call
struct numberNode *pNext; //pointer to next node
struct numberNode *pPrev; //pointer to previous node
};
to this:
struct numberNode {
int number; //number
struct numberNode *pNext; //pointer to next node
struct numberNode *pPrev; //pointer to previous node
};
i.e. you don't need more than one struct for this.
Not sure why you are traversing the list since it is double linked.
This should work:
if (pHead==NULL){
(...)
} else {
pHead->pPrev = var;
pTail->pNext = var;
var->pPrev = pTail;
var->pNext = pPrev;
pTail = var;
}

Removing node from singly linked list

I need to remove a node from a singly linked list. I know this is a simple thing to do, but my mind is blank and I've searched both Google and Stackoverflow, but I seriously haven't found anything that will help me.
basically the list of nodes is contained in a bucket; like this:
struct node{
unsigned char id[20];
struct node *next;
};
struct bucket{
unsigned char id;
struct node *nodes;
};
and I have a function
struct bucket *dht_bucketfind(unsigned char *id); // return bucket with id[20]
to find the correct bucket. So I know how to find the correct bucket, but I don't know how to remove a given node. I would like to remove the node by nodeid (I think, I haven't really written the code that will call the remove function yet ;) but I think I'll be able to modify the code if necessary). I think that's all that's needed to solve this. Thanks in advance.
If you know the item you want to remove, you must do two things:
Change all pointers that point to the target item to point to the target item's next member. This will be the preceding item's next pointer, or the head of the list bucket.nodes.
Free the node you just made unreachable.
The code for manipulating a linked list is really not that tricky, once you understand what you are doing.
Your nodes don't have any payload other than an id, so, depending on the data payload of a node, you might not actually need to iterate the list in the standard way. This is useful if deleters are going to know the address of only the node they want to delete.
If your payload is a pointer to other data:
struct _node {
void *data;
unsigned char id[20];
struct _node *next
}
Then you could "delete" a node by stealing the payload of the next node, and then delinking the next node:
int delete (struct _node *node)
{
struct _node *temp;
memcpy(node->id, node->next->id, 20);
free_function(node->data);
node->data = node->next->data;
temp = node->next;
node->next = node->next->next);
free(temp);
return 0;
}
/* define your two pointers, prev and cur */
prev=NULL;
cur=head;
/* traverse the list until you find your target */
while (cur != NULL && cur->id != search_id) {
prev=cur;
cur=cur->next;
}
/* if a result is found */
if (cur != NULL) {
/* check for the head of the list */
if (prev == NULL)
head=cur->next;
else
prev->next=cur->next;
/* release the old memory structure */
free(cur);
}
public void Remove(T data)
{
if (this.Head.Data.Equals(data))
{
this.Head = this.Head.Next;
this.Count = this.Count - 1;
}
else
{
LinkedListNode<T> node = this.Head;
bool found = false;
while (node.Next != null && !found)
{
if (node.Next.Data.Equals(data))
{
found = true;
node.Next = node.Next.Next;
this.Count = Count - 1;
}
else
{
node = node.Next;
}
}
}
}
Its been a long time ago since I worked with C, but this should be compile clean.
Basically, you need to keep track of the previous pointer while you iterate through the linked list. When you find the node to delete, just change the previous pointer to skip the delete node.
This function deletes all nodes with id (find). If you want to delete only the first occurrence, then put a return after the free statement.
void delete(struct bucket *thisBucket, unsigned char find[20]) {
struct node *prev = null;
struct node *curr = thisBucket->nodes;
while (curr != null) {
if (!strcmp(curr->id, find)) { // found the node?
if (prev == null) { // going to delete the first node (header)?
thisBucket->nodes = curr->next; // set the new header to the second node
} else {
prev->next = curr->next;
}
free(curr);
// if deleted the first node, then current is now the new header,
// else jump to the next
curr = prev == null? thisBucket->nodes : prev->next;
} else { // not found, keep going
prev = curr;
curr = curr->next;
}
}
}
The following does not contain any error checking and only removes the current node from the list ...
pPrev->next = pCurrent->next;
Your preferences may vary, but I tend to put my linked list node at the start of the structure (whenever practical).
struct node{
struct node *next;
unsigned char id[20];
};
struct bucket{
struct node *nodes;
unsigned char id;
};
I find this generally helps to simplify pointer arithmetic and allows simple typecasting when needed.
This removes a node given its address; you can modify it to remove a node given its id, but you haven't specified the form of an id -- is it a NUL-terminated string, or is it 20 bytes?
// remove node from bucket and return true
// or return false if node isn't in bucket
int dht_rmnode(struct bucket* bucket, struct node* node)
{
struct node** ppnode = &bucket->nodes;
for( ;; ){
struct node* pnode = *ppnode;
if( pnode == NULL ) return 0;
if( pnode == node ){
*ppnode = pnode->next;
return 1;
}
ppnode = &pnode->next;
}
}
Or, more compactly,
// remove node from bucket and return true
// or return false if node isn't in bucket
int dht_rmnode(struct bucket* bucket, struct node* node)
{
struct node** ppnode = &bucket->nodes;
struct node* pnode;
for( ; (pnode = *ppnode); ppnode = &pnode->next )
if( pnode == node ){
*ppnode = pnode->next;
return 1;
}
return 0;
}
typedef struct node
{
int id;
struct node* next;
}Node;
void delete_element(void)
{
int i;
Node* current=head;
Node* brev=NULL;
if(i==head->id){
head=current->next;
free(current);}
else{
while(NULL!=current->next)
{
if(i==current->next->id){
brev=current;
current=current->next;
break;}
else
current=current->next;
}
if(i==current->id)
{
if(NULL==head->next){
head=NULL;
free(current);}
else
brev->next=current->next;
free(current);
}
else
printf("this id does not exist\n");
}
}

Resources