So for my class in C, we are told to create an array of Contacts (telephone numbers and names) with nodes containing the address of the next Contact in the list.
I'm new to pointers and I get the concept of them, but they are confusing. I will comment my thought process and what I think I am doing. We we're provided a lot of this code. I only implemented the Contact structure and disaster of words that form the addLast function.
typedef struct Contact
{
int *Next;
char *Name;
char *Tel;
} Contact;
Contact *start=NULL; //This start variable dictates the first node in the list.
void builtList(Contact*);
void addLast(Contact*);
void printList();
int main()
{
Contact contacts[7]=
{
{NULL,"Dennis","0203/123456"},
{NULL,"Chantal","0177/3123345"},
{NULL,"Robert","0163/9295986"},
{NULL,"Bjoern","040 - 123232345"},
{NULL,"Andreas","+49 178 11903123"},
{NULL,"Jenny","+41 119 34544345"},
{NULL,"Zeuss","0162-123-4531698"},
};
builtList(contacts);
printList();
return 0;
}
void builtList(Contact contacts[]) //This function was written for us.
//I would prefer to modify this as little as possible.
{
Contact *ptr=NULL;
int i;
for(i=0; i<=6; i++)
{
ptr=&contacts[i];
addLast(ptr);
}
}
void addLast(Contact *AddressOfCurrent)
{
/* This is the function I am struggling with. We are told this function is to
"add a Contact element to the end of the singly linked list". From what I understand,
It obtains the ADDRESS of the next node and places it into the current node. Thereby
establishing a link between two elements in the list. My friend did this without
importing the contacts[] array and just using a '*temp' array. This confuses me
greatly. How do I establish links between elements if I don't have the elements
with me? */
if (start == NULL)
{
start = AddressOfCurrent; //I can figure out how to establish the start.
} else
{
?????????
}
}
To clarify, here is my task;
Your task is to implement a Contact List that uses a singly linked
list.
In computer science, a linked list (or more clearly, "singly linked
list") is a data structure that consists of a sequence of nodes each
of which contains a reference (i.e., a link) to the next node in the
sequence.
Realise the following structures/Variables
Create a structure called Contact which has the following variables
Contact *next (pointer to the next element in the List) char *name
(used to store the contact's name) char tel (used to store the
contacts telephone number) Create a global Contact variable called
"start" which points to the start element of the singly linked list.
Realise the following functions (for prototypes see linked source
code):
addLast(Contact*): add a Contact element to the end of the singly
linked list (a few other unrelated functions)
For all listed operations youe have to write a new C function each.
The only actual question I see in your post is this one:
My friend did this without
importing the contacts[] array and just using a '*temp' array. This confuses me
greatly. How do I establish links between elements if I don't have the elements
with me?
Since we don't have your friends code at hand, it's hard to evaluate, so let's forget that. Without adding parameters to the addUser() function, you'd need a global, which you have declared:
Contact *start=NULL;
So that's accessible everywhere. And you are on the right track in addContact():
if (!start) {
But if start isn't NULL, then you need to walk the list to the end via the Next pointer, implying another necessity for the addContact() function:
AddressOfCurrent->Next = NULL;
This means each added node has a NULL next pointer. When another node is added to that one, then you need to the previous last node Next to non-null:
???->Next = AddressOfCurrent;
??? here is the node at the end of the current list you'll find by walking it. It's the only one where Next == NULL ;)
Related
I'm fairly new to coding in c and have stumbled upon a problem. The code below is what I have so far.
The trouble I'm running into is the syntax, more specifically on how to loop through the list. I've spent the past week looking at different resources but none explained how to work with a similar struct data type. The way I've attempted to loop through the list results in an error, and I'm having trouble adding the job in the right place since the list is in increasing order - based on the reference number.
The other problem I've run into is within function 5. I'm not entirely too sure of how to return both an integer and character value through a char pointer, unless you return just the entire job_node. As of now, I have casted the value of the node to be a char.
Since I haven't coded much in c - any other suggestions on how to make the code more efficient without changing the values of the functions would be extremely helpful.
A linked list is a container of nodes, and each node has some data payload. Often each data record has a key, a value used to compare two records. In students' assignments in general the data is a simple letter or a number. In your case is a pointer to a "job post".
Below I will show you an alternative way to write his. But first...
It is important to note that the list is a container of nodes, not a list of job posts. A list is not a node, a node is not a list, and the data is not a node.
Mixing these things like you did in your program leads only to problems: you will not be able to use the list to contain other data, for example. You will have trouble changing the implementation of the list without changing the data. You will need to change the list functions if you change a field in the job post. Only problems.
example
bool job_insert(int refNum, char job_name[], struct job_list * list);
should be like
int insert_l( Job* job_post ,List* the_list ,int(*compare_function)(void*,void*));
Why?
Using the former way you can use just a pointer to Job --- in general you should use a void* so you can use anything inside the data record without the need to change the arguments list.
this way if you add a field to Job or change perhaps the reference number to a char[] to add a check-digit you do not need to change a thing here
compare_function() compare two Job and return -1 if the 1st is greater, 1 if the 2nd is greater, or 0. This way you can change the sorting criteria at any time, just writing a new 10-line function, and have records inserted by new criteria. C qsort() uses this, C++ sort() uses this, Borland Turbo Pascal used this in the 80;s. It is simple and flexible.
the function can be as simples as
int compare_reference(void* a, void* b)
{
int first = ((Job*) a)->reference_number;
int second = ((Job*) b)->reference_number;
if (first < second ) return 1;
if (first > second ) return -1;
return 0;
};
and used like this
int res = insert_l( one_job, new_jobs, compare_reference );
and if res is 0 one_job was inserted in new_jobs list at the correct position. It is also easier to read: insert record into list according to criteria.
And if at any time you need to use descending order or sort by another criteria you just need to pass a new function. This means that you can use the same List-related functions to contain any data. This is the reason to use only void pointers to the data element also...
Back to the program
This could be a test file to drive your tests:
1 engineer
2 magician
3 astronaut
4 actress
5 truck driver
6 writer
The structures
typedef struct
{
int reference_number;
char* job_name;
} Job;
typedef struct node_
{
Job* info; // pointer to data record
struct node_ *next;
struct node_ *prev;
} Node;
typedef struct
{
unsigned size; // actual size
unsigned capacity; // limit in # of nodes
Node* head;
Node* tail;
} List;
And you have a List that is a collection of Node. Each Node has a pointer info that point to a Job, that is the data record. Inside a Job you have the reference number and the job's name. reference_number is called key because it is the field used to compare Job records.
The List has no reference to Job, only to Node. Node has no data, just a pointer. So to use List to contain songs or cars or books like the next assignment in line is easy ;)
the functions
List* create_l(unsigned); // return new List
List* delete_l(List*); // erase one
int insert_l( Job*,List*,int(*)(void*,void*)); // insert based on function
List* merge_l(List*,List*,int(*)(void*,void*) ); // merge 2 lists into a 3rd
int remove_by_ref_l(int,List*); // delete a record
char* search_job_l(int,List*); // search for job description for a reference#
I believe that now you see some added convenience:
insert() receives just a pointer to a Job and to a List, and the name of a function to compare 2.
create() returns a pointer to a new List with the limit set to a max # of nodes
remove() gets a reference number and if it is found in List removes the record and returns 0
search() works the same way
I suggest you write this way. If you need help I can provide more code. I had no time today to write a full example.
I am trying to edit part of a backnet stack to not use malloc as it always fails. The code uses malloc to create an object and insert into a linked list. In the following code snippet I have commented out the malloc. My plan is to create a local instance of the struct and insert that into my list. I am able to insert 2 items into my list, when trying to add the third, the list is not properly terminated and I enter an infinite while loop. Can anyone see why my list is not properly terminated?
CHobjects is a stuct and I want a linked list of them. I can not use malloc to create new CHobject instances. To get around this I am attempting to create a local instance of CHobject and add that to my list.
CHobjects* newNode(instance, channel, name, description)
{
CHobjects *node;
CHobjects newNode;
node=CHobjects;
while(node!=NULL)
{
if(node->instance==instance)
return
node=node->next;
}
if(strlen((char *)objectName)>objectNameMax || strlen((char *)description)>descriptionMax)
goto cc8; //fail name or description is too long
// if((node=(CHobject *)malloc(sizeof(CHobject)))==NULL) //get a block of space for this object's info
// goto cc8; //fail if we can't get space for it
test.next=CHobjects; //link on to list
CHobjects=&test;
CHcount++;
}
This code simply adds the elements to the list, the whole code would afterwards set some variables to default values.
After our extensive discussion in the comments, I think it's obvious that you problem is the use of local struct instances in a global list. The structs you create on the stack become invalid on exiting the newNode() function, and the same stack space is recycled on the next call. So you link the same instance to itself, and after two calls, you've got a circular list, and enter an infinite loop.
Since you're obviously on plain C without a heap, your only chance is to roll your own struct allocator in global memory, preallocated at compile time. Declare a global array of CHobjects large enough to satisfy all of you allocations (i.e. the maximum length of the list). In your case, this seems to be 4. Here's a raw outline:
#define CHOBJECTS_MAX 4
static CHobjects gaCHobjects [CHOBJECTS_MAX];
static int giNextSlot = 0;
public: static CHobjects* Allocator ()
{
return gaCHObjects + giNextSlot++;
}
The function Allocator() returns a struct pointer from your global array and increments the giNextSlot index, so you get a new instance on each invocation. Use this pointer inside newNode() instead of a local CHobjects instance.
Your question is a little unclear, but I think that it's possible to give you a useful answer anyway.
The only way I can think that you can implement this is using an array as the storage for the linked list, and as a plus you will have both an array and a linked list at the same time
#include <stdio.h>
struct list {
int value;
struct list *next;
};
static void
print_list(const struct list *item)
{
while (item->next != NULL) {
fprintf(stdout, "%d\n", item->value);
item = item->next;
}
}
int
main(void)
{
struct list items[15];
size_t count;
count = sizeof items / sizeof *items - 1;
for (int index = 0; index < count; ++index) {
items[index].next = &items[index + 1];
items[index].value = index + 1;
}
items[count].next = NULL;
print_list(items);
}
As you see, you need access to the given array element to use as storage location, and the array must be valid through the life time of the linked list.
So I'm creating a system to control inventory. I have a text file which contains all the items in the inventory.
as:
{component, stock code, count, price}
I am creating a struct to represent the stock (this is done in a header file):
typedef struct StockItem {
char *componentType;
char *stockCode;
int numOfItems
int price;
} StockItem;
I want to have a struct in which controls the entire inventory as a linked list, was wondering how would I do it so it would have a collection of StockItems. ( would this be a good way to do it)?
Also one more question, is it conventional to have the struct as a capital letter or not ?
EDIT:
typedef struct inventory {
struct StockItem item;
struct inventory *next;
}inventory;
inventory *pFirstNode = NULL;
inventory *pLastNode = NULL;
void createNewList(struct StockItem *item){
// Set aside enough space in memory for this struct
inventory *pNewStruct = (inventory*) malloc(sizeof(inventory));
// We can assign the value directly for the structs
// reference for the next struct in the linked list
pNewStruct->next = NULL;
printf("Enter Product Name: ");
// The & is needed only because scanf() is used
pNewStruct->item = item;
// When the first struct is created all of the following
// refer to the same struct
pFirstNode = pLastNode = pNewStruct;
}
If a linked list is suitable in your case really depends on how you want to access your inventory. If you plan only to go through it in sequence a linked list is good. If you store an index to a specific inventory item and later retrieve that item out of your list, thats going to be incredibly slow. In this case a datastructure with an array (std::vector for example) is better. But all of that also depends on the amount of data you have. Theres nothing wrong querying a linkedlist by index that only has 100 elements. For your specific question on how you can create a collection, are you limited to c, or can you use c++? The std namespace has a lot of useful collections including an implementation for a linkedlist and a vector which basically is an array, that dynamically resizes.
As you want to limit yourself to c, you will have to write your list implementation yourself. Its nothing that i would recommend somone who is still learning though. Implementing a decent list is really difficult. But if you really want to, this might be a good start. You also learn how linked lists work under the hood, which is a good thing considering a lot of people missuse linkedlists and wonder about bad performance afterwards.
Lets take the link above as an example. They defined a node struct:
typedef struct node {
int val;
struct node * next;
} node_t;
The field "val" is type int. In your case this will be the type of item, that you want to store in your list. Its going to be StockItem or a pointer to a StockItem, depending on how you want to manage your memory. If you want to add a StockItem to the list, you wrap it into a node and assign the pointer to that node to the "next" field of the previous node. Everything is also really well explained in the link i provided.
What you got so far is fine. Next, to add a node to your list, you should set the lastNode pointer and the next pointer in lastNode:
pLastNode->next = pNewStruct;
pLastNode = pNewStruct;
I'm trying to find a specific location in a linked list and then be able to access its attributes. I know how to sort through the linked list but I can not figure out how to access the name attribute of the Locations.
I define my Location * structure as (These locations are stored into the list later):
#ifndef NESW_STRUCT
#define NESW_STRUCT
typedef struct location{
char *name;
char *longer;
char *shorter;
char *tip;
char *north;
char *south;
char *east;
char *west;
char *logic;
int visited;
char *items[20];
} Location;
#endif
My instructor provides us with a module to create a linked list as well as various functions to manipulate the list. The linked list is comprised of Node * which I believe hold the Locations as well as point to the next node in the list.
typedef struct node
{
Location *loc;
struct node *next;
} Node;
So in my game loop I create a global variable 'world' that is my linked list of (I think) Locations:
Node *world;
and
extern Node* world;
In other modules that also access it.
I then run a simple while loop in my main that creates a Location structure and then joins it to the Linked list(excluded from this post), world, using join(location,world) with the following functions my instructor provided, modified by me to work with Locations rather than void objects. I don't initialize world to anything before joining the first location to it, I think I may need to, but since its a core dump and crashes either way, I can't tell if it makes a difference/is necessary:
Node *
newNode(Location *place,Node *next)
{
Node *n = malloc(sizeof(Node));
if (n == 0)
{
fprintf(stderr,"newNode: out of memory!\n");
exit(1);
}
n->loc = place;
n->next = next;
return n;
}
Node *
join(Location *s,Node *rest)
{
return newNode(s,rest);
}
This all works perfectly fine so far and I create my list successfully. However, elsewhere in my program I created a function that maps through the world list and find the location that has a matching name to whichever name I pass to the function, which, logically, works correctly . I created a temp list that is equal to 'world', and then compared the name attribute of the head of the list to the name of the location I was looking for using, strcmp, returning that location if it matches, and setting the list = to the tail of the list if it doesn't.
Head and Tail are defined here, again provided in the module from my instructor:
Location *
head(Node *items)
{
return items->loc;
}
Node *
tail(Node *items)
{
return items->next;
}
If I understand these functions correctly, using head(list) should return a Location right, not a pointer? Then I should be able to just use 'location->name' to access the name? Apparently not though...
To save time of running through all the game logic just get to the part where it needs to compare the names, I tried writing some temporary code similar to how it would be in the mapping function, to test getting a location from the list and then accessing the attributes.
The probably wrong code I'm using to try and test accessing the list is:
Location *test = 0; //creating an empty location, (not sure if it needs to be initialized to 0 before assigning the desired value but I think I remember a mention of that during class)
test = head(world); //I would like to believe this sets test equal to the location of the head of the list world, but I am fairly certain this is where my error occurs because what is getting assigned to test really isn't a location
printf("%s",test->name); //basic print of the name attribute, I know this works logically because I use it elsewhere when dealing with locations not accessed through world, however this is what causes the core dump because I think I'm trying to access a garbage value so to speak
The program compiles with no errors and successfully reads all the the locations based on a debugging print statement I added. Any help, advice, or tips are greatly welcomed. I know people hate on kids that post here because they think they are trying to get their work done for free, but this is a very small part of an immersive project and once I figure this out, the game is essentially done other than content. I'm at a minor roadblock that is a major inhibitor and have tried everything my friend and I could think of and have even just started changing random data types in the Node struct and join/newNode functions as well as the Location struct hoping to either get lucky or figure out a solution through different error messages that occurred but as you can guess, no luck.
Solution by OP.
Because each new item is joined to the front of the list, the very last Node read into (which is the first node read when going through the list because the list is filled backwards) is the null pointer.
Example: Because the join function used stores a pointer to a Location and then points to the next Node in the list, the list is reversed after reading in.
Say you want to read alpha, bravo, charlie, delta epsilon into the list and you read them in that order, the list in memory looks like this with null being the head in the list:
null<-epsilon<-delta<-charlie<-bravo<-alpha
Therefore when I was trying to print with
Node *spot = world;
Location *loc = 0;
loc = head(spot);
printf("%s",loc->name);
I was attempting the print the name for the location which was really just a null pointer and obviously doesn't exist...So a very easy fix was to set spot equal to the tail before actually working with any of the Nodes in the list.
Node *spot = world;
Location *loc = 0;
spot = tail(spot);
loc = head(spot);
printf("%s",loc->name);
Let's say I have the following struct:
struct object {
char *name;
struct object *next;
};
Using that I can easily create a table as a described in K&R C book. And remove all the objects by that:
object *object_destroy(object *obj)
{
if (obj != NULL) {
object_destroy(obj->next);
free(obj->name);
free(obj);
obj = NULL;
}
}
But what I want is to remove one of the objects in table, saving all the others. I really have no idea how to implement that, because just free() that object is won't work: the objects after it will be permamently lost. I can't obj_to_remove = obj_to_remove->next too, because after that I will lose all the objects before that object.
So can you point me out what I am missing? Thanks.
You are effectively attempting to delete a single node from a singly linked list (as opposed to a doubly-linked-list, or a circular list, also known as a ring buffer).
Please refer to the references below for more information on the concept of a singly linked list. In short, you:
Start at the first node in the list (the head node).
Cycle through the list one node at a time, keeping a pointer to the previously accessed node, until you find the node you want to delete.
Point the previous node in the list to the one ahead of the current/found node.
3.1. If there is no node afterwards (we are at the end of the list), set to NULL.
3.2. If the head/first node was the one found, set the head node to the second node in the list.
Delete the elements inside the node if the node has been found.
Delete the current node itself.
The second reference will be very helpful to you, as it covers building a list from scratch, adding items to the end of the list (appending), inserting items at an arbitrary point in the list, deleting individual items, and clearing out the whole list.
References
Deleting from a Linked List, Accessed 2014-04-22, <https://www.cs.bu.edu/teaching/c/linked-list/delete/>
Singly linked list - insert, remove, add, count source code, Accessed 2014-04-22, <http://www.cprogramming.com/snippets/source-code/singly-linked-list-insert-remove-add-count>
You have the following 1->2->3->4->5 and you want to remove the element 3. The final result will be 1->2->4->5.
To do this you just need to do the following steps:
1- If the element is in the middle of the list:
Traverse the table, for each element you save previous element and the element itself.
When the element equals the one you want to delete you have cur_el = 3 and prev_el = 2. (cur_el and prev_el are pointers to the elements 3 and 2)
Now just make prev_el->next = cur_el->next (don't forget to keep a pointer to the prev_el.
Finally just free the cur_el.
2- If the element is the first of the list (let's say you want to delete 1):
- Set the first list element as cur_el->next (here cur_el points to 1, the first element in the list)
free the cur_el
3- If the element is in the end of the list (in this case 5):
- go to the last element, get the penultimate element (let's call the pointer to this one prev_el)
set prev_el->next = null
free cur_el
Also, notice that removing an element from the list has a complexity of O(n), where n is the number of elements of the list.
If you just insert and remove from the begin or from the end you can reach a O(1).
In the question, the memory structure is referred to as a 'table'. Perhaps it would be better to call it a 'linked-list'.
int object_destroy(
object **head, /* The head of the linked-list is required in order to maintain proper list nodes linkage. */
object *obj
)
{
int rCode=0;
/* Unlink the node to be destroyed. */
if(*head == obj) /* Is the obj to destroy the head list node? */
*head = obj->next;
else
{
object *temp = *head;
/* Find the parent list node (to the one that will be destroyed). */
while(temp)
{
if(temp->next == obj)
break;
temp=temp->next;
}
/* Not found? */
if(NULL == temp)
{
rCode=ENOENT;
fprintf(stderr, "obj node not found in list\n");
goto CLEANUP;
}
/* Unlink the node, and patch the list so that remaining nodes are not lost. */
temp->next = temp->next->next;
}
/* Free the node to be destroyed. */
if(obj->name)
free(obj->name);
free(obj);
CLEANUP:
return(rCode);
}