Adding nodes inside a linked list using a function - c

I try to use the CreateRoom function to adding new nodes.
Each time I add a node, I edit the old "lastRoom.next" and make it the current new node's address.
And then I make the current new node's pointer as the new "lastRoom"
I thought this is a good idea and I don't need to return anything. I thought this is good.
However, it doesn't work at all.
I'm really bad at coding and I just learn C. Can anyone help?
struct Room {
int number;
int status;
int luxury;
char occupier[20];
struct Room *next;
};
//I main copy this kind of code from my lecture notes.
//But It's really crappy. This is the only example I can get from the lecture notes
typedef struct Room Room_t;
Room_t *newRoomNode, *ptr, *prev, *temp;
Room_t *firstRoom = NULL, *lastRoom = NULL;
Room_t* CreateRoom(Room_t **first, Room_t **last, int RoomNumber, int type){
Room_t *new = (Room_t *)malloc(sizeof(Room_t));
int *temp;
if (new == NULL)
{
printf("\nMemory was not allocated");
return 0;
}
else
{
//And then I try my way of adding new nodes.
//I don't really understand the example so I make my own
if (*last != NULL)
{
(**last).next = new;
}
new->number = RoomNumber;
new->luxury = type;
new->next = NULL;
*last = new;
if (*first=NULL){
*first=new;
}
}
return 0;
}
void main(){
CreateRoom(&firstRoom, &lastRoom,1,1);
printf("%d",(*firstRoom).number);
}

if (*first=NULL){
*first=new;
}
= is assignment operator. You should use == for comparison.

You shouldn't really bother about the last element. (If you need to traverse the list backward, you have to have a prev member in addition to next.) Now, if you want CreateRoom() to always add a new element at the end of the list, it should first traverse the whole list until it reaches the end of it —which it recognizes because of the NULL pointer— and then assign the new pointer to the place it has reached:
while (*first != NULL)
first = &(*first)->next;
new->number = RoomNumber;
new->luxury = type;
new->next = *first;
*first = new;
Two points are worth being noted:
The assignment *first = new doesn't know if first is firstRoom or the next member of an actual element.
The while loop can be omitted to have new elements inserted at the beginning, or modified so as to have elements sorted the way you want.

Related

C: From char array to linked list

I'm still learning how to program in C and I've stumbled across a problem.
Using a char array, I need to create a linked list, but I don't know how to do it. I've searched online, but it seems very confusing. The char array is something like this char arr[3][2]={"1A","2B","3C"};
Have a look at this code below. It uses a Node struct and you can see how we iterate through the list, creating nodes, allocating memory, and adding them to the linked list. It is based of this GeeksForGeeks article, with a few modifications. I reccommend you compare the two to help understand what is going on.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char value[2];
struct Node * next;
};
int main() {
char arr[3][2] = {"1A","2B","3C"};
struct Node * linked_list = NULL;
// Iterate over array
// We calculate the size of the array by using sizeof the whole array and dividing it by the sizeof the first element of the array
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
// We create a new node
struct Node * new_node = (struct Node *)malloc(sizeof(struct Node));
// Assign the value, you can't assign arrays so we do each char individually or use strcpy
new_node->value[0] = arr[i][0];
new_node->value[1] = arr[i][1];
// Set next node to NULL
new_node->next = NULL;
if (linked_list == NULL) {
// If the linked_list is empty, this is the first node, add it to the front
linked_list = new_node;
continue;
}
// Find the last node (where next is NULL) and set the next value to the newly created node
struct Node * last = linked_list;
while (last->next != NULL) {
last = last->next;
}
last->next = new_node;
}
// Iterate through our linked list printing each value
struct Node * pointer = linked_list;
while (pointer != NULL) {
printf("%s\n", pointer->value);
pointer = pointer->next;
}
return 0;
}
There are a few things the above code is missing, like checking if each malloc is successful, and freeing the allocated memory afterwards. This is only meant to give you something to build off of!

Creating a sublist from a linked list based on position?

I'm trying to type a function that takes 2 linked list. One has the values to be printed and the second has positions for the linked list values to be printed. It gives me an error that i put as comment in the code.
Structs
typedef int Item;
typedef struct node_struct * link;
typedef struct list_struct * list;
struct node_struct {
Item item;
link next;
};
struct list_struct {
link first;
int length;
};
Function:
list sublist(list A, list pos_list) {
link tempOne;
link tempTwo;
link node = malloc(sizeof *node);
tempOne = pos_list->first;
tempTwo = A->first;
int counter;
while(tempOne->next != NULL)
{
counter = 0;
while(counter < tempOne->item && tempOne->next != NULL)
{
tempTwo = tempTwo->next;
counter = counter+1;
}
node->item = tempTwo->item; //EXC_BAD_ACCESS code:1
node = node->next;
tempTwo = A->first;
tempOne = tempOne->next;
counter = 0;
}
return node;
There are bunch of bad practices in the code which makes understanding (and hence debugging and maintaining) such code very difficult for you and for us.
You are creating a pointer typdef when there is no intention to hide the actual data behind the pointer
You are creating a linked list of positions and a linked list of data, using the same data type. I understand in your case both are int, but then don't use the misleading typedef int Item and simply stick to using int
tempOne and tempTwo are probably the worst naming options in this case, not only for calling the variables with non-intuitive names like temp, but also calling the first arg as Two and second arg as One - as counter-intuitive as it can get
I can see cases where you use 2 different structures node_struct (which frankly I would call node) and list_struct see node_structcomment), but in this example, you don't need list_struct, it only adds more confusion to the code.
You should really do the "find" job (the inner for loop)in a separate function, so you can easily handle errors, and not confuse the inner loop with the outer loop
With that out of the way, You haven't specified if the pos_list actually contains relative positions (position from previous position) or absolute positions (like array index). I will assume it is absolute position.
after you do node = node->next; you need to malloc it again. Or rather just malloc it before using it on line node->item = tempTwo->item; and get rid of the malloc out side the loops
I don't have a c compiler handy, so couldn't test it. But I don't see any other issues
EDIT
I noticed that the return value for sublist is always just the last node, instead of the first node in the linked list - this is obviously going to be a problem too.
Below is how I would write this code. Remember, this is not a debugged and tested code, but mere expression of the idea (first draft if you will)
typedef struct Node_ Node;
struct Node_ {
int Item;
Node* Next;
};
Node* GetNodeAt(Node *dataList, int indx) {
for (int i = 0; i < indx && dataList != NULL; ++i)
dataList = dataList->Next;
return dataList;
}
Node* SubList(Node *dataList, Node *posList) {
Node* origDataList = dataList;
Node *currentRetNode = malloc(sizeof(Node));
Node *prevRetNode = NULL, *returnList = currentRetNode;
while (posList->Next != NULL) {
// Find the node in dataList
Node *node = GetNodeAt(dataList, posList->Item);
// create/manage the linked list to be returned
prevRetNode = currentRetNode;
currentRetNode->Next = malloc(sizeof(Node));
currentRetNode->Item = node->Item;
currentRetNode = currentRetNode->Next;
posList = posList->Next; // move to the next index
}
free(currentRetNode);
if (prevRetNode == NULL)
returnList = NULL;
else
prevRetNode->Next = NULL;
return returnList;
}

A Better Understanding Of Linked List

I'm learning C and I'm trying to understand a better concept of a Linked List.
I have a code as an example (I changed it to be like the one i want to understand better).
The code doesnt have any mistakes but again like i said it's to understand it better.
Please have a look at the code first and below the code i'll ask my questions:
Here is the code for my struct and my first function:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct client{
char first_name[20];
char last_name[20];
char id;
char reference;
char deposit;
struct client *next; // pointer to the next entry in the clients list
};
typedef struct client new_Client;
/***********************************************************
* find_Client
* Finds a place in the list to insert new user
* Input: User's first and last name, id, reference, deposit
* Returns: A pointer to teh struct which AFTER we'll insert
the new struct. NULL if head of the linked-list
***********************************************************/
new_Client *find_Client(char *new_last_name, new_Client *head)
{
new_Client *prev = NULL; // previous has nothing
new_Client *curr = head; // current is the head
while (curr != NULL) //// while the current is not NULL because if it's null it's not head
{
if (strcmp(new_last_name, curr->last_name)<0)
break;
prev = curr;
curr = curr->next; // pointing to the next node
}
return prev;
}
And here is my next function where i usually have a problem understanding
/***********************************************************
* add_new_Client
* Adds a new client
* Input: clients details and the address of the list's head
* Returns: nothing
***********************************************************/
void add_new_Client(char *first_n, char *last_n, char *ident, char *ref, char *dep, new_Client **head)
{
new_Client *after;
// create new entry
new_Client *new_entry = (new_Client*)malloc(sizeof(new_Client)); //allocating size of the struct
if (NULL == new_entry)
{
exit(1); //Q1: does it mean that it terminates?
}
else
{
strcpy(new_entry->first_name, first_n);
strcpy(new_entry->last_name, last_n);
strcpy(&new_entry->id, ident);
strcpy(&new_entry->reference, ref);
strcpy(&new_entry->deposit, dep);
}
after = find_Client(new_entry->last_name, *head); // Q2: don't understand this line..
if (NULL == after) // new head
{
if (NULL == *head) // Q3: for adding the first item (when the head is NULL) --> why is this condition necessary
{
new_entry->next = NULL;
}
else
{
new_entry->next = *head;
}
*head = new_entry;
}else
{ //add in the middle
new_entry->next = after->next;
after->next = new_entry;
}
}
Okay so i put my questions in the code itself. They're marked as Q1,Q2 and Q3.
Please let me know if you would prefer i edit on my post and change the questioning methode for it to be easier for you to understand my questions.
//Q1: does it mean that it terminates?
exit(1);
Yes, the program will exit with 1, which is interpreted as failure.
// Q2: don't understand this line..
after = find_Client(new_entry->last_name, *head);
here, after is a pointer to a struct new_Client. The function find_Client returns a pointer to a client that was searched using new_entry->last_name, and head is passed in order to give the search a beginning, somewhere to start.
// Q3: for adding the first item (when the head is NULL) --> why is this condition necessary
if (NULL == *head)
Because when the there is only one element in the list it is alone, that is, it doesn't have a next element. If the list size is higher than one, however, the new node's next element will point to the head, and the this new node will be the new head. That is, the new node's next element will have the value of the last head element, just before it. This is why this distinction is necessary.

C finding the last element of the list passed as a argument

I have a global list
typedef struct center {
char center_name[100];
char hostname[100];
int port;
struct center *next_center;
} center;
So when i start:
int main(int argc, char** argv) {
center *head = null;
parse(argv, &head);
}
where parse:
void parser (char** argv, center **head) {
//read a file amd add the elements to a newCenter
addToCenterList(newcenter, head);
}
where addToCenterList:
void addToCenterList(center *newcenter, center **head) {
center *newNode = malloc(sizeof(center));
strcpy(newNode->center_name, newcenter->center_name);
strcpy(newNode->hostname, newcenter->hostname);
newNode->port = newcenter->port;
newcenter->next_center = NULL;
if (*head == NULL)
*head = newNode;
else {
//problem starts here, it never adds after the first element
center **iterator;
center ite;
iterator = head;
ite = **iterator;
while(1){
if(ite.next_center == NULL){
*ite.next_center = *newNode;
break;
}
}
}
My problem starts with the else:
I am passing the address of the head of the list.
So I know i need a variable that allows to move through the list.
I have tried many things and none work.
I had in mind: iterate through the list and store the address of each "node" in some variable, and if the content of that address (the node!) its the next_center is == NULL then i would stop looking since that is the last element.
And afterward i would just assign that next_center address a new content.
Thats what i am trying to do. I dont know how to make it work....
thanks in advance.
void addToCenterList(center *newcenter, center **head) {
center *newNode ;
while (*head ) { head = &(*head)->next_center; }
*head = newNode = malloc(sizeof *newNod);
strcpy(newNode->center_name, newcenter->center_name);
strcpy(newNode->hostname, newcenter->hostname);
newNode->port = newcenter->port;
/* Note the next line:
** the OP assigned not to newNode, but to newcenter,
** which appears to be
** "read-only" source data element
*/
newNode->next_center = NULL;
}
Remove the asterisks in the last lines of addToCenterList and see what happens.
item *k = &head;
while (*k != NULL)
k = &((*k)->next);
item e = calloc(1, sizeof(struct element));
if (!e) {// calloc didn't work
// error handling
}
e->value = value;
*k = e;
Notice that item is of type pointer:
struct element {
int value;
struct element * next;
};
typedef struct element * item;
You would have to adjust it for your implementation (add some asterisks there and remove some here).
And the asterisks statement was because it causes errors afaik: You can't assign whole structs, that's why you should do it with pointers instead.
while(1){
if(ite.next_center == NULL){
*ite.next_center = *newNode;
break;
}
}
This loop considers what to do if your iterator is the last element, but not what to do if it isnt. You need to add a else { ite = ite->next;} or something to that effect, so that you keep iterating through the list until you find the end.
The second problem, perhaps more key, is that you are modifying a copy of the list.
center ite;
...
ite = **iterator;
This creates a copy of the list element. You then assign to this copy, and the copy is destroyed at the end of the block.
Fix that with
center *ite;
...
ite = *iterator;
This will insert the second element (fix syntax in the while(1) loop) and then inserting the third element will cause a infinite loop due to the first mentioned issue.

Linked List Insertion & Selection

I define a linked list in the same way as it is commonly used, i.e. with a data part and a
self referencing pointer. My logic of insertion is as follows:
struct node
{
int data; //or any type.
struct node *nextPtr;
}*start = NULL;
//main
struct *newPtr = (struct node *)malloc(sizeof(struct node *));
scanf("%d", newPtr->data); //or cout
newPtr->nextPtr = NULL;
if(start == NULL)
start = newPtr;
else
{
while(tempPtr->nextPtr != NULL)
{
tempPtr = tempPtr->nextPtr;
}
tempPtr->nextPtr = newPtr;
}
i) Is this logic correct?
ii) a) I possibly get a run-time error, when I insert two nodes (in one system) or three nodes(in another).
b) The nodes are inserted in the correct order, every time I insert a node.
Is the run-time error as a result of this code...???
struct node
{
int data; //or any type.
struct node *nextPtr;
}*start = NULL;
//main
struct *newPtr = (struct node *)malloc(sizeof(struct node));// You dont need * here
scanf("%d", newPtr->data); //or cout
newPtr->nextPtr = NULL;
if(start == NULL)
start = newPtr;
else
{
tempPtr = start; // you missed this.
while(tempPtr->nextPtr != NULL)
{
tempPtr = tempPtr->nextPtr;
}
tempPtr->nextPtr = newPtr;
}
disregard the answer as it is c++, the original question was tagged c++
The original code, once the small issues are solved (actual allocation of the node, setting the value, definition of the temporary pointer to help walk the list) should work. But there are other approaches that you can take to simplify the code (well, not that it is hugely complex), which basically imply finding the point of insertion before creation first then creating the new element:
Node** insertPoint = &start;
while (*insertionPoint)
insertionPoint = &((*insertionPoint)->next);
*insertionPoint = new Node(value);
Use a pointer to pointer to walk through the list, initialized with the address of the head pointer move it until it refers to the Node* where the new element will be appended (note, appended, not inserted). Then create the new node in that position. This assumes that the Node constructor takes care of copying the value and initializing the next pointer.
Alternatively you can write this recursively and let the compiler perform the tail optimization for you (it might be a bit simpler to read, some people find recursion simpler, some don't):
void append( Node*& tail, Value value ) {
if ( tail==NULL )
list = new Node(value);
else
append( list->next, value );
}
Calling code:
append( start, 100 ); // assuming nits contained in the list
In this case, instead of a double pointer we can use a reference to the pointer, as we don't need to modify it
struct node *newPtr, **hnd;
newPtr = malloc(sizeof *newPtr);
if (!newPtr) barf();
scanf("%d", &newPtr->data);
newPtr->nextPtr = NULL;
for(hnd = &start; *hnd; hnd = &(*hnd)->next) {;}
*hnd = newPtr;

Resources